diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..dd84ea782 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..bbcbbe7d6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml new file mode 100644 index 000000000..78ec7e5a5 --- /dev/null +++ b/.github/workflows/coverity.yml @@ -0,0 +1,68 @@ +name: Linux Coverity Build + +on: + push: + # Pushes to this branch get the scan-build treatment + branches: + - 'coverity*' + +jobs: + linux: + #if: ${{ secrets.COVERITY_SCAN_TOKEN }} != '' + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + name: [linux-clang] + include: + - name: linux-clang + os: ubuntu-22.04 + compiler: clang + steps: + - name: Clone repository + uses: actions/checkout@v1 + - name: Install packages + if: startsWith(matrix.os, 'ubuntu') + run: | + sudo apt-get update -qq + sudo apt-get install -y bison comerr-dev flex libcap-ng-dev libdb-dev libedit-dev libjson-perl libldap2-dev libncurses5-dev libperl4-corelibs-perl libsqlite3-dev libkeyutils-dev pkg-config python3 ss-dev texinfo unzip netbase keyutils ldap-utils gdb apport curl libmicrohttpd-dev clang-tools clang-format jq valgrind + # Temporary workaround for: + # https://github.com/actions/virtual-environments/issues/3185 + sudo hostname localhost + - name: Download Coverity Build Tool + env: + TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} + PROJECT: ${{ secrets.COVERITY_SCAN_PROJECT }} + run: | + wget -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=$TOKEN&project=$PROJECT" -O cov-analysis-linux64.tar.gz + mkdir cov-analysis-linux64 + tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64 + - name: Build + env: + CC: ${{ matrix.compiler }} + MAKEVARS: ${{ matrix.makevars }} + CONFIGURE_OPTS: ${{ matrix.configureopts }} + run: | + /bin/sh ./autogen.sh + export PATH="$PWD/cov-analysis-linux64/bin:$PATH" + mkdir build + cd build + ../configure --srcdir=`dirname "$PWD"` --enable-maintainer-mode --enable-developer --with-ldap $CONFIGURE_OPTS --prefix=$HOME/inst CFLAGS="-Wno-error=shadow -Wno-error=bad-function-cast -Wno-error=unused-function -Wno-error=unused-result -Wno-error=deprecated-declarations" + ulimit -c unlimited + # We don't want to scan-build libedit nor SQLite3 because ETOOSLOW + (cd lib/libedit && make -j4) + (cd lib/sqlite && make -j4) + cov-build --dir cov-int make -j4 + tar czvf ../heimdal.tgz cov-int + - name: Submit the result to Coverity Scan + env: + TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} + EMAIL: ${{ secrets.COVERITY_SCAN_EMAIL }} + PROJECT: ${{ secrets.COVERITY_SCAN_PROJECT }} + run: | + curl \ + --form "token=$TOKEN" \ + --form "email=$EMAIL" \ + --form "file=@heimdal.tgz" \ + --form version="$(git rev-parse HEAD)" \ + --form description="$GITHUB_REF / $GITHUB_SHA" "https://scan.coverity.com/builds?project=$PROJECT" diff --git a/.github/workflows/linux-mit-interop.yml b/.github/workflows/linux-mit-interop.yml new file mode 100644 index 000000000..36830e411 --- /dev/null +++ b/.github/workflows/linux-mit-interop.yml @@ -0,0 +1,117 @@ +name: Linux Build + +on: + push: + branches: + - 'interop-mit*' + +jobs: + unix: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + name: [linux-clang] + include: + - name: linux-clang + os: ubuntu-22.04 + compiler: clang + cflags: '' + steps: + - name: Clone repository + uses: actions/checkout@v1 + - name: Checkout MIT + uses: actions/checkout@v3 + with: + repository: krb5/krb5 + path: mit + - name: Install Heimdal dependencies + run: | + sudo apt-get update -qq + sudo apt-get install -y bison comerr-dev flex doxygen + sudo apt-get install -y libcap-ng-dev libdb-dev libedit-dev libjson-perl + sudo apt-get install -y libldap2-dev libncurses5-dev libperl4-corelibs-perl + sudo apt-get install -y libsqlite3-dev libkeyutils-dev pkg-config python3 + sudo apt-get install -y ss-dev texinfo unzip netbase keyutils ldap-utils + sudo apt-get install -y gdb apport curl libmicrohttpd-dev jq valgrind + - name: Install MIT Kerberos dependencies + run: | + sudo apt-get install -y gettext libcmocka-dev libresolv-wrapper libsasl2-dev libssl-dev python3-kdcproxy python3-pip slapd tcsh + pip3 install pyrad + # Temporary workaround for: + # https://github.com/actions/virtual-environments/issues/3185 + sudo hostname localhost + - name: Build MIT + env: + CC: ${{ matrix.compiler }} + MAKEVARS: ${{ matrix.makevars }} + run: | + cd mit/src + autoreconf + ./configure --enable-maintainer-mode --with-ldap --with-crypto-impl=openssl --prefix=$HOME/mitkrb5 + make -j4 $MAKEVARS + make install + - name: Build + env: + CC: ${{ matrix.compiler }} + MAKEVARS: ${{ matrix.makevars }} + run: | + /bin/sh ./autogen.sh + mkdir build + cd build + ../configure --srcdir=`dirname "$PWD"` --enable-maintainer-mode --enable-developer --with-ldap $CONFIGURE_OPTS --prefix=$HOME/inst CFLAGS="${{ matrix.cflags }} -Wno-error=shadow -Wno-error=bad-function-cast -Wno-error=unused-function -Wno-error=unused-result -Wno-error=deprecated-declarations" --with-mitkrb5=$HOME/mitkrb5 + make -j4 + - name: Test + env: + CC: ${{ matrix.compiler }} + MAKEVARS: ${{ matrix.makevars }} + run: | + cd build + ulimit -c unlimited + make check + - name: Make Install + env: + CC: ${{ matrix.compiler }} + MAKEVARS: ${{ matrix.makevars }} + run: | + cd build || true + make DESTDIR=/tmp/h5l install + cd /tmp/h5l + tar czf $HOME/heimdal-install-linux-${{ matrix.compiler }}.tgz . + - name: Core dump stacks + run: | + echo "thread apply all bt" > /tmp/x + find . -name core -print | while read core; do gdb -batch -x x `file "$core"|sed -e "s/^[^']*'//" -e "s/[ '].*$//"` "$core"; done + if [ "$(find . -name core -print | wc -l)" -gt 0 ]; then false; fi + - name: Test logs + run: | + find build -depth -name \*.trs | xargs grep -lw FAIL | sed -e 's/trs$/log/' | tar -czf $HOME/logs-linux-${{ matrix.compiler }}.tgz --verbatim-files-from --files-from - + find build -name \*.trs | xargs grep -lw FAIL | sed -e 's/trs$/log/' | xargs cat + - name: Failed Test logs + if: ${{ failure() }} + run: | + find build -name \*.trs | xargs grep -lw FAIL | sed -e 's/trs$/log/' | xargs cat + - name: Make Dist + run: | + cd build + make dist + make distclean + if [ "$(git ls-files -o|grep -v ^build/ | wc -l)" -ne 0 ]; then + echo "Files not removed by make distclean:" + git ls-files -o|grep -v ^build/ + fi + - name: Upload Install Tarball + uses: actions/upload-artifact@v4 + with: + name: Install Tarball + path: '~/heimdal-install-linux-${{ matrix.compiler }}.tgz' + - name: Upload Dist Tarball + uses: actions/upload-artifact@v4 + with: + name: Dist Tarball + path: 'build/heimdal-*.tar.gz' + - name: Upload Logs Tarball + uses: actions/upload-artifact@v4 + with: + name: Test Logs + path: '~/logs-linux-${{ matrix.compiler }}.tgz' diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml new file mode 100644 index 000000000..983136b76 --- /dev/null +++ b/.github/workflows/linux.yml @@ -0,0 +1,146 @@ +name: Linux Build + +on: + push: + branches: + - 'master' + - 'heimdal-7-1-branch' + paths: + - '!docs/**' + - '!**.md' + - '!**.[1-9]' + - '**.[chly]' + - '**.hin' + - '**.in' + - '**.am' + - '**.m4' + - '**.ac' + - '**.pl' + - '**.py' + - '**.asn1' + - '**.opt' + - '**/COPYING' + - '**/INSTALL' + - '**/README*' + - '.github/workflows/linux.yml' + - '!appveyor.yml' + - '!.travis.yml' + + pull_request: + paths: + - '!docs/**' + - '!**.md' + - '!**.[1-9]' + - '**.[chly]' + - '**.hin' + - '**.in' + - '**.am' + - '**.m4' + - '**.ac' + - '**.pl' + - '**.py' + - '**.asn1' + - '**.opt' + - '**/COPYING' + - '**/INSTALL' + - '**/README*' + - '.github/workflows/linux.yml' + - '!appveyor.yml' + - '!.travis.yml' + +jobs: + unix: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + name: [linux-clang, linux-gcc] + include: + - name: linux-clang + os: ubuntu-22.04 + compiler: clang + cflags: '' + - name: linux-gcc + os: ubuntu-22.04 + compiler: gcc + cflags: '-Wnonnull' + steps: + - name: Clone repository + uses: actions/checkout@v1 + - name: Install packages + if: startsWith(matrix.os, 'ubuntu') + run: | + sudo apt-get update -qq + sudo apt-get install -y bison comerr-dev flex doxygen + sudo apt-get install -y libcap-ng-dev libdb-dev libedit-dev libjson-perl + sudo apt-get install -y libldap2-dev libncurses5-dev libperl4-corelibs-perl + sudo apt-get install -y libsqlite3-dev libkeyutils-dev pkg-config python3 + sudo apt-get install -y ss-dev texinfo unzip netbase keyutils ldap-utils + sudo apt-get install -y gdb apport curl libmicrohttpd-dev jq valgrind + # Temporary workaround for: + # https://github.com/actions/virtual-environments/issues/3185 + sudo hostname localhost + - name: Build + env: + CC: ${{ matrix.compiler }} + MAKEVARS: ${{ matrix.makevars }} + run: | + /bin/sh ./autogen.sh + mkdir build + cd build + ../configure --srcdir=`dirname "$PWD"` --enable-maintainer-mode --enable-developer --with-ldap $CONFIGURE_OPTS --prefix=$HOME/inst CFLAGS="${{ matrix.cflags }} -Wno-error=shadow -Wno-error=bad-function-cast -Wno-error=unused-function -Wno-error=unused-result -Wno-error=deprecated-declarations" + make -j4 + - name: Test + env: + CC: ${{ matrix.compiler }} + MAKEVARS: ${{ matrix.makevars }} + run: | + cd build + ulimit -c unlimited + make check + - name: Make Install + env: + CC: ${{ matrix.compiler }} + MAKEVARS: ${{ matrix.makevars }} + run: | + cd build || true + make DESTDIR=/tmp/h5l install + cd /tmp/h5l + tar czf $HOME/heimdal-install-linux-${{ matrix.compiler }}.tgz . + - name: Core dump stacks + run: | + echo "thread apply all bt" > /tmp/x + find . -name core -print | while read core; do gdb -batch -x x `file "$core"|sed -e "s/^[^']*'//" -e "s/[ '].*$//"` "$core"; done + if [ "$(find . -name core -print | wc -l)" -gt 0 ]; then false; fi + - name: Test logs + run: | + find build -depth -name \*.trs | xargs grep -lw FAIL | sed -e 's/trs$/log/' | tar -czf $HOME/logs-linux-${{ matrix.compiler }}.tgz --verbatim-files-from --files-from - + find build -name \*.trs | xargs grep -lw FAIL | sed -e 's/trs$/log/' | xargs cat + - name: Failed Test logs + if: ${{ failure() }} + run: | + find build -name \*.trs | xargs grep -lw FAIL | sed -e 's/trs$/log/' | xargs cat + - name: Make Dist + run: | + cd build + make dist + make distclean + if [ "$(git ls-files -o|grep -v ^build/ | wc -l)" -ne 0 ]; then + echo "Files not removed by make distclean:" + git ls-files -o|grep -v ^build/ + fi + - name: Upload Install Tarball + uses: actions/upload-artifact@v4 + with: + name: Install Tarball + path: '~/heimdal-install-linux-${{ matrix.compiler }}.tgz' + - name: Upload Dist Tarball + uses: actions/upload-artifact@v4 + with: + name: Dist Tarball + path: 'build/heimdal-*.tar.gz' + - name: Upload Logs Tarball + uses: actions/upload-artifact@v4 + with: + name: Test Logs + path: '~/logs-linux-${{ matrix.compiler }}.tgz' diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml new file mode 100644 index 000000000..fc6b4ad7b --- /dev/null +++ b/.github/workflows/osx.yml @@ -0,0 +1,124 @@ +name: OS X Build + +on: + push: + branches: + - 'master' + - 'osx-build' + - 'heimdal-7-1-branch' + paths: + - '!docs/**' + - '!**.md' + - '!**.[1-9]' + - '**.[chly]' + - '**.hin' + - '**.in' + - '**.am' + - '**.m4' + - '**.ac' + - '**.pl' + - '**.py' + - '**.asn1' + - '**.opt' + - '**/COPYING' + - '**/INSTALL' + - '**/README*' + - '.github/workflows/osx.yml' + - '!appveyor.yml' + - '!.travis.yml' + + pull_request: + paths: + - '!docs/**' + - '!**.md' + - '!**.[1-9]' + - '**.[chly]' + - '**.hin' + - '**.in' + - '**.am' + - '**.m4' + - '**.ac' + - '**.pl' + - '**.py' + - '**.asn1' + - '**.opt' + - '**/COPYING' + - '**/INSTALL' + - '**/README*' + - '.github/workflows/osx.yml' + - '!appveyor.yml' + - '!.travis.yml' + +jobs: + osx: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + name: [osx-clang] + include: + - name: osx-clang + os: macos-latest + compiler: clang + steps: + - name: Install packages + run: | + echo "bison, flex, ncurses, texinfo, and unzip are in the base OS." + echo "berkeley-db, perl, python3, curl, and jq are installed in the" + echo "base image already." + brew install autoconf automake libtool cpanm texinfo texi2html + sudo cpanm install JSON + - name: Clone repository + uses: actions/checkout@v1 + - name: Build + env: + CC: ${{ matrix.compiler }} + MAKEVARS: ${{ matrix.makevars }} + CONFIGURE_OPTS: ${{ matrix.configureopts }} + run: | + /bin/sh ./autogen.sh + mkdir build + cd build + ../configure --srcdir=`dirname "$PWD"` --disable-heimdal-documentation --disable-afs-support --enable-maintainer-mode --enable-developer $CONFIGURE_OPTS --prefix=$HOME/inst CFLAGS="-Wno-error=shadow -Wno-error=bad-function-cast -Wno-error=unused-function -Wno-error=unused-result -Wno-error=deprecated-declarations" CFLAGS="-O0 -g -ggdb3" + ulimit -c unlimited + PATH=/usr/local/opt/texinfo/bin:$PATH + export PATH + make -j4 + #- name: Setup upterm session + # uses: lhotari/action-upterm@v1 + # with: + # limit-access-to-actor: true + - name: Test + env: + CC: ${{ matrix.compiler }} + MAKEVARS: ${{ matrix.makevars }} + CONFIGURE_OPTS: ${{ matrix.configureopts }} + run: | + set -vx + sudo lsof -nP -i:49188 || true + cd build + make check + - name: Install + run: | + cd build || true + make DESTDIR=/tmp/h5l install + cd /tmp/h5l + tar czf $HOME/heimdal-install-osx.tgz . + - name: Test logs + run: | + find build -depth -name \*.trs|xargs grep -lw FAIL|sed -e 's/trs$/log/' | cpio -o > $HOME/logs-osx.cpio + find build -name \*.trs|xargs grep -lw FAIL|sed -e 's/trs$/log/'|xargs cat + - name: Failed Test logs + if: ${{ failure() }} + run: | + find build -name \*.trs|xargs grep -lw FAIL|sed -e 's/trs$/log/'|xargs cat + - name: Upload Install Tarball + uses: actions/upload-artifact@v4 + with: + name: Install Tarball + path: '~/heimdal-install-osx.tgz' + - name: Upload Artifacts + uses: actions/upload-artifact@v4 + with: + name: Upload Test Logs + path: '~/logs-osx.cpio' diff --git a/.github/workflows/scanbuild.yml b/.github/workflows/scanbuild.yml new file mode 100644 index 000000000..0b79c8b9b --- /dev/null +++ b/.github/workflows/scanbuild.yml @@ -0,0 +1,67 @@ +name: Linux Static Analyzer Build + +on: + push: + # Pushes to this branch get the scan-build treatment + branches: + - 'scan-build*' + + pull_request: + # Changing this build gets it to run + paths: + - '.github/workflows/scanbuild.yml' + +jobs: + unix: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + name: [linux-clang] + include: + - name: linux-clang + os: ubuntu-22.04 + compiler: clang + steps: + - name: Clone repository + uses: actions/checkout@v1 + - name: Install packages + if: startsWith(matrix.os, 'ubuntu') + run: | + sudo apt-get update -qq + sudo apt-get install -y bison comerr-dev flex libcap-ng-dev libdb-dev libedit-dev libjson-perl libldap2-dev libncurses5-dev libperl4-corelibs-perl libsqlite3-dev libkeyutils-dev pkg-config python3 ss-dev texinfo unzip netbase keyutils ldap-utils gdb apport curl libmicrohttpd-dev clang-tools clang-format jq valgrind + # Temporary workaround for: + # https://github.com/actions/virtual-environments/issues/3185 + sudo hostname localhost + - name: Build + env: + CC: ${{ matrix.compiler }} + MAKEVARS: ${{ matrix.makevars }} + CONFIGURE_OPTS: ${{ matrix.configureopts }} + run: | + /bin/sh ./autogen.sh + mkdir build + cd build + ../configure --srcdir=`dirname "$PWD"` --enable-maintainer-mode --enable-developer --with-ldap $CONFIGURE_OPTS --prefix=$HOME/inst CFLAGS="-Wno-error=shadow -Wno-error=bad-function-cast -Wno-error=unused-function -Wno-error=unused-result -Wno-error=deprecated-declarations" + ulimit -c unlimited + # We don't want to scan-build libedit nor SQLite3 because ETOOSLOW + (cd lib/libedit && make -j4) + (cd lib/sqlite && make -j4) + scan-build --keep-going make -j4 + - name: Test + env: + CC: ${{ matrix.compiler }} + MAKEVARS: ${{ matrix.makevars }} + run: | + cd build + ulimit -c unlimited + scan-build --keep-going make check + - name: Failed Test logs + if: ${{ failure() }} + run: | + find build -name \*.trs|xargs grep -lw FAIL|sed -e 's/trs$/log/'|xargs cat + - name: Upload Artifacts + uses: actions/upload-artifact@v4 + with: + name: Scan-Build Reports + path: '/tmp/scan-build*/' diff --git a/.github/workflows/ubsan.yml b/.github/workflows/ubsan.yml new file mode 100644 index 000000000..515010ef0 --- /dev/null +++ b/.github/workflows/ubsan.yml @@ -0,0 +1,133 @@ +name: Linux UBSAN Build + +on: + push: + branches: + - 'master' + - 'ubsan' + paths: + - '!docs/**' + - '!**.md' + - '!**.[1-9]' + - '**.[chly]' + - '**.hin' + - '**.in' + - '**.am' + - '**.m4' + - '**.ac' + - '**.pl' + - '**.py' + - '**.asn1' + - '**.opt' + - '**/COPYING' + - '**/INSTALL' + - '**/README*' + - '.github/workflows/ubsan.yml' + - '!appveyor.yml' + - '!.travis.yml' + + pull_request: + paths: + - '!docs/**' + - '!**.md' + - '!**.[1-9]' + - '**.[chly]' + - '**.hin' + - '**.in' + - '**.am' + - '**.m4' + - '**.ac' + - '**.pl' + - '**.py' + - '**.asn1' + - '**.opt' + - '**/COPYING' + - '**/INSTALL' + - '**/README*' + - '.github/workflows/ubsan.yml' + - '!appveyor.yml' + - '!.travis.yml' + +jobs: + unix: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + name: [linux-clang, linux-gcc] + include: + - name: linux-clang + os: ubuntu-22.04 + compiler: clang + cflags: '-fsanitize=undefined' + ldflags: '' + - name: linux-gcc + os: ubuntu-22.04 + compiler: gcc + cflags: '-Wnonnull -fsanitize=undefined' + ldflags: '' + steps: + - name: Clone repository + uses: actions/checkout@v1 + - name: Install packages + if: startsWith(matrix.os, 'ubuntu') + run: | + sudo apt-get update -qq + sudo apt-get install -y bison comerr-dev flex doxygen + sudo apt-get install -y libcap-ng-dev libdb-dev libedit-dev libjson-perl + sudo apt-get install -y libldap2-dev libncurses5-dev libperl4-corelibs-perl + sudo apt-get install -y libsqlite3-dev libkeyutils-dev pkg-config python3 + sudo apt-get install -y ss-dev texinfo unzip netbase keyutils ldap-utils + sudo apt-get install -y gdb apport curl libmicrohttpd-dev jq valgrind + # Temporary workaround for: + # https://github.com/actions/virtual-environments/issues/3185 + sudo hostname localhost + - name: Build + env: + CC: ${{ matrix.compiler }} + MAKEVARS: ${{ matrix.makevars }} + run: | + /bin/sh ./autogen.sh + mkdir build + cd build + ../configure --srcdir=`dirname "$PWD"` --enable-maintainer-mode --enable-developer --enable-dynamic --disable-static --with-ldap $CONFIGURE_OPTS --prefix=$HOME/inst CFLAGS="${{ matrix.cflags }} -Wno-error=shadow -Wno-error=bad-function-cast -Wno-error=unused-function -Wno-error=unused-result -Wno-error=deprecated-declarations" LDFLAGS="${{ matrix.ldflags }}" + make -j4 + - name: Test + env: + CC: ${{ matrix.compiler }} + MAKEVARS: ${{ matrix.makevars }} + run: | + cd build + ulimit -c unlimited + make check + - name: Make Install + env: + CC: ${{ matrix.compiler }} + MAKEVARS: ${{ matrix.makevars }} + run: | + cd build || true + make DESTDIR=/tmp/h5l install + cd /tmp/h5l + tar czf $HOME/heimdal-install-linux-${{ matrix.compiler }}.tgz . + - name: Core dump stacks + run: | + echo "thread apply all bt" > /tmp/x + find . -name core -print | while read core; do gdb -batch -x x `file "$core"|sed -e "s/^[^']*'//" -e "s/[ '].*$//"` "$core"; done + if [ "$(find . -name core -print | wc -l)" -gt 0 ]; then false; fi + - name: Test logs + run: | + find build -depth -name \*.trs | xargs grep -lw FAIL | sed -e 's/trs$/log/' | tar -czf $HOME/logs-linux-${{ matrix.compiler }}.tgz --verbatim-files-from --files-from - + find build -name \*.trs | xargs grep -lw FAIL | sed -e 's/trs$/log/' | xargs cat + - name: Failed Test logs + if: ${{ failure() }} + run: | + find build -name \*.trs | xargs grep -lw FAIL | sed -e 's/trs$/log/' | xargs cat + - name: All Test logs + if: true + run: | + find build -name \*.trs | sed -e 's/trs$/log/' | xargs cat + - name: Upload Logs Tarball + uses: actions/upload-artifact@v4 + with: + name: Test Logs + path: '~/logs-linux-${{ matrix.compiler }}.tgz' diff --git a/.github/workflows/valgrind.yml b/.github/workflows/valgrind.yml new file mode 100644 index 000000000..f6079f6cf --- /dev/null +++ b/.github/workflows/valgrind.yml @@ -0,0 +1,71 @@ +name: Linux Valgrind Tests Build + +on: + push: + # Pushes to the valgrind branch get the valgrind treatment + branches: + - 'valgrind*' + + pull_request: + # Changing this build also gets it to run + paths: + - '.github/workflows/valgrind.yml' + +jobs: + unix: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + name: [linux-clang] + include: + - name: linux-clang + os: ubuntu-22.04 + compiler: clang + steps: + - name: Clone repository + uses: actions/checkout@v1 + - name: Install packages + if: startsWith(matrix.os, 'ubuntu') + run: | + sudo apt-get update -qq + sudo apt-get install -y bison comerr-dev flex libcap-ng-dev lmdb-utils liblmdb-dev libdb-dev libedit-dev libjson-perl libldap2-dev libncurses5-dev libperl4-corelibs-perl libsqlite3-dev libkeyutils-dev pkg-config python3 ss-dev texinfo unzip netbase keyutils ldap-utils gdb apport curl libmicrohttpd-dev jq valgrind + # Temporary workaround for: + # https://github.com/actions/virtual-environments/issues/3185 + sudo hostname localhost + - name: Build + env: + CC: ${{ matrix.compiler }} + MAKEVARS: ${{ matrix.makevars }} + CONFIGURE_OPTS: ${{ matrix.configureopts }} + CHECK_TESTER_NO_VALGRIND: 'no-valgrind' + run: | + /bin/sh ./autogen.sh + mkdir build + cd build + ../configure --srcdir=`dirname "$PWD"` --enable-maintainer-mode --enable-developer --with-ldap $CONFIGURE_OPTS --prefix=$HOME/inst CFLAGS="-g -ggdb3 -O0 -Wno-error=shadow -Wno-error=bad-function-cast -Wno-error=unused-function -Wno-error=unused-result -Wno-error=deprecated-declarations" + make -j4 + - name: Test + env: + CC: ${{ matrix.compiler }} + MAKEVARS: ${{ matrix.makevars }} + run: | + cd build + ulimit -c unlimited + make check-valgrind + - name: Valgrind output + run: | + find . -name \*.log -print0|xargs -0 grep '^==[0-9]*== ' || true + - name: Test logs + run: | + find build -depth -name \*.log | sed -e 's/trs$/log/' | tar -czf $HOME/logs-linux-valgrind.tgz --verbatim-files-from --files-from - + find build -name \*.trs|xargs grep -lw FAIL | sed -e 's/trs$/log/' | xargs cat + - name: Failed Test logs + if: ${{ failure() }} + run: | + find build -name \*.trs|xargs grep -lw FAIL | sed -e 's/trs$/log/' | xargs cat + - name: Upload Artifacts + uses: actions/upload-artifact@v4 + with: + name: Test Logs + path: '~/logs-linux-valgrind.tgz' diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml new file mode 100644 index 000000000..a48545ac8 --- /dev/null +++ b/.github/workflows/windows.yml @@ -0,0 +1,94 @@ +name: Windows Build + +on: + push: + branches: + - 'master' + - 'windows-build' + - 'heimdal-7-1-branch' + paths: + - '!docs/**' + - '!**.md' + - '!**.[1-9]' + - '**.[chly]' + - '**.hin' + - '**.in' + - '**.pl' + - '**.py' + - '**.asn1' + - '**.opt' + - '**.w32' + - '**/NTMakefile*' + - '**/COPYING' + - '**/INSTALL' + - '**/README*' + - '.github/workflows/windows.yml' + - '!appveyor.yml' + - '!.travis.yml' + + pull_request: + paths: + - '!docs/**' + - '!**.md' + - '!**.[1-9]' + - '**.[chly]' + - '**.hin' + - '**.in' + - '**.pl' + - '**.py' + - '**.asn1' + - '**.opt' + - '**.w32' + - '**/NTMakefile' + - '**/COPYING' + - '**/INSTALL' + - '**/README*' + - '.github/workflows/windows.yml' + - '!appveyor.yml' + - '!.travis.yml' + +jobs: + windows: + runs-on: windows-latest + env: + APPVER: '10.0' + CODESIGN_PKT: 0000000000000000 + INSTALL_DIR: C:\heimdal + WINSDKVER: '10.0.22000.0' + WIXDIR: 'c:\Program Files (x86)\Windows Installer XML v3.5' + steps: + - name: Clone repository + uses: actions/checkout@v1 + - name: Find MSVC and run vcvarsall.bat + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: amd64 + - name: Build and Test + shell: cmd + run: | + set PATH=%PATH%;C:\msys64\usr\bin;C:\Program Files (x86)\HTML Help Workshop;C:\program files (x86)\windows installer xml v3.5\bin;C:\cygwin\bin + set CODESIGN_PKT=0000000000000000 + set dbg__type=Debug + mkdir %INSTALL_DIR% + pacman --noconfirm -S zstd + pacman --noconfirm -S autoconf + pacman --noconfirm -S automake + pacman --noconfirm -S flex + pacman --noconfirm -S bison + pacman --noconfirm -S perl + pacman --noconfirm -S perl-JSON + pacman --noconfirm -S texinfo + set PATH=%PATH%;%wix%bin + title Heimdal Build %CPU% %dbg__type% + set "PATH=%PATH%;C:\Perl64\bin;C:\tools\cygwin\bin;C:\Program Files (x86)\HTML Help Workshop" + set "PATH=%PATH%;C:/msys64/usr/bin" + set "PATH=%PATH%;C:\program files (x86)\windows installer xml v3.5\bin;C:\cygwin\bin" + set "PATH=%PATH%;C:\Python310-x64" + echo PATH=%PATH% + nmake /f NTMakefile APPVEYOR=1 MAKEINFO=makeinfo NO_INSTALLERS=1 + nmake /f NTMakefile APPVEYOR=1 MAKEINFO=makeinfo NO_INSTALLERS=1 test + - name: Upload Artifacts + uses: actions/upload-artifact@v4 + with: + name: Objects + path: 'D:/a/heimdal/heimdal/out/' diff --git a/.gitignore b/.gitignore index d52995b92..6a56c2089 100644 --- a/.gitignore +++ b/.gitignore @@ -1,26 +1,116 @@ -# git-ls-files --others --exclude-from=.git/info/exclude -# Lines that start with '#' are comments. -# For a project mostly in C, the following would be a good set of -# exclude patterns (uncomment them if you want to use them): -# *.[oa] -# *~ +# After changing this file, please run: +# +# git ls-files -i --exclude-standard +# +# to check that you haven't inadvertently ignored any tracked files. This +# command should return no output. Any files listed by it are files +# present in the repository but ignored by .gitignore. + +# General rules, with some exclusions for where they're too general. .DS_Store +.deps/ +.dirstamp +.libs/ +Makefile Makefile.in +rs_state.ini +tags +!/lib/asn1/asn1_gen.c +!/lib/asn1/asn1_print.c +!/lib/krb5/asn1_glue.c +*_asn1.h +!/lib/asn1/heim_asn1.h +*_asn1-priv.h +asn1_*_asn1.c +*_asn1_files +*_asn1_oids.x +*_asn1_syms.x +*_err.[ch] +!/lib/com_err/com_err.[ch] +*-commands.[ch] *~ +*.a +*.la +*.lo +*.o +*.log +*.trs +*.tmp +# Top-level files. + +/.vscode /aclocal.m4 /autom4te.cache /compile +/confdefs.h /config.guess +/config.log +/config.status /config.sub /configure +/conftest.c +/conftest.err /depcomp /install-sh +/libtool /ltmain.sh /missing +/setupbuild.cmd +/stage1.diff +/stage2.diff +/test-driver +/tmp.h /ylwrap -/appl/login/login-protos.h + +/lib/libedit/aclocal.m4 +/lib/libedit/autom4te.cache +/lib/libedit/compile +/lib/libedit/config.guess +/lib/libedit/config.h +/lib/libedit/config.log +/lib/libedit/config.status +/lib/libedit/config.sub +/lib/libedit/configure +/lib/libedit/depcomp +/lib/libedit/install-sh +/lib/libedit/libtool +/lib/libedit/ltmain.sh +/lib/libedit/missing +/lib/libedit/setupbuild.cmd +/lib/libedit/ylwrap +/lib/libedit/src/common.h +/lib/libedit/src/emacs.h +/lib/libedit/src/fcns.c +/lib/libedit/src/fcns.h +/lib/libedit/src/func.h +/lib/libedit/src/help.c +/lib/libedit/src/help.h +/lib/libedit/src/vi.h +/lib/libedit/stamp-h1 + +# Files in subdirectories. + +/admin/ktutil +/appl/afsutil/afslog +/appl/afsutil/pagsh +/appl/dbutils/bsearch +/appl/gssmask/gssmaestro +/appl/gssmask/gssmask +/appl/kf/kf +/appl/kf/kfd +/appl/otp/otp +/appl/otp/otpprint +/appl/test/gssapi_client +/appl/test/gssapi_server +/appl/test/http_client +/appl/test/nt_gss_client +/appl/test/nt_gss_server +/appl/test/tcp_client +/appl/test/tcp_server +/appl/test/uu_client +/appl/test/uu_server /cf/libtool.m4 /cf/ltoptions.m4 /cf/ltsugar.m4 @@ -36,32 +126,434 @@ Makefile.in /doc/krb5 /doc/ntlm /doc/wind +/doc/vars.texi +/doc/doxyout +/include/*.h +!/include/crypto-headers.h +!/include/heim_threads.h +/include/bits /include/config.h.in -/include/stamp-h.in +/include/gssapi/*.h +/include/hcrypto/*.h +/include/kadm5/*.h +/include/stamp-h1 +/include/version.h.in +/kadmin/add_random_users +/kadmin/kadmin +/kadmin/kadmind +/kadmin/test_util +/kcm/kcm /kcm/kcm-protos.h +/kdc/digest-service +/kdc/hprop +/kdc/hpropd +/kdc/kdc /kdc/kdc-protos.h /kdc/kdc-private.h -/lib/asn1/der-protos.h +/kdc/kdc-replay +/kdc/kdc-tester +/kdc/kstash +/kdc/string2key +/kdc/test_csr_authorizer +/kdc/test_kdc_ca +/kdc/test_token_validator +/kpasswd/kpasswd +/kpasswd/kpasswd-generator +/kpasswd/kpasswdd +/kuser/copy_cred_cache +/kuser/generate-requests +/kuser/heimtools +/kuser/kdecode_ticket +/kuser/kdestroy +/kuser/kdigest +/kuser/kgetcred +/kuser/kimpersonate +/kuser/kinit +/kuser/klist +/kuser/kswitch +/kuser/kverify +/lib/asn1/asn1_compile +/lib/asn1/asn1_gen +/lib/asn1/asn1_print +/lib/asn1/asn1parse.c +/lib/asn1/asn1parse.h +/lib/asn1/check-ber +/lib/asn1/check-der +/lib/asn1/check-gen +/lib/asn1/check-gen-template +/lib/asn1/check-template +/lib/asn1/check-timegm +/lib/asn1/cms_asn1.json +/lib/asn1/cms_asn1_oids.c +/lib/asn1/cms_asn1_syms.c +/lib/asn1/cms_template_asn1.json +/lib/asn1/cms_template_asn1_oids.c +/lib/asn1/cms_template_asn1_syms.c +/lib/asn1/crmf_asn1.json +/lib/asn1/crmf_asn1_oids.c +/lib/asn1/crmf_asn1_syms.c +/lib/asn1/crmf_template_asn1.json +/lib/asn1/crmf_template_asn1_oids.c +/lib/asn1/crmf_template_asn1_syms.c /lib/asn1/der-private.h +/lib/asn1/der-protos.h +/lib/asn1/digest_asn1.json +/lib/asn1/digest_asn1_oids.c +/lib/asn1/digest_asn1_syms.c +/lib/asn1/digest_template_asn1.json +/lib/asn1/digest_template_asn1_oids.c +/lib/asn1/digest_template_asn1_syms.c +/lib/asn1/krb5_asn1.json +/lib/asn1/krb5_asn1_oids.c +/lib/asn1/krb5_asn1_syms.c +/lib/asn1/krb5_template_asn1.json +/lib/asn1/krb5_template_asn1_oids.c +/lib/asn1/krb5_template_asn1_syms.c +/lib/asn1/kx509_asn1.json +/lib/asn1/kx509_asn1_oids.c +/lib/asn1/kx509_asn1_syms.c +/lib/asn1/kx509_template_asn1.json +/lib/asn1/kx509_template_asn1_oids.c +/lib/asn1/kx509_template_asn1_syms.c +/lib/asn1/lex.c +/lib/asn1/ocsp_asn1.json +/lib/asn1/ocsp_asn1_oids.c +/lib/asn1/ocsp_asn1_syms.c +/lib/asn1/ocsp_template_asn1.json +/lib/asn1/ocsp_template_asn1_oids.c +/lib/asn1/ocsp_template_asn1_syms.c +/lib/asn1/pkcs10_asn1.json +/lib/asn1/pkcs10_asn1_oids.c +/lib/asn1/pkcs10_asn1_syms.c +/lib/asn1/pkcs10_template_asn1.json +/lib/asn1/pkcs10_template_asn1_oids.c +/lib/asn1/pkcs10_template_asn1_syms.c +/lib/asn1/pkcs12_asn1.json +/lib/asn1/pkcs12_asn1_oids.c +/lib/asn1/pkcs12_asn1_syms.c +/lib/asn1/pkcs12_template_asn1.json +/lib/asn1/pkcs12_template_asn1_oids.c +/lib/asn1/pkcs12_template_asn1_syms.c +/lib/asn1/pkcs8_asn1.json +/lib/asn1/pkcs8_asn1_oids.c +/lib/asn1/pkcs8_asn1_syms.c +/lib/asn1/pkcs8_template_asn1.json +/lib/asn1/pkcs8_template_asn1_oids.c +/lib/asn1/pkcs8_template_asn1_syms.c +/lib/asn1/pkcs9_asn1.json +/lib/asn1/pkcs9_asn1_oids.c +/lib/asn1/pkcs9_asn1_syms.c +/lib/asn1/pkcs9_template_asn1.json +/lib/asn1/pkcs9_template_asn1_oids.c +/lib/asn1/pkcs9_template_asn1_syms.c +/lib/asn1/pkinit_asn1.json +/lib/asn1/pkinit_asn1_oids.c +/lib/asn1/pkinit_asn1_syms.c +/lib/asn1/pkinit_template_asn1.json +/lib/asn1/pkinit_template_asn1_oids.c +/lib/asn1/pkinit_template_asn1_syms.c +/lib/asn1/rfc2459_asn1.json +/lib/asn1/rfc2459_asn1_oids.c +/lib/asn1/rfc2459_asn1_syms.c +/lib/asn1/rfc2459_template_asn1.json +/lib/asn1/rfc2459_template_asn1_oids.c +/lib/asn1/rfc2459_template_asn1_syms.c +/lib/asn1/rfc4108_asn1.json +/lib/asn1/rfc4108_asn1_oids.c +/lib/asn1/rfc4108_asn1_syms.c +/lib/asn1/rfc4108_template_asn1.json +/lib/asn1/rfc4108_template_asn1_oids.c +/lib/asn1/rfc4108_template_asn1_syms.c +/lib/asn1/test_asn1.json +/lib/asn1/test_asn1_oids.c +/lib/asn1/test_asn1_syms.c +/lib/asn1/test_template_asn1.json +/lib/asn1/test_template_asn1_oids.c +/lib/asn1/test_template_asn1_syms.c +/lib/asn1/x690sample_asn1.json +/lib/asn1/x690sample_asn1_oids.c +/lib/asn1/x690sample_asn1_syms.c +/lib/asn1/x690sample_template_asn1.json +/lib/asn1/x690sample_template_asn1_oids.c +/lib/asn1/x690sample_template_asn1_syms.c /lib/auth/Makefile.in +/lib/base/base64.c +/lib/base/heimbase-protos.h +/lib/base/json-journal +/lib/base/test_base +/lib/base/test_db.json +/lib/com_err/compile_et +/lib/com_err/lex.c /lib/com_err/parse.c /lib/com_err/parse.h +/lib/com_err/snprintf.c +/lib/com_err/strlcpy.c +/lib/gssapi/asn1_ContextFlags.c +/lib/gssapi/asn1_GSSAPIContextToken.c +/lib/gssapi/asn1_MechType.c +/lib/gssapi/asn1_MechTypeList.c +/lib/gssapi/asn1_NegHints.c +/lib/gssapi/asn1_NegStateEnum.c +/lib/gssapi/asn1_NegTokenInit.c +/lib/gssapi/asn1_NegTokenInit2.c +/lib/gssapi/asn1_NegTokenResp.c +/lib/gssapi/asn1_NegotiationToken.c +/lib/gssapi/asn1_NegotiationToken2.c +/lib/gssapi/gss-token +/lib/gssapi/gssapi_asn1-template.c +/lib/gssapi/gssapi_asn1.json +/lib/gssapi/gssapi_asn1_oids.c +/lib/gssapi/gssapi_asn1_syms.c +/lib/gssapi/gsstool /lib/gssapi/krb5/gsskrb5-private.h /lib/gssapi/ntlm/ntlm-private.h +/lib/gssapi/sanon/sanon-private.h /lib/gssapi/spnego/spnego-private.h -/lib/hdb/hdb-protos.h +/lib/gssapi/spnego_asn1-template.c +/lib/gssapi/spnego_asn1.json +/lib/gssapi/spnego_asn1_oids.c +/lib/gssapi/spnego_asn1_syms.c +/lib/gssapi/test_acquire_cred +/lib/gssapi/test_add_store_cred +/lib/gssapi/test_cfx +/lib/gssapi/test_context +/lib/gssapi/test_cred +/lib/gssapi/test_kcred +/lib/gssapi/test_names +/lib/gssapi/test_ntlm +/lib/gssapi/test_oid +/lib/gss_preauth/gss-preauth-protos.h +/lib/gss_preauth/gss-preauth-private.h +/lib/hcrypto/crypto-test +/lib/hcrypto/crypto-test2 +/lib/hcrypto/destest +/lib/hcrypto/error +/lib/hcrypto/example_evp_cipher +/lib/hcrypto/hcrypto +/lib/hcrypto/hcrypto-link +/lib/hcrypto/mdtest +/lib/hcrypto/rc2test +/lib/hcrypto/rctest +/lib/hcrypto/test-out-1 +/lib/hcrypto/test-out-15 +/lib/hcrypto/test-out-16 +/lib/hcrypto/test-out-17 +/lib/hcrypto/test-out-31 +/lib/hcrypto/test-out-32 +/lib/hcrypto/test-out-33 +/lib/hcrypto/test_bn +/lib/hcrypto/test_bulk +/lib/hcrypto/test_cipher +/lib/hcrypto/test_crypto +/lib/hcrypto/test_dh +/lib/hcrypto/test_engine_dso +/lib/hcrypto/test_hmac +/lib/hcrypto/test-out-7 +/lib/hcrypto/test_pkcs12 +/lib/hcrypto/test_pkcs5 +/lib/hcrypto/test_rand +/lib/hcrypto/test_rsa +/lib/hcrypto/unix +/lib/hcrypto/libtommath/callgraph.txt +/lib/hdb/asn1_Event.c +/lib/hdb/asn1_GENERATION.c +/lib/hdb/asn1_HDBFlags.c +/lib/hdb/asn1_HDB_EncTypeList.c +/lib/hdb/asn1_HDB_EntryOrAlias.c +/lib/hdb/asn1_HDB_Ext_Aliases.c +/lib/hdb/asn1_HDB_Ext_Constrained_delegation_acl.c +/lib/hdb/asn1_HDB_Ext_KeyRotation.c +/lib/hdb/asn1_HDB_Ext_KeySet.c +/lib/hdb/asn1_HDB_Ext_Lan_Manager_OWF.c +/lib/hdb/asn1_HDB_Ext_PKINIT_acl.c +/lib/hdb/asn1_HDB_Ext_PKINIT_cert.c +/lib/hdb/asn1_HDB_Ext_PKINIT_hash.c +/lib/hdb/asn1_HDB_Ext_Password.c +/lib/hdb/asn1_HDB_entry.c +/lib/hdb/asn1_HDB_entry_alias.c +/lib/hdb/asn1_HDB_extension.c +/lib/hdb/asn1_HDB_extensions.c +/lib/hdb/asn1_HDB_keyset.c +/lib/hdb/asn1_Key.c +/lib/hdb/asn1_KeyRotation.c +/lib/hdb/asn1_KeyRotationFlags.c +/lib/hdb/asn1_Keys.c +/lib/hdb/asn1_Salt.c /lib/hdb/hdb-private.h -/lib/hx509/hx509-private.h -/lib/hx509/hx509-protos.h -/lib/hx509/data/*.pem +/lib/hdb/hdb-protos.h +/lib/hdb/hdb_asn1-template.c +/lib/hdb/hdb_asn1.json +/lib/hdb/hdb_asn1_oids.c +/lib/hdb/hdb_asn1_syms.c +/lib/hdb/test_concurrency +/lib/hdb/test_dbinfo +/lib/hdb/test_hdbkeys +/lib/hdb/test_mkey +/lib/hdb/test_namespace +/lib/hdb/testhdb-*-shm +/lib/hdb/testhdb-*-wal +/lib/hx509/actual +/lib/hx509/PKITS_data/ +/lib/hx509/cert-ca.der +/lib/hx509/cert-ca.pem +/lib/hx509/cert-ee.pem +/lib/hx509/cert-null.pem +/lib/hx509/cert-proxy.der +/lib/hx509/cert-sub-ca.pem +/lib/hx509/cert-sub-ca2.pem +/lib/hx509/cert-sub-ee.pem +/lib/hx509/crl.crl /lib/hx509/data/*.srl /lib/hx509/data/*.req /lib/hx509/data/sub-ca-combined.crt +/lib/hx509/expected +/lib/hx509/ev.data +/lib/hx509/ev.data.out +/lib/hx509/hx509-private.h +/lib/hx509/hx509-protos.h +/lib/hx509/hxtool +/lib/hx509/out.pem +/lib/hx509/out2.pem +/lib/hx509/pkcs10-request.der +/lib/hx509/random-data +/lib/hx509/request.out +/lib/hx509/sel-gram.c +/lib/hx509/sel-gram.h +/lib/hx509/sel-lex.c +/lib/hx509/sd +/lib/hx509/sd.data +/lib/hx509/sd.data.out +/lib/hx509/sd.pem +/lib/hx509/statfile +/lib/hx509/test +/lib/hx509/test-rc-file.rc +/lib/hx509/test_ca +/lib/hx509/test_cert +/lib/hx509/test_chain +/lib/hx509/test_cms +/lib/hx509/test_crypto +/lib/hx509/test_expr +/lib/hx509/test_java_pkcs11 +/lib/hx509/test_name +/lib/hx509/test_nist +/lib/hx509/test_nist2 +/lib/hx509/test_nist_cert +/lib/hx509/test_nist_pkcs12 +/lib/hx509/test_pkcs11 +/lib/hx509/test_query +/lib/hx509/test_req +/lib/hx509/test_soft_pkcs11 +/lib/hx509/test_windows +/lib/hx509/wca.pem +/lib/hx509/wcrl.crl +/lib/hx509/wdc.pem +/lib/hx509/wuser.pem +/lib/ipc/tc +/lib/ipc/ts +/lib/ipc/ts-http +/lib/kadm5/default_keys +/lib/kadm5/iprop-log +/lib/kadm5/ipropd-master +/lib/kadm5/ipropd-slave +/lib/kadm5/test_pw_quality /lib/kadm5/kadm5-protos.h /lib/kadm5/kadm5-private.h +/lib/kafs/resolve.c +/lib/kafs/strlcpy.c +/lib/kafs/strsep.c +/lib/kafs/strtok_r.c +/lib/krb5/aes-test +/lib/krb5/config_file.c.orig +/lib/krb5/config_file.c.rej +/lib/krb5/derived-key-test /lib/krb5/krb5-protos.h /lib/krb5/krb5-private.h +/lib/krb5/krbhst-test +/lib/krb5/n-fold-test +/lib/krb5/parse-name-test +/lib/krb5/pseudo-random-test +/lib/krb5/store-test +/lib/krb5/string-to-key-test +/lib/krb5/test_acl +/lib/krb5/test_addr +/lib/krb5/test_alname +/lib/krb5/test_ap-req +/lib/krb5/test_canon +/lib/krb5/test_cc +/lib/krb5/test_config +/lib/krb5/test_config_include.out +/lib/krb5/test_config_strings.out +/lib/krb5/test_crypto +/lib/krb5/test_crypto_wrapping +/lib/krb5/test_expand_toks +/lib/krb5/test_fx +/lib/krb5/test_hostname +/lib/krb5/test_keytab +/lib/krb5/test_mem +/lib/krb5/test_mkforwardable +/lib/krb5/test_pac +/lib/krb5/test_pkinit_dh2key +/lib/krb5/test_pknistkdf +/lib/krb5/test_plugin +/lib/krb5/test_prf +/lib/krb5/test_princ +/lib/krb5/test_set_kvno0 +/lib/krb5/test_store +/lib/krb5/test_time +/lib/krb5/test_x500 +/lib/krb5/test_forward +/lib/krb5/test_get_addrs +/lib/krb5/test_gic +/lib/krb5/test_kuserok +/lib/krb5/test_renew +/lib/krb5/test_rfc3961 +/lib/krb5/verify_krb5_conf /lib/ntlm/heimntlm-protos.h +/lib/ntlm/test_ntlm +/lib/otp/ndbm_wrap.c +/lib/otp/ndbm_wrap.h +/lib/otp/otptest +/lib/otp/snprintf.c +/lib/otp/strcasecmp.c +/lib/otp/strlcat.c +/lib/otp/strlcpy.c +/lib/otp/strlwr.c +/lib/otp/strncasecmp.c +/lib/roken/base32-test +/lib/roken/base64-test +/lib/roken/getaddrinfo-test +/lib/roken/getifaddrs-test +/lib/roken/hex-test +/lib/roken/make-roken +/lib/roken/make-roken.c +/lib/roken/parse_bytes-test +/lib/roken/parse_reply-test +/lib/roken/parse_time-test +/lib/roken/resolve-test +/lib/roken/rkbase32 +/lib/roken/rkbase64 +/lib/roken/rkpty +/lib/roken/rkvis +/lib/roken/roken.h +/lib/roken/rtbl +/lib/roken/snprintf-test +/lib/roken/strpftime-test +/lib/roken/test-auxval +/lib/roken/test-detach +/lib/roken/test-getuserinfo +/lib/roken/test-readenv +/lib/roken/tsearch-test +/lib/roken/vis.h +/lib/sl/getprogname.c +/lib/sl/slc +/lib/sl/slc-gram.c +/lib/sl/slc-gram.h +/lib/sl/slc-lex.c +/lib/sl/snprintf.c +/lib/sl/strdup.c +/lib/sl/strtok_r.c +/lib/sl/strupr.c +/lib/sl/test_sl /lib/wind/*.pyc /lib/wind/bidi_table.c /lib/wind/bidi_table.h @@ -69,10 +561,162 @@ Makefile.in /lib/wind/combining_table.h /lib/wind/errorlist_table.c /lib/wind/errorlist_table.h +/lib/wind/idn-lookup /lib/wind/map_table.c /lib/wind/map_table.h /lib/wind/normalize_table.c /lib/wind/normalize_table.h /lib/wind/punycode_examples.c /lib/wind/punycode_examples.h +/lib/wind/__pycache__/ +/lib/wind/test-bidi +/lib/wind/test-ldap +/lib/wind/test-map +/lib/wind/test-normalize +/lib/wind/test-prohibited +/lib/wind/test-punycode +/lib/wind/test-rw +/lib/wind/test-utf8 +/out +/po/gen-po.sh /scripts +/tests/bin/intr +/tests/bin/setup-env +/tests/can/check-can +/tests/can/current-db.db +/tests/can/krb5.conf +/tests/can/log +/tests/can/mit-pkinit-20070607.cf +/tests/can/test_can +/tests/db/add-modify-delete +/tests/db/check-aliases +/tests/db/check-dbinfo +/tests/db/current-db.db +/tests/db/dbinfo.out +/tests/db/have-db +/tests/db/krb5.conf +/tests/db/krb5.conf-db1 +/tests/db/krb5.conf-db3 +/tests/db/krb5.conf-lmdb +/tests/db/krb5.conf-sqlite +/tests/db/loaddump-db +/tests/db/log +/tests/db/tempfile +/tests/gss/barpassword +/tests/gss/check-basic +/tests/gss/check-context +/tests/gss/check-gss +/tests/gss/check-gssmask +/tests/gss/check-negoex +/tests/gss/check-ntlm +/tests/gss/check-spnego +/tests/gss/current-db.db +/tests/gss/foopassword +/tests/gss/krb5.conf +/tests/gss/krb5ccfile +/tests/gss/krb5ccfile-ds +/tests/gss/krb5ccfile2 +/tests/gss/mech +/tests/gss/new_clients_k5.conf +/tests/gss/server.keytab +/tests/gss/tempfile +/tests/java/check-kinit +/tests/java/krb5.conf +/tests/kdc/acache.krb5 +/tests/kdc/barpassword +/tests/kdc/bx509.pem +/tests/kdc/cache.krb5 +/tests/kdc/cc_dir/ +/tests/kdc/cdigest-reply +/tests/kdc/check-authz +/tests/kdc/check-bx509 +/tests/kdc/check-canon +/tests/kdc/check-cc +/tests/kdc/check-delegation +/tests/kdc/check-des +/tests/kdc/check-digest +/tests/kdc/check-fast +/tests/kdc/check-hdb-mitdb +/tests/kdc/check-httpkadmind +/tests/kdc/check-iprop +/tests/kdc/check-kadmin +/tests/kdc/check-kdc +/tests/kdc/check-kdc-weak +/tests/kdc/check-keys +/tests/kdc/check-kpasswdd +/tests/kdc/check-pkinit +/tests/kdc/check-referral +/tests/kdc/check-tester +/tests/kdc/check-uu +/tests/kdc/current-db.db +/tests/kdc/current-db.sqlite3 +/tests/kdc/current-db.sqlite3-shm +/tests/kdc/current-db.sqlite3-wal +/tests/kdc/current.log.save +/tests/kdc/email.pem +/tests/kdc/foopassword +/tests/kdc/foopassword.rkpty +/tests/kdc/icache.krb5 +/tests/kdc/iprop-stats +/tests/kdc/iprop-stats2 +/tests/kdc/iprop.keytab +/tests/kdc/ipropd.dumpfile +/tests/kdc/k.der +/tests/kdc/kdc-tester4.json +/tests/kdc/kdc.pid +/tests/kdc/krb5-authz.conf +/tests/kdc/krb5-authz2.conf +/tests/kdc/krb5-bx509.conf +/tests/kdc/krb5-canon.conf +/tests/kdc/krb5-canon2.conf +/tests/kdc/krb5-cccol.conf +/tests/kdc/krb5-hdb-mitdb.conf +/tests/kdc/krb5-httpkadmind.conf +/tests/kdc/krb5-master2.conf +/tests/kdc/krb5-pkinit-win.conf +/tests/kdc/krb5-pkinit.conf +/tests/kdc/krb5-pkinit2.conf +/tests/kdc/krb5-slave.conf +/tests/kdc/krb5-slave2.conf +/tests/kdc/krb5-weak.conf +/tests/kdc/krb5.conf +/tests/kdc/krb5.conf.keys +/tests/kdc/localname +/tests/kdc/messages.log2 +/tests/kdc/mixed-issuer.pem +/tests/kdc/notfoopassword +/tests/kdc/o2cache.krb5 +/tests/kdc/ocache.krb5 +/tests/kdc/pkinit-anchor.pem +/tests/kdc/req +/tests/kdc/s2digest-reply +/tests/kdc/sdb +/tests/kdc/sdigest-init +/tests/kdc/sdigest-reply +/tests/kdc/server-issuer.pem +/tests/kdc/server.keytab +/tests/kdc/server.pem +/tests/kdc/simple_csr_authz/ +/tests/kdc/tempfile +/tests/kdc/test-rc-file.rc +/tests/kdc/trivial.pem +/tests/kdc/user-issuer.pem +/tests/ldap/check-ldap +/tests/ldap/krb5.conf +/tests/ldap/slapd-init +/tests/plugin/cache.krb5 +/tests/plugin/check-pac +/tests/plugin/current-db.db +/tests/plugin/foopassword +/tests/plugin/krb5.conf +/tests/plugin/server.keytab +/tools/heimdal-gssapi.pc +/tools/heimdal-kadm-client.pc +/tools/heimdal-kadm-server.pc +/tools/heimdal-krb5.pc +/tools/kadm-client.pc +/tools/kadm-server.pc +/tools/kafs.pc +/tools/krb5-gssapi.pc +/tools/krb5.pc +/tools/krb5-config diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..1a1f587e6 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,92 @@ +os: + - linux + - osx + +language: c + +env: + global: + secure: "YKG77M7zMvJ+IeV2ziw//HcHqMqFoAzIZlE99Yw/aOn5pvMYKq6Ep7EFVhbfDu9yN0T7M5csCGQeH7/ylDlsZSRMUw72844ezMDM8e10T/lW/T/OYN7j1ZVHh3WSJgS+1D9VG6/Y0OY1Si3lb7PcOdAIU0fPJV5xQONN2+hpJeI=" + +before_install: + - if [ $TRAVIS_OS_NAME = linux ]; then sudo apt-get update -qq; fi + - if [ $TRAVIS_OS_NAME = linux ]; then sudo apt-get install -qq bison comerr-dev flex libcap-ng-dev libdb-dev libedit-dev libjson-perl libldap2-dev libncurses5-dev libperl4-corelibs-perl libsqlite3-dev libkeyutils-dev pkg-config python ss-dev texinfo unzip netbase keyutils; fi + - if [ $TRAVIS_OS_NAME = linux ]; then sudo apt-get install -qq ldap-utils gdb apport; fi + - if [ $TRAVIS_OS_NAME = linux ]; then sudo apt-get install -qq curl libmicrohttpd-dev; fi + - if [ $TRAVIS_OS_NAME = linux -a -n "$COVERAGE" ]; then sudo apt-get install -qq jq; fi + - if [ $TRAVIS_OS_NAME = osx ]; then HOMEBREW_NO_AUTO_UPDATE=1 brew install cpanm bison flex berkeley-db lmdb openldap openssl; fi + - if [ $TRAVIS_OS_NAME = osx ]; then sudo cpanm install JSON; fi + - if [ $TRAVIS_OS_NAME = osx -a -n "$COVERAGE" ]; then brew install jq; fi + - mkdir ci-build + - mkdir coverity-build + - ./autogen.sh + +install: + - cd ci-build + - | + if [ $TRAVIS_OS_NAME = osx ]; then + LDFLAGS="-L/usr/local/opt/berkeley-db/lib -L/usr/local/opt/lmdb/lib" \ + CFLAGS="-I/usr/local/opt/lmdb/include" \ + ../configure \ + --srcdir=`dirname "$PWD"` \ + --prefix=/tmp/heimdal \ + --enable-maintainer-mode $COVERAGE \ + --enable-static=no \ + --enable-pthread-support \ + --disable-afs-support \ + --disable-ndbm-db \ + --with-openldap=/usr/local/opt/openldap \ + --with-openssl=/usr/local/opt/openssl/ \ + --with-hcrypto-default-backend=ossl \ + --with-berkeley-db \ + --with-berkeley-db-include=/usr/local/opt/berkeley-db/include + else + # This list of -Wno-error options should be reduced over time where possible + if [ x"$TRAVIS_COMPILER" != x"clang" ]; then + CFLAGS="-Wno-error=empty-body -Wno-error=shadow -Wno-error=unused-value -Wno-error=bad-function-cast -Wno-error=unused-function -Wno-error=unused-result -Wno-error=deprecated-declarations" ../configure --enable-developer --srcdir=`dirname "$PWD"` --enable-maintainer-mode $COVERAGE + else + CFLAGS="-Wno-error=shadow -Wno-error=bad-function-cast -Wno-error=unused-function -Wno-error=unused-result -Wno-error=deprecated-declarations" ../configure --enable-developer --srcdir=`dirname "$PWD"` --enable-maintainer-mode $COVERAGE + fi + fi + - ulimit -c unlimited; make -j3 + +script: + - if [ x${COVERITY_SCAN_BRANCH} != x1 ]; then ulimit -c unlimited; make check${MAKE_CHECK_SUFFIX}; fi + +after_script: + - if [ -n "$COVERAGE" ]; then ../tools/coveralls-tool -O $PWD -S ..; fi + - find . -name \*.log -print0|xargs -0 grep '^==[1-9]' + +after_failure: + - find . -name test-suite.log -print0 | xargs -0 cat + - if [ $TRAVIS_OS_NAME = linux ]; then echo "thread apply all bt" > x; find . -name core -print | while read core; do gdb -batch -x x `file "$core"|sed -e "s/^[^']*'//" -e "s/[ '].*$//"` "$core"; done; fi + - if [ $TRAVIS_OS_NAME = osx ]; then find . -name core -print | while read core; do echo bt | lldb --core "$core" `file "$core"|sed -e "s/^[^']*'//" -e "s/[ '].*$//"` "$core"; done; fi + +compiler: + - clang + - gcc + +matrix: + include: + - os: linux + compiler: gcc + env: COVERAGE=--enable-gcov + exclude: + - os: osx + compiler: gcc + +notifications: + email: + on_success: change + on_failure: always + +addons: + + coverity_scan: + project: + name: "heimdal/heimdal" + description: "Build submitted via Travis CI" + notification_email: heimdal-builders@secure-endpoints.com + build_command_prepend: ../configure --enable-maintainer-mode + build_command: make + branch_pattern: coverity_scan diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..06c44ad65 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at abuse@heimdal.team. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/ChangeLog.2005 b/ChangeLog.2005 index a594d0924..b92ee39bb 100644 --- a/ChangeLog.2005 +++ b/ChangeLog.2005 @@ -1323,7 +1323,7 @@ 2005-05-07 Love Hörnquist Åstrand * lib/krb5/addr_families.c (krb5_print_address): catch when the - unknown adress don't fit. From Björn Sandell + unknown address don't fit. From Björn Sandell 2005-05-05 Dave Love diff --git a/ChangeLog.2006 b/ChangeLog.2006 index d48ea8aba..f9176a763 100644 --- a/ChangeLog.2006 +++ b/ChangeLog.2006 @@ -366,7 +366,7 @@ * lib/krb5/pac.c: Almost enough code to do PAC parsing and verification, missing in the unix2NTTIME and ucs2 corner. The - later will be adressed by finally adding libwind. + later will be addressed by finally adding libwind. * lib/krb5/krb5_init_context.3: document krb5_[gs]et_max_time_skew @@ -2016,7 +2016,7 @@ * lib/krb5/n-fold-test.c: main is not a KRB5_LIB_FUNCTION * lib/krb5/mk_priv.c (krb5_mk_priv): abort if ASN1_MALLOC_ENCODE - failes to produce the matching lenghts. + failes to produce the matching lengths. 2006-01-27 Love Hörnquist Åstrand diff --git a/ChangeLog.2007 b/ChangeLog.2007 index 60c95459f..1ac528f53 100644 --- a/ChangeLog.2007 +++ b/ChangeLog.2007 @@ -423,7 +423,7 @@ 2007-06-28 Love Hörnquist Åstrand - * kdc/digest.c: On success, print username, not ip-adress. + * kdc/digest.c: On success, print username, not ip-address. 2007-06-26 Love Hörnquist Åstrand diff --git a/LICENSE b/LICENSE index 2a34af8c2..c76fc234a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 1995 - 2008 Kungliga Tekniska Högskolan +Copyright (c) 1995 - 2014 Kungliga Tekniska Högskolan (Royal Institute of Technology, Stockholm, Sweden). All rights reserved. diff --git a/Makefile.am b/Makefile.am index 26de7bc65..b9bdcf499 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,12 +7,20 @@ kcm_dir = kcm endif SUBDIRS= include lib kuser kdc admin kadmin kpasswd -SUBDIRS+= $(kcm_dir) appl doc tools tests packages etc po +SUBDIRS+= $(kcm_dir) appl tools tests packages etc po + +if HEIMDAL_DOCUMENTATION +SUBDIRS+= doc +endif + + ## ACLOCAL = @ACLOCAL@ -I cf ACLOCAL_AMFLAGS = -I cf EXTRA_DIST = \ + NTMakefile \ + windows \ TODO \ LICENSE \ README \ @@ -30,21 +38,33 @@ EXTRA_DIST = \ autogen.sh \ krb5.conf \ cf/make-proto.pl \ + cf/roken-h-process.pl \ cf/install-catman.sh \ cf/ChangeLog \ cf/c-function.m4 \ cf/ChangeLog \ cf/have-pragma-weak.m4 \ cf/have-types.m4 \ - cf/krb-func-getcwd-broken.m4 \ cf/krb-prog-ranlib.m4 \ cf/krb-prog-yacc.m4 \ cf/krb-sys-aix.m4 \ cf/krb-sys-nextstep.m4 \ - cf/krb-version.m4 \ cf/roken.m4 \ cf/valgrind-suppressions \ + cf/maybe-valgrind.sh \ + cf/symbol-version.py \ + cf/w32-check-exported-symbols.pl \ + cf/w32-def-from-dll.pl \ + cf/w32-detect-vc-version.pl \ + cf/w32-hh-toc-from-info.pl \ + cf/w32-list-externs-from-objs.pl \ cf/vararray.m4 print-distdir: @echo $(distdir) + +clean-local-gcov: + find . '(' -name '*.gcno' -o -name '*.gcda' -o -name '*.gcov' ')' -a -print|xargs rm -f + +.PHONY: clean-local-gcov + diff --git a/NEWS b/NEWS index e1176d465..4bb5a7037 100644 --- a/NEWS +++ b/NEWS @@ -1,14 +1,606 @@ + +Partial news for a future Heimdal 8.0 release -- but NOTE WELL that this is NOT +a release at this time! + +Bug fixes + + - Errors found by the Coverity static analysis. + - Errors found by the LLVM scan-build static analyzer. + - Errors found by the valgrind memory debugger. + - Fix out-of-tree SQLite3 ccache permissions / umask issues. + - iprop bugs, race conditions, and performance + - Many misc. bugs + +Features: + + - KDC: Add FAST support for TGS. + - KDC: Greatly improved plugin facility for Samba. + - KDC: Add httpkadmind service providing a subset of kadmin + functionality over HTTP. + - KDC: Add support for virtual service principal namespaces. + - KDC: Add support for synthetic client principals that exist if the + pre-authentication mechanism (e.g., PKINIT) can authenticate + them, thus not requiring an HDB entry. + - KDC: Add experimental GSS-API pre-authentication support. + - KDC: Revamp and enhance kx509 support (though bx509d mostly replaces kx509). + - KDC: Better support for aliases and referrals. + - KDC: Always return the salt in the PA-ETYPE-INFO[2]. + - KDC: Add warn_ticket_addresses configuration parameter. + - KDC: allow anonymous AS requests with long-term keys. + - KDC: Do not include PAC for anonymous AS requests. + - KDC: Enable keepalive mode on incoming sockets. + - KDC: Greatly improved logging. + - KDC: Remove KRB5SignedPath, to be replaced with PAC. + - PKIX: Add bx509d -- an online certification authority (CA) with an HTTP API. + - kadmin: Add HTTP-based kadmin protocol. + - kadmin: Add add_alias, del_alias. + - kadmin: Add command aliases to man page. + - kadmin: Add disallow-client attribute. + - kadmin: add --hdb / -H argument. + - kadmin: Allow enforcing password quality on admin password change. + - kadmin: Improve ext_keytab usage. + - kadmin: Selective pruning of historic key for principal. + - krb5: Add client_aware_channel_bindings option. + - krb5: Add constrained credential delegation option "destination TGT" + - krb5: Add "EFILE:" target for logging. + - krb5: Add include/includedir directives for krb5.conf. + - krb5: Complete DIR ccache collection support. + - krb5: Add FILE ccache collection support. + - krb5: Improved FILE ccache performance. + - krb5: Add KEYRING ccache support. + - krb5: Add kx509 client. + - krb5: Improve FILE keytab performance. + - krb5: Implement KRB5_TRACE environment variable. + - krb5: Add experimental name canonicalization rules configuration. + - krb5: Support start_realm ccconfig entry type. + - kinit: Add --default-for option for ccache collection support. + - kinit: Add --pk-anon-fast-armor option. + - kinit: Don't leave dangling temporary ccaches. + - klist: Better --json + - iprop: Many performance and scaling enhancements. + - iprop: Support hierarchical propagation. + - ASN.1: Document fuzzing process. + - ASN.1: Complete template backend. + - ASN.1: Add partial Information Object System support (template backend + only). This means that open type holes can be decoded recursively + with one codec function call. + - ASN.1: Add JSON encoder functionality (template backend only). + - ASN.1: Greatly enhanced asn1_print(1) command, which can now print a + JSON representation of any DER-encoded value of any type exported + by ASN.1 modules in Heimdal. + - ASN.1: Support circular types. + - ASN.1: Topographically sort declarations. + - ASN.1: Proper support for IMPLICIT tags. + - GSS: Import gss-token(1) command. + - GSS: Add advanced credential store / load functionality. + - GSS: Add name attributes support, with support for many basic attributes + and PAC buffer accessors too. + - GSS: Add SANON mechanism for anonymous-only key exchange using + elliptic curve Diffie-Hellman (ECDH) with Curve25519. + - GSS: Add gss_acquire_cred_from() and credential store extensions. + - GSS: Support fragmented tokens reassembly (for SMB). + - GSS: Support client keytab. + - GSS: Add NegoEx support. + - libhx509: Lots of improvements. + - hxtool: Add "acert" (assert cert contents) command + - hxtool: add cert type: https-negotiate-server + - hxtool: add generate-key command + - hxtool: Add OID symbol resolution and printing of OIDs known to hxtool. + - hxtool: Add print --raw-json option that shows certificates in JSON, with + all extensions and attributes known to Heimdal fully decoded. + - hxtool: Improved SAN support. + - hxtool: Improved CSR support. + - Improved plugin interfaces. + - hcrypto: Add X25519. + - hcrypto: Better RSA key generation. + - hcrypto: import libtommath v1.2.0. + - roken: Add secure_getenv() and issuid(), use them extensively. + +Release Notes - Heimdal - Version Heimdal 7.8 + + Bug fixes + + - CVE-2022-42898 PAC parse integer overflows + + - CVE-2022-3437 Overflows and non-constant time leaks in DES{,3} and arcfour + - Pass correct length to _gssapi_verify_pad() + - Check for overflow in _gsskrb5_get_mech() + - Check buffer length against overflow for DES{,3} unwrap + - Check the result of _gsskrb5_get_mech() + - Avoid undefined behaviour in _gssapi_verify_pad() + - Don't pass NULL pointers to memcpy() in DES unwrap + - Use constant-time memcmp() in unwrap_des3() + - Use constant-time memcmp() for arcfour unwrap + + - CVE-2021-44758 NULL dereference DoS in SPNEGO acceptors + + - CVE-2022-44640 Heimdal KDC: invalid free in ASN.1 codec + + This is a 10.0 on the Common Vulnerability Scoring System (CVSS) v3. + + Heimdal's ASN.1 compiler generates code that allows specially + crafted DER encodings of CHOICEs to invoke the wrong free function + on the decoded structure upon decode error. This is known to impact + the Heimdal KDC, leading to an invalid free() of an address partly + or wholly under the control of the attacker, in turn leading to a + potential remote code execution (RCE) vulnerability. + + This error affects the DER codec for all CHOICE types used in + Heimdal, though not all cases will be exploitable. We have not + completed a thorough analysis of all the Heimdal components + affected, thus the Kerberos client, the X.509 library, and other + parts, may be affected as well. + + This bug has been in Heimdal since 2005. It was first reported by + Douglas Bagnall, though it had been found independently by the + Heimdal maintainers via fuzzing. + + While no zero-day exploit is known, such an exploit will likely be + available soon after public disclosure. + + - Errors found by the LLVM scan-build static analyzer. + + - Errors found by the valgrind memory debugger. + + - Work around GCC Bug 95189 (memcmp wrongly stripped like strcmp). + + - Fix Unicode normalization read of 1 bytes past end of array. + + - Correct ASN.1 OID typo for SHA-384 + + - Fix a deadlock in in the MEMORY ccache type. + + - TGS: strip forwardable and proxiable flags if the server is + disallowed. + + - CVE-2019-14870: Validate client attributes in protocol-transition + - CVE-2019-14870: Apply forwardable policy in protocol-transition + - CVE-2019-14870: Always lookup impersonate client in DB + + - Incremental HDB propagation improvements + + - Refactor send_diffs making it progressive + - Handle partial writes on non-blocking sockets + - Disable Nagle in iprop master and slave + - Use async I/O + - Don't send I_HAVE in response to AYT + - Do not recover log in kadm5_get_principal() + - Don't send diffs to slaves with not yet known version + - Don't stutter in send_diffs + + - Optional backwards-compatible anon-pkinit behaviour + +Release Notes - Heimdal - Version Heimdal 7.7 + + Bug fixes + + - PKCS#11 hcrypto back-end + . initialize the p11_module_load function list + . verify that not only is a mechanism present but that its mechanism + info states that it offers the required encryption, decryption or + digest services + - krb5: + . Starting with 7.6, Heimdal permitted requesting authenticated + anonymous tickets. However, it did not verify that a KDC in fact + returned an anonymous ticket when one was requested. + - Cease setting the KDCOption reaquest_anonymous flag when issuing + S4UProxy (constrained delegation) TGS requests. + . when the Win2K PKINIT compatibility option is set, do + not require krbtgt otherName to match when validating KDC + certificate. + . set PKINIT_BTMM flag per Apple implementation + . use memset_s() instead of memset() + - kdc: + . When generating KRB5SignedPath in the AS, use the reply client name + rather than the one from the request, so validation will work + correctly in the TGS. + . allow checksum of PA-FOR-USER to be HMAC_MD5. Even if tgt used + an enctype with a different checksum. Per [MS-SFU] 2.2.1 + PA-FOR-USER the checksum is always HMAC_MD5, and that's what + Windows and MIT clients send. + + In heimdal both the client and kdc use instead the + checksum of the tgt, and therefore work with each other + but Windows and MIT clients fail against heimdal KDC. + + Both Windows and MIT KDCs would allow any keyed checksum + to be used so Heimdal client interoperates with them. + + Change Heimdal KDC to allow HMAC_MD5 even for non RC4 + based tgt in order to support per-spec clients. + . use memset_s() instead of memset(). + - Detect Heimdal 1.0 through 7.6 clients that issue S4UProxy + (constrained delegation) TGS Requests with the request + anonymous flag set. These requests will be treated as + S4UProxy requests and not anonymous requests. + - HDB: + . Set SQLite3 backend default page size to 8KB. + . Add hdb_set_sync() method + - kadmind: + . disable HDB sync during database load avoiding unnecessary disk i/o. + - ipropd: + . disable HDB sync during receive_everything. Doing an fsync + per-record when receiving the complete HDB is a performance + disaster. Among other things, if the HDB is very large, then + one slave receving a full HDB can cause other slaves to timeout + and, if HDB write activity is high enough to cause iprop log + truncation, then also need full syncs, which leads to a cycle of + full syncs for all slaves until HDB write activity drops. + Allowing the iprop log to be larger helps, but improving + receive_everything() performance helps even more. + - kinit: + . Anonymous PKINIT tickets discard the realm information used + to locate the issuing AS. Store the issuing realm in the + credentials cache in order to locate a KDC which can renew them. + . Do not leak the result of krb5_cc_get_config() when determining + anonymous PKINIT start realm. + - klist: + . Show transited-policy-checked, ok-as-delegate and anonymous + flags when listing credentials. + - tests: + . Regenerate certs so that they expire before the 2038 armageddon + so the test suite will pass on 32-bit operating systems until the + underlying issues can be resolved. + - Solaris: + . Define _STDC_C11_BCI for memset_s prototype + - build tooling: + . Convert from python 2 to python 3 + - documentation + . rename verify-password to verify-password-quality + . hprop default mode is encrypt + . kadmind "all" permission does not include "get-keys" + . verify-password-quality might not be stateless + +Release Notes - Heimdal - Version Heimdal 7.6 + + Security + + - CVE-2018-16860 Heimdal KDC: Reject PA-S4U2Self with unkeyed checksum + + When the Heimdal KDC checks the checksum that is placed on the + S4U2Self packet by the server to protect the requested principal + against modification, it does not confirm that the checksum + algorithm that protects the user name (principal) in the request + is keyed. This allows a man-in-the-middle attacker who can + intercept the request to the KDC to modify the packet by replacing + the user name (principal) in the request with any desired user + name (principal) that exists in the KDC and replace the checksum + protecting that name with a CRC32 checksum (which requires no + prior knowledge to compute). + + This would allow a S4U2Self ticket requested on behalf of user + name (principal) user@EXAMPLE.COM to any service to be changed + to a S4U2Self ticket with a user name (principal) of + Administrator@EXAMPLE.COM. This ticket would then contain the + PAC of the modified user name (principal). + + - CVE-2019-12098, client-only: + + RFC8062 Section 7 requires verification of the PA-PKINIT-KX key excahnge + when anonymous PKINIT is used. Failure to do so can permit an active + attacker to become a man-in-the-middle. + + Bug fixes + + - Happy eyeballs: Don't wait for responses from known-unreachable KDCs. + - kdc: check return copy_Realm, copy_PrincipalName, copy_EncryptionKey + - kinit: + . cleanup temporary ccaches + . see man page for "kinit --anonymous" command line syntax change + - kdc: Make anonymous AS-requests more RFC8062-compliant. + - Updated expired test certificates + - Solaris: + . PKCS#11 hcrypto backend broken since 7.0.1 + . Building with Sun Pro C + + Features + + - kuser: support authenticated anonymous AS-REQs in kinit + - kdc: support for anonymous TGS-REQs + - kgetcred support for anonymous service tickets + - Support builds with OpenSSL 1.1.1 + +Release Notes - Heimdal - Version Heimdal 7.5 + + Security + + - Fix CVE-2017-17439, which is a remote denial of service + vulnerability: + + In Heimdal 7.1 through 7.4, remote unauthenticated attackers + are able to crash the KDC by sending a crafted UDP packet + containing empty data fields for client name or realm. + + Bug fixes + + - Handle long input lines when reloading database dumps. + + - In pre-forked mode (default on Unix), correctly clear + the process ids of exited children, allowing new child processes + to replace the old. + + - Fixed incorrect KDC response when no-cross realm TGT exists, + allowing client requests to fail quickly rather than time + out after trying to get a correct answer from each KDC. + +Release Notes - Heimdal - Version Heimdal 7.4 + + Security + + - Fix CVE-2017-11103: Orpheus' Lyre KDC-REP service name validation + + This is a critical vulnerability. + + In _krb5_extract_ticket() the KDC-REP service name must be obtained from + encrypted version stored in 'enc_part' instead of the unencrypted version + stored in 'ticket'. Use of the unecrypted version provides an + opportunity for successful server impersonation and other attacks. + + Identified by Jeffrey Altman, Viktor Duchovni and Nico Williams. + + See https://www.orpheus-lyre.info/ for more details. + +Release Notes - Heimdal - Version Heimdal 7.3 + + Security + + - Fix transit path validation. Commit f469fc6 (2010-10-02) inadvertently + caused the previous hop realm to not be added to the transit path + of issued tickets. This may, in some cases, enable bypass of capath + policy in Heimdal versions 1.5 through 7.2. + + Note, this may break sites that rely on the bug. With the bug some + incomplete [capaths] worked, that should not have. These may now break + authentication in some cross-realm configurations. + (CVE-2017-6594) + +Release Notes - Heimdal - Version Heimdal 7.2 + + Bug fixes + - Portability improvements + - More strict parsing of encoded URI components in HTTP KDC + - Fixed memory leak in malloc error recovery in NTLM GSSAPI mechanism + - Avoid overly specific CPU info in krb5-config in aid of reproducible builds + - Don't do AFS string-to-key tests when feature is disabled + - Skip mdb_stat test when the command is not available + - Windows: update SHA2 timestamp server + - hdb: add missing export hdb_generate_key_set_password_with_ks_tuple + - Fix signature of hdb_generate_key_set_password() + - Windows: enable KX509 support in the KDC + - kdc: fix kx509 service principal match + - iprop: handle case where master sends nothing new + - ipropd-slave: fix incorrect error codes + - Allow choice of sqlite for HDB pref + - check-iprop: don't fail to kill daemons + - roken: pidfile -> rk_pidfile + - kdc: _kdc_do_kx509 fix use after free error + - Do not detect x32 as 64-bit platform. + - No sys/ttydefaults.h on CYGWIN + - Fix check-iprop races + - roken_detach_prep() close pipe + +Release Notes - Heimdal - Version Heimdal 7.1 + + Security + + - kx509 realm-chopping security bug + - non-authorization of alias additions/removals in kadmind + (CVE-2016-2400) + + Feature + + - iprop has been revamped to fix a number of race conditions that could + lead to inconsistent replication + - Hierarchical capath support + - AES Encryption with HMAC-SHA2 for Kerberos 5 + draft-ietf-kitten-aes-cts-hmac-sha2-11 + - hcrypto is now thread safe on all platforms + - libhcrypto has new backends: CNG (Windows), PKCS#11 (mainly for + Solaris), and OpenSSL. OpenSSL is now a first-class libhcrypto backend. + OpenSSL 1.0.x and 1.1 are both supported. AES-NI used when supported by + backend + - HDB now supports LMDB + - Thread support on Windows + - RFC 6113 Generalized Framework for Kerberos Pre-Authentication (FAST) + - New GSS APIs: + . gss_localname + - Allow setting what encryption types a principal should have with + [kadmin] default_key_rules, see krb5.conf manpage for more info + - Unify libhcrypto with LTC (libtomcrypto) + - asn1_compile 64-bit INTEGER functionality + - HDB key history support including --keepold kadmin password option + - Improved cross-realm key rollover safety + - New krb5_kuserok() and krb5_aname_to_localname() plug-in interfaces + - Improved MIT compatibility + . kadm5 API + . Migration from MIT KDB via "mitdb" HDB backend + . Capable of writing the HDB in MIT dump format + - Improved Active Directory interoperability + . Enctype selection issues for PAC and other authz-data signatures + . Cross realm key rollover (kvno 0) + - New [kdc] enctype negotiation configuration: + . tgt-use-strongest-session-key + . svc-use-strongest-session-key + . preauth-use-strongest-session-key + . use-strongest-server-key + - The KDC process now uses a multi-process model improving + resiliency and performance + - Allow batch-mode kinit with password file + - SIGINFO support added to kinit cmd + - New kx509 configuration options: + . kx509_ca + . kca_service + . kx509_include_pkinit_san + . kx509_template + - Improved Heimdal library/plugin version safety + - Name canonicalization + . DNS resolver searchlist + . Improved referral support + . Support host:port host-based services + - Pluggable libheimbase interface for DBs + - Improve IPv6 Support + - LDAP + . Bind DN and password + . Start TLS + - klist --json + - DIR credential cache type + - Updated upstream SQLite and libedit + - Removed legacy applications: ftp, kx, login, popper, push, rcp, rsh, + telnet, xnlock + - Completely remove RAND_egd support + - Moved kadmin and ktutil to /usr/bin + - Stricter fcache checks (see fcache_strict_checking krb5.conf setting) + . use O_NOFOLLOW + . don't follow symlinks + . require cache files to be owned by the user + . require sensible permissions (not group/other readable) + - Implemented gss_store_cred() + - Many more + + Bug fixes + - iprop has been revamped to fix a number of race conditions that could + lead to data loss + - Include non-loopback addresses assigned to loopback interfaces + when requesting tickets with addresses + - KDC 1DES session key selection (for AFS rxkad-k5 compatibility) + - Keytab file descriptor and lock leak + - Credential cache corruption bugs + (NOTE: The FILE ccache is still not entirely safe due to the + fundamentally unsafe design of POSIX file locking) + - gss_pseudo_random() interop bug + - Plugins are now preferentially loaded from the run-time install tree + - Reauthentication after password change in init_creds_password + - Memory leak in the client kadmin library + - TGS client requests renewable/forwardable/proxiable when possible + - Locking issues in DB1 and DB3 HDB backends + - Master HDB can remain locked while waiting for network I/O + - Renewal/refresh logic when kinit is provided with a command + - KDC handling of enterprise principals + - Use correct bit for anon-pkinit + - Many more + + Acknowledgements + + This release of Heimdal includes contributions from: + + Abhinav Upadhyay Heath Kehoe Nico Williams + Andreas Schneider Henry Jacques Patrik Lundin + Andrew Bartlett Howard Chu Philip Boulain + Andrew Tridgell Igor Sobrado Ragnar Sundblad + Antoine Jacoutot Ingo Schwarze Remi Ferrand + Arran Cudbard-Bell Jakub Čajka Rod Widdowson + Arvid Requate James Le Cuirot Rok Papež + Asanka Herath James Lee Roland C. Dowdeswell + Ben Kaduk Jeffrey Altman Ross L Richardson + Benjamin Kaduk Jeffrey Clark Russ Allbery + Bernard Spil Jeffrey Hutzelman Samuel Cabrero + Brian May Jelmer Vernooij Samuel Thibault + Chas Williams Ken Dreyer Santosh Kumar Pradhan + Chaskiel Grundman Kiran S J Sean Davis + Dana Koch Kumar Thangavelu Sergio Gelato + Daniel Schepler Landon Fuller Simon Wilkinson + David Mulder Linus Nordberg Stef Walter + Douglas Bagnall Love Hörnquist Åstrand Stefan Metzmacher + Ed Maste Luke Howard Steffen Jaeckel + Eray Aslan Magnus Ahltorp Timothy Pearson + Florian Best Marc Balmer Tollef Fog Heen + Fredrik Pettai Marcin Cieślak Tony Acero + Greg Hudson Marco Molteni Uri Simchoni + Gustavo Zacarias Matthieu Hautreux Viktor Dukhovni + Günther Deschner Michael Meffie Volker Lendecke + Harald Barth Moritz Lenz + +Release Notes - Heimdal - Version Heimdal 1.5.3 + + Bug fixes + - Fix leaking file descriptors in KDC + - Better socket/timeout handling in libkrb5 + - General bug fixes + - Build fixes + +Release Notes - Heimdal - Version Heimdal 1.5.2 + + Security fixes + - CVE-2011-4862 Buffer overflow in libtelnet/encrypt.c in telnetd - escalation of privilege + - Check that key types strictly match - denial of service + +Release Notes - Heimdal - Version Heimdal 1.5.1 + + Bug fixes + - Fix building on Solaris, requires c99 + - Fix building on Windows + - Build system updates + +Release Notes - Heimdal - Version Heimdal 1.5 + +New features + + - Support GSS name extensions/attributes + - SHA512 support + - No Kerberos 4 support + - Basic support for MIT Admin protocol (SECGSS flavor) + in kadmind (extract keytab) + - Replace editline with libedit + +Release Notes - Heimdal - Version Heimdal 1.4 + + New features + + - Support for reading MIT database file directly + - KCM is polished up and now used in production + - NTLM first class citizen, credentials stored in KCM + - Table driven ASN.1 compiler, smaller!, not enabled by default + - Native Windows client support + +Notes + + - Disabled write support NDBM hdb backend (read still in there) since + it can't handle large records, please migrate to a diffrent backend + (like BDB4) + +Release Notes - Heimdal - Version Heimdal 1.3.3 + + Bug fixes + - Check the GSS-API checksum exists before trying to use it [CVE-2010-1321] + - Check NULL pointers before dereference them [kdc] + +Release Notes - Heimdal - Version Heimdal 1.3.2 + + Bug fixes + + - Don't mix length when clearing hmac (could memset too much) + - More paranoid underrun checking when decrypting packets + - Check the password change requests and refuse to answer empty packets + - Build on OpenSolaris + - Renumber AD-SIGNED-TICKET since it was stolen from US + - Don't cache /dev/*random file descriptor, it doesn't get unloaded + - Make C++ safe + - Misc warnings + +Release Notes - Heimdal - Version Heimdal 1.3.1 + + Bug fixes + + - Store KDC offset in credentials + - Many many more bug fixes + +Release Notes - Heimdal - Version Heimdal 1.3.1 + + New features + + - Make work with OpenLDAPs krb5 overlay + Release Notes - Heimdal - Version Heimdal 1.3 New features - - Partital support for MIT kadmind rpc protocol in kadmind + - Partial support for MIT kadmind rpc protocol in kadmind - Better support for finding keytab entries when using SPN aliases in the KDC - Support BER in ASN.1 library (needed for CMS) - Support decryption in Keychain private keys - Support for new sqlite based credential cache - - Try both to KDC referals the the common DNS reverse lookup in GSS-API - - Fix the KCM not not leak resources on failure + - Try both KDC referals and the common DNS reverse lookup in GSS-API + - Fix the KCM to not leak resources on failure - Add IPv6 support to iprop - Support localization of error strings in kinit/klist/kdestroy and Kerberos library @@ -22,7 +614,7 @@ Release Notes - Heimdal - Version Heimdal 1.3 - Support for settin friendly name on credential caches - Move to using doxygen to generate documentation. - - Sprinkling __attribute__((depricated)) for old function to be removed + - Sprinkling __attribute__((__deprecated__)) for old function to be removed - Support to export LAST-REQUST information in AS-REQ - Support for client deferrals in in AS-REQ - Add seek support for krb5_storage. diff --git a/NTMakefile b/NTMakefile new file mode 100644 index 000000000..adf04f845 --- /dev/null +++ b/NTMakefile @@ -0,0 +1,47 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +!if exist("thirdparty\NTMakefile") +thirdparty=thirdparty +!endif + +!ifdef APPVEYOR +SUBDIRS = include lib kuser kdc admin kadmin kpasswd appl \ + tools tests packages etc +!else +SUBDIRS = include lib kuser kdc admin kadmin kpasswd appl doc \ + tools tests packages etc $(thirdparty) packages\windows\installer +!endif + +!include windows/NTMakefile.w32 + +all:: + @echo Build finished succesfully diff --git a/README b/README index f13069859..9e4ba911d 100644 --- a/README +++ b/README @@ -1,18 +1,19 @@ -Heimdal is a Kerberos 5 implementation. +Heimdal is an implementation of: ASN.1/DER, PKIX, and Kerberos. -Please see the manual in doc, by default installed in -/usr/heimdal/info/heimdal.info for information on how to install. -There are also briefer man pages for most of the commands. +For information how to install see +. -Bug reports and bugs are appreciated, see more under Bug reports in -the manual on how we prefer them. +There are briefer man pages for most of the commands. + +Bug reports and bugs are appreciated. Use GitHub issues. +. For more information see the web-page at - or the mailing lists: + or the mailing lists: -heimdal-announce@sics.se low-volume announcement -heimdal-discuss@sics.se high-volume discussion +heimdal-announce@heimdal.software low-volume announcement +heimdal-discuss@heimdal.software high-volume discussion -send a mail to heimdal-announce-request@sics.se and -heimdal-discuss-request@sics.se respectively to subscribe. +send a mail to heimdal-announce-subscribe@heimdal.software and +heimdal-discuss-subscribe@heimdal.software respectively to subscribe. diff --git a/README.fast b/README.fast new file mode 100644 index 000000000..d0cd5121d --- /dev/null +++ b/README.fast @@ -0,0 +1,13 @@ + +-- in order of preference + +- client: plugin support for fast plugins + note GSS-API can be used as PA plugin interface + +- kdc: plugin support for fast plugins + partly done with "struct kdc_patypes" + +- kcm: support FAST armor ticket +-- using PK-INIT anonymous +-- using host key + diff --git a/README.md b/README.md new file mode 100644 index 000000000..5e49fd0e1 --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +[![GitHub Build Workflow](https://github.com/heimdal/heimdal/actions/workflows/linux.yml/badge.svg)](https://github.com/heimdal/heimdal/actions?query=workflow%3Alinux) +[![GitHub Build Workflow](https://github.com/heimdal/heimdal/actions/workflows/osx.yml/badge.svg)](https://github.com/heimdal/heimdal/actions?query=workflow%3Aosx) +[![GitHub Build Workflow](https://github.com/heimdal/heimdal/actions/workflows/windows.yml/badge.svg)](https://github.com/heimdal/heimdal/actions?query=workflow%3Awindows) +[![Appveyor-CI build (Windows)](https://ci.appveyor.com/api/projects/status/6j0k0m7kd6jjj4tw/branch/master?svg=true)](https://ci.appveyor.com/project/heimdal/heimdal/branch/master) +[![Coverage Status](https://coveralls.io/repos/github/heimdal/heimdal/badge.svg?branch=master)](https://coveralls.io/github/heimdal/heimdal?branch=master) + +Heimdal +======= + +Heimdal is an implementation of: + + - ASN.1/DER, + - PKIX, and + - Kerberos. + +For information how to install see [here](https://github.com/heimdal/heimdal/wiki/Building-and-installing). + +There are man pages for most of the commands. + +Bug reports and bugs are appreciated. Use [GitHub issues](https://www.heimdal.software/heimdal/issues). + +For more information see the project homepage [https://heimdal.software/heimdal/](https://heimdal.software/heimdal/) or the mailing lists: + + heimdal-announce@heimdal.software low-volume announcement + heimdal-discuss@heimdal.software high-volume discussion + +send mail to [heimdal-announce-subscribe@heimdal.software](mailto:heimdal-announce-subscribe@heimdal.software) and +[heimdal-discuss-subscribe@heimdal.software](mailto:heimdal-discuss-subscribe@heimdal.software) +respectively to subscribe. + + +Build Status +============ + +[![GitHub Build Workflow](https://github.com/heimdal/heimdal/actions/workflows/linux.yml/badge.svg)](https://github.com/heimdal/heimdal/actions?query=workflow%3Alinux) +[![GitHub Build Workflow](https://github.com/heimdal/heimdal/actions/workflows/osx.yml/badge.svg)](https://github.com/heimdal/heimdal/actions?query=workflow%3Aosx) +[![GitHub Build Workflow](https://github.com/heimdal/heimdal/actions/workflows/windows.yml/badge.svg)](https://github.com/heimdal/heimdal/actions?query=workflow%3Awindows) +[![Appveyor-CI build (Windows)](https://ci.appveyor.com/api/projects/status/6j0k0m7kd6jjj4tw/branch/master?svg=true)](https://ci.appveyor.com/project/heimdal/heimdal/branch/master) +[![Coverage Status](https://coveralls.io/repos/github/heimdal/heimdal/badge.svg?branch=master)](https://coveralls.io/github/heimdal/heimdal?branch=master) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..77b313b56 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,90 @@ +# Security Policy + +## Supported Versions + +Use this section to tell people about which versions of your project are +currently being supported with security updates. + +| Version | Supported | +| ------- | ------------------ | +| 7.x.x | :white_check_mark: | +| < 7.0 | :x: | + +## Reporting a Vulnerability + +Security sensitive bug reports should be sent to +heimdal-security@heimdal.team using this PGP key. + +Key ID: 9A077911BB7DC320 + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2.0.22 (MingW32) + +mQINBFz8mXMBEAC3oUdMAP52TaJYQ2Rri0C4hNx7v73Jb/MqoAJKyJ7RKlGkpNp4 +8K7+/VwRqiex0Cs//wU2TMCLRK7n/J2YG3Z+Eu2FZeWRUmEJfvzgXDi/IfYmyytV +DU5RxFF7oB3X8xeESoLLB1haGuDR4fTxgtIJGVgh6ShddcMObO9zhqGtLmlf6BTD +fXPxxPn0fNqStVh38rEoL3Ri/KFoojOxIFubhfrKfTwRarNUUCT6b+ybra82rfB1 +JzNICraskvZGelCvC7vIflHLeg6a2a9dYkJeaNbXPR0p2BbNWoZ+y/nukCtTQHNO +avsFnALgm4LpWjEOkCr38TRPllrrYYA+DbjfB4bnp4BxOd1DaXtwBvkm/QMn2xuv +DBsJklY2RzAW9/l0S6VDVNbtIao21wtDLC98SdR9iweOcuvm0LcTfzEfiSf6vqIt +YIatTo7wh2/X0axzHsE5XTxmwzutMQ5ysOkgj5v6bmhxhAxNYspmSeei8698t2xT +ezOJwj2zjzaqgSQVND9uaRkxWkEQnp8P26DizGgO8VygAKSM6abqGnSXQgHrLYWR +FziTai98M3f9DA8m4aAxYHNRh/EnE7CieM8QglEEqRjfUzaZs+cUQMZaEMAkh8G6 +yJKhEWfhiWR6vK6vdA1lUSgzTGynch96OCrOYebjfp0VKLOFgkGauusyZwARAQAB +tDBIZWltZGFsIFNlY3VyaXR5IDxoZWltZGFsLXNlY3VyaXR5QGhlaW1kYWwudGVh +bT6JAjkEEwECACMFAlz8mXMCGyMHCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAK +CRCaB3kRu33DICt6D/4/SzcNwUHb4CsOFgBVX/f4Gi6VDaGzgcthX8ddby2sHmgJ +YvmHD3ftwATVPZ0NtZ0h0v6tlBBVP6lq2lV0dJk4wDRZU2x2xxCMNFvgid2OFH4n +s47Wyed63IKokuwfqqDRcTMKLG/8zE0s/zmczxGw4KTPkiFe58qWPS4WdQqxhGbQ +byDByi16yO/5Yp13kFhtdzpDiwCIlf4W1DkwK133JZRKGvvc2E8dFY0H1u+ZYWj5 +YkJMbxSJkUD8vOarO7LaHLTeu+nRwrbmBqNX3e7UOcgCozwTpTlD63oxZ25HOSCb +nJs0xjQU0lGhebbBWO0e2gGljE+irAuIO5sPd/JOxV+Ppl97LkRFs2PrNqABj1XP +caknBkeT//12s2YbmQAMv3xWdqsH8YypWHMSG4vTwxS/CdM2FqrPiAUUa9OoZaSK +Oi9CxV5/02XkGIdVDKLqAXpzYMbQXRGyUORL/93QLULq3CMZq8depzELJGGhTr52 +tqtK1ecq8hUqtroSixFydKOfHL/CnssteRHTOT0O110PLOkrcPAE7cadjhYYUXWc +4R8QnUQpUnpsEDBLOeqLubw/yGCG9YfA3j6uXkWsKeFuC5P0QG1ptoOEcT40l0J0 +bbHSSrbeAsovGQcs7qZGs0Vybetufx3YbhFcj85W64+Q36YK97L2gnuitnxNPIhG +BBMRAgAGBQJc/Jr7AAoJEFWROgb+WUtoRN4An1T7Oz+P0xe+TRCDISoofk9QuXLk +AKCw9dd28MLBFjeBSDgihi27RqtjOIkBHAQTAQIABgUCXPybJwAKCRDcZtQjSX34 +eN2sB/46kXACbiPbfZKa4HuipnTGbmach66PrTkpdZUXt+kYyO9Os33kLO33qNSe +mFZwRHJGMhahzMZMEA18n85HYyQw4/Kqx/Atr2TnVigJpN2YIw0L6rfv9KP8vhwK +fn4YXpH1ZFs54EUK85pT+Orbkk83tWPDnUlf9dkVX2GHWBqTbUjbKduaEbdDvRqE +NiiXTWhaSBpxLW/Iqu/ogwAH+36B1apLjoBtMYzU3up+OKrNN+Lrsi0ztCdhGIjj +jND4JiqnnaKbKOpj6htXJHryXNicXfFa64cHtrYkz8PJVEpo4AkBIAZRvgl0C5vT +HkeyBuRAHSbvtN0EfQCgIFJRUVnmiQIcBBMBAgAGBQJc/JtjAAoJEPd6c1WStpoE +GooQAJB1zZwIeTKj77FqqfPtU9sc8DWrxnBSYSJCYJAM4520OaG2RBpLFjJ30GSY +Ky9MeUGOCfOl4wx9LfMU4GKFqxjw5N0H7f2DTNdPKp5QzZT5LIle5xu4UerolDdU +Wn/LOJpYJbYnyFKOi3NU0A8yS1wJsJ1ZGf4GB6Xi9q8Wx+E482pSFDWkFInwAozc +rvZCtx/4vsEKLWDCEOlUclbnmipiUtKm1jxyOnTQbzqx5X5ZLxIjTmz/LdvJJiYf +H+BAFAaIlCr5JWw6SSRo/cL0l7b+Q0YPqaY+ElTdYQXyfC0C0yPVmpA2jnqpgUp/ +O53AYZNZtvRnbBq67VWSbBUXllu44QgVI180tBeDqZWYbGcyRWQ+36S3xh6O1gfA +cOqs6IzKNtALFOYKLvaWFP+Tls+uGAzYeQFN92V0n3agK1p9rGmMa79yPyIqeHfi +7cpnqtsjXDm6qoMD+119tWL+exg3GKzZpYVpptpSQXnVzqOLGhEQdVtQ8uLaY/4g +2CL27Rg3wp+dmQDPmUWqZIWBg32R6vqxzbKcnwaAqLiH0ryULOB2ebKPu/FKQGZN +5I6S75pwzXoDioXD1ALAeAyhfpp2XSYDI3AeLvF34hgPwLuw1AVdr0VF27E7IAub +lcHvdNS+bry6k16difwjJS9G2qRblZmwxpv5UpdiRW87YDjLuQINBFz8mXMBEACg +P4pnjDcLtWTDfNNaRbTl/4VTLKEgTwF04dslWFKJt7SiDepwcJNBux6sPdF3B4/U +VQXI1OqQ9msBz4nQj5c+m2ZQC2mRohLIjigmEiCe+62CbauKP5Jaj4xKW0xEkPiX +DsiUWZqetQBXvxjVvh6rS1MArzKtLOGXHsaRRK84JquD+CjMxKwOPPgRJNbOay5f +rXfKV2oxVWGxylaZnc1zZhLau+Z1mto1c80glt1HNTNzue1NLBckB55Z7nUn0ue8 +q2pay1VrPwdM2Ym/r+K5mpwvqKw9Xwc8Uj/Uypb9r9Qt8WvlZ7j1lbbF9Tgs4Hjk +O5ZmHN4SZxhRHSymwce6R3efp+3T1A2I0es5BGBhmz62i2x98Jf3uaR7wQIGO+bS +3XoVG1llghpYYZIVK1x+2HyWqfVBfnO62vbULA5wtXYdY5V+R7gzctnybr0SUjh0 +msWLh39G3yReU9ia4dZg4CLb3/bAf25AeN+V8DraGyPdeieMOfad+IpazFm0aPo/ +zmMe94mhyOK/pDkuvLOvSGQm0dy/lWPLK8K8p4fLMKKRv6Tyzps77407GWqo8+8R +sF9YPvN2/E0iJXokgIKrCQtoovNsitgL9CANX8+kzcs5QHsh/FJJhLoA3zwaR/9S +nAP3JeAubda4PbBXggzsv2+lIIBvz5URwN9lSPdblQARAQABiQIfBBgBAgAJBQJc +/JlzAhsMAAoJEJoHeRG7fcMgMGwP/00bpcf6K/GCZxAuu0vuohvKe3tTR1cD8Sks +ZsavXyvaUuHkZn31OPow/RGYcRnMLfh9iddgV++lxYcaZ8iILtGnH9vXg0bhiX1x +XLhSRwcpF1Rf7/1KgAsKcd0PtHehxNMEiS9ISqZBDZQyMYaCh2wK5FienQziGOLx +ehHxarEfwQJEFqW3+rWs5YhaRD4fLuxi4fxefT9TQp+rZp+2CNFENI5w2bFFkFYe +wUZ2waTbxpFUDV2HB0znH8HEyIfEBGGpbD8tHCiM7W46gpi6mBnEfd/3gQu+ewoz +z4dfspKTQfuIUMN1s0+iqzY9to1Bzfrnc328ntMnhfXsz91hwqMLpD36zLUTtHPc +Zf9E+R4Q9bsqGUoVo8xrkd52Nxta24leF5x7+8K90vghsFJ8dP1qS2y8w3emUlDn +++GVrZWJRLhwbVOtcroRF2WqGTRRJZ5sgaMq5LIE9KUCKioq+/gFvWyDABH1Y1jq +vEep+eyl6DuEoDY9KV912EUtF7Fn7mM1aY4tLOYYGVIqy/SfvKKS+8Fv9QUkFjVV +PhkGVow1Hh8SHAzq/8mMV6/D7xUgMJhfnjwUNp0t7s5J9xN4uLSKSVlyNkI2JRvd +m445blzP6zyWOwlY1RdOX+qEo+y7zyruWc3EB8kzQTKjIzShVN3k+SOAO4QGM6Jy +CthJqQ8K +=Nb2m +-----END PGP PUBLIC KEY BLOCK----- diff --git a/TODO b/TODO index 7e4a08699..87c50b82b 100644 --- a/TODO +++ b/TODO @@ -1,49 +1,30 @@ -*- indented-text -*- -$Id$ - -* configure - -* appl - -** appl/popper - -* doc - -* kdc - -* kadmin - -* kpasswdd - -* lib - -** lib/asn1 - -** lib/auth - -** lib/auth/sia - -** lib/com_err - -** lib/des - ** lib/gssapi cache delegation credentials to avoid hitting the kdc ? require time stampless tickets, and was supported in the recv'ing end with 0.6.1. -** lib/hdb +make iov work for arcfour + +make iov work for ntlm + +interop test + +make TYPE_STREAM work ** lib/kadm5 add policies? -fix to use rpc? - ** lib/krb5 verify_user: handle non-secure verification failing because of host->realm mapping -** lib/roken +* windows stuff + +-- drop all double negation #ifndef NO_ +-- got though windows specific ifdefs to minimized them +-- switch to use heim-ipc for services, like the kadmin change notification socket +-- Unify lib/krb5/expand_path_w32.c diff --git a/TODO-iov b/TODO-iov deleted file mode 100644 index 6217960fe..000000000 --- a/TODO-iov +++ /dev/null @@ -1,5 +0,0 @@ - -make iov work for arcfour -make iov work for ntlm -interop test -make TYPE_STREAM work diff --git a/admin/Makefile.am b/admin/Makefile.am index 3948e3fdd..1821d4b2e 100644 --- a/admin/Makefile.am +++ b/admin/Makefile.am @@ -2,13 +2,11 @@ include $(top_srcdir)/Makefile.am.common -AM_CPPFLAGS += $(INCLUDE_readline) $(INCLUDE_hcrypto) +AM_CPPFLAGS += $(INCLUDE_readline) -SLC = $(top_builddir)/lib/sl/slc +man_MANS = ktutil.1 -man_MANS = ktutil.8 - -sbin_PROGRAMS = ktutil +bin_PROGRAMS = ktutil dist_ktutil_SOURCES = \ add.c \ @@ -39,7 +37,8 @@ LDADD = \ $(LIB_hcrypto) \ $(top_builddir)/lib/asn1/libasn1.la \ $(top_builddir)/lib/sl/libsl.la \ + $(LIB_heimbase) \ $(LIB_readline) \ $(LIB_roken) -EXTRA_DIST = $(man_MANS) ktutil-commands.in +EXTRA_DIST = NTMakefile ktutil-version.rc $(man_MANS) ktutil-commands.in diff --git a/admin/NTMakefile b/admin/NTMakefile new file mode 100644 index 000000000..f78a201a8 --- /dev/null +++ b/admin/NTMakefile @@ -0,0 +1,75 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=admin +cincdirs=$(cincdirs) -I$(OBJ) +!include ../windows/NTMakefile.w32 + +SBINPROGRAMS=$(SBINDIR)\ktutil.exe + +KTUTIL_OBJS= \ + $(OBJ)\add.obj \ + $(OBJ)\change.obj \ + $(OBJ)\copy.obj \ + $(OBJ)\destroy.obj \ + $(OBJ)\get.obj \ + $(OBJ)\ktutil.obj \ + $(OBJ)\ktutil-commands.obj \ + $(OBJ)\list.obj \ + $(OBJ)\purge.obj \ + $(OBJ)\remove.obj \ + $(OBJ)\rename.obj + +KTUTIL_LIBS= \ + $(LIBHEIMBASE) \ + $(LIBHEIMDAL) \ + $(LIBKADM5SRV) \ + $(LIBSL) \ + $(LIBROKEN) \ + $(LIBVERS) + +$(SBINDIR)\ktutil.exe: $(KTUTIL_OBJS) $(KTUTIL_LIBS) $(OBJ)\ktutil-version.res + $(EXECONLINK) + $(EXEPREP) + +$(OBJ)\ktutil-commands.c $(OBJ)\ktutil-commands.h: ktutil-commands.in + cd $(OBJ) + $(CP) $(SRCDIR)\ktutil-commands.in $(OBJ) + $(BINDIR)\slc.exe ktutil-commands.in + cd $(SRCDIR) + +INCFILES=\ + $(OBJ)\ktutil-commands.h + +all:: $(INCFILES) $(SBINPROGRAMS) + +clean:: + -$(RM) $(SBINPROGRAMS:.exe=.*) diff --git a/admin/add.c b/admin/add.c index 16216db4f..5f3d58459 100644 --- a/admin/add.c +++ b/admin/add.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan + * Copyright (c) 1997-2022 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -32,6 +32,8 @@ */ #include "ktutil_locl.h" +#include +#include RCSID("$Id$"); @@ -94,7 +96,8 @@ kt_add(struct add_options *opt, int argc, char **argv) goto out; } if(opt->password_string == NULL && opt->random_flag == 0) { - if(UI_UTIL_read_pw_string(buf, sizeof(buf), "Password: ", 1)) { + if(UI_UTIL_read_pw_string(buf, sizeof(buf), "Password: ", + UI_UTIL_FLAG_VERIFY)) { ret = 1; goto out; } @@ -104,7 +107,7 @@ kt_add(struct add_options *opt, int argc, char **argv) if (opt->hex_flag) { size_t len; void *data; - + len = (strlen(opt->password_string) + 1) / 2; data = malloc(len); @@ -113,7 +116,7 @@ kt_add(struct add_options *opt, int argc, char **argv) goto out; } - if (hex_decode(opt->password_string, data, len) != len) { + if ((size_t)hex_decode(opt->password_string, data, len) != len) { free(data); krb5_warn(context, ENOMEM, "hex decode failed"); goto out; @@ -152,6 +155,180 @@ kt_add(struct add_options *opt, int argc, char **argv) krb5_warn(context, ret, "add"); out: krb5_kt_free_entry(context, &entry); - krb5_kt_close(context, keytab); + if (ret == 0) { + ret = krb5_kt_close(context, keytab); + if (ret) + krb5_warn(context, ret, "Could not write the keytab"); + } else { + krb5_kt_close(context, keytab); + } + return ret != 0; +} + +/* We might be reading from a pipe, so we can't use rk_undumpdata() */ +static char * +read_file(FILE *f) +{ + size_t alloced; + size_t len = 0; + size_t bytes; + char *res, *end, *p; + + if ((res = malloc(1024)) == NULL) + err(1, "Out of memory"); + alloced = 1024; + + end = res + alloced; + p = res; + do { + if (p == end) { + char *tmp; + + if ((tmp = realloc(res, alloced + (alloced > 1))) == NULL) + err(1, "Out of memory"); + alloced += alloced > 1; + p = tmp + len; + res = tmp; + end = res + alloced; + } + bytes = fread(p, 1, end - p, f); + len += bytes; + p += bytes; + } while (bytes && !feof(f) && !ferror(f)); + + if (ferror(f)) + errx(1, "Could not read all input"); + if (p == end) { + char *tmp; + + if ((tmp = strndup(res, len)) == NULL) + err(1, "Out of memory"); + free(res); + res = tmp; + } + if (strlen(res) != len) + err(1, "Embedded NULs in input!"); + return res; +} + +static void +json2keytab_entry(heim_dict_t d, krb5_keytab kt, size_t idx) +{ + krb5_keytab_entry e; + krb5_error_code ret; + heim_object_t v; + uint64_t u; + int64_t i; + char *buf = NULL; + + memset(&e, 0, sizeof(e)); + + v = heim_dict_get_value(d, HSTR("timestamp")); + if (heim_get_tid(v) != HEIM_TID_NUMBER) + goto bad; + u = heim_number_get_long(v); + e.timestamp = u; + if (u != (uint64_t)e.timestamp) + goto bad; + + v = heim_dict_get_value(d, HSTR("kvno")); + if (heim_get_tid(v) != HEIM_TID_NUMBER) + goto bad; + i = heim_number_get_long(v); + e.vno = i; + if (i != (int64_t)e.vno) + goto bad; + + v = heim_dict_get_value(d, HSTR("enctype_number")); + if (heim_get_tid(v) != HEIM_TID_NUMBER) + goto bad; + i = heim_number_get_long(v); + e.keyblock.keytype = i; + if (i != (int64_t)e.keyblock.keytype) + goto bad; + + v = heim_dict_get_value(d, HSTR("key")); + if (heim_get_tid(v) != HEIM_TID_STRING) + goto bad; + { + const char *s = heim_string_get_utf8(v); + int declen; + + if ((buf = malloc(strlen(s))) == NULL) + err(1, "Out of memory"); + declen = rk_base64_decode(s, buf); + if (declen < 0) + goto bad; + e.keyblock.keyvalue.data = buf; + e.keyblock.keyvalue.length = declen; + } + + v = heim_dict_get_value(d, HSTR("principal")); + if (heim_get_tid(v) != HEIM_TID_STRING) + goto bad; + ret = krb5_parse_name(context, heim_string_get_utf8(v), &e.principal); + if (ret == 0) + ret = krb5_kt_add_entry(context, kt, &e); + + /* For now, ignore aliases; besides, they're never set anywhere in-tree */ + + if (ret) + krb5_warn(context, ret, + "Could not parse or write keytab entry %lu", + (unsigned long)idx); +bad: + krb5_free_principal(context, e.principal); + free(buf); +} + +int +kt_import(void *opt, int argc, char **argv) +{ + krb5_error_code ret; + krb5_keytab kt; + heim_object_t o; + heim_error_t json_err = NULL; + heim_json_flags_t flags = HEIM_JSON_F_STRICT; + FILE *f = argc == 0 ? stdin : fopen(argv[0], "r"); + size_t alen, i; + char *json; + + if (f == NULL) + err(1, "Could not open file %s", argv[0]); + + json = read_file(f); + fclose(f); + o = heim_json_create(json, 10, flags, &json_err); + free(json); + if (o == NULL) { + if (json_err != NULL) { + o = heim_error_copy_string(json_err); + if (o) + errx(1, "Could not parse JSON: %s", heim_string_get_utf8(o)); + } + errx(1, "Could not parse JSON"); + } + + if (heim_get_tid(o) != HEIM_TID_ARRAY) + errx(1, "JSON text must be an array"); + + alen = heim_array_get_length(o); + if (alen == 0) + errx(1, "Empty JSON array; not overwriting keytab"); + + if ((kt = ktutil_open_keytab()) == NULL) + err(1, "Could not open keytab"); + + for (i = 0; i < alen; i++) { + heim_object_t e = heim_array_get_value(o, i); + + if (heim_get_tid(e) != HEIM_TID_DICT) + warnx("Element %ld of JSON text array is not an object", (long)i); + else + json2keytab_entry(heim_array_get_value(o, i), kt, i); + } + ret = krb5_kt_close(context, kt); + if (ret) + krb5_warn(context, ret, "Could not write the keytab"); return ret != 0; } diff --git a/admin/change.c b/admin/change.c index 1693c3497..b9d0e830d 100644 --- a/admin/change.c +++ b/admin/change.c @@ -36,17 +36,23 @@ RCSID("$Id$"); static krb5_error_code -change_entry (krb5_keytab keytab, - krb5_principal principal, krb5_kvno kvno, - const char *realm, const char *admin_server, int server_port) +change_entry(krb5_keytab keytab, + krb5_principal principal, + krb5_kvno kvno, + int keep, + size_t nkstuple, + krb5_key_salt_tuple *kstuple, + const char *realm, + const char *admin_server, + int server_port) { krb5_error_code ret; kadm5_config_params conf; void *kadm_handle; char *client_name; krb5_keyblock *keys; + size_t i; int num_keys; - int i; ret = krb5_unparse_name (context, principal, &client_name); if (ret) { @@ -73,7 +79,7 @@ change_entry (krb5_keytab keytab, free(conf.realm); krb5_set_error_message(context, ENOMEM, "malloc failed"); return ENOMEM; - } + } conf.mask |= KADM5_CONFIG_ADMIN_SERVER; } @@ -96,14 +102,15 @@ change_entry (krb5_keytab keytab, free (client_name); return ret; } - ret = kadm5_randkey_principal (kadm_handle, principal, &keys, &num_keys); - kadm5_destroy (kadm_handle); + ret = kadm5_randkey_principal_3(kadm_handle, principal, keep, nkstuple, + kstuple, &keys, &num_keys); + kadm5_destroy(kadm_handle); if (ret) { - krb5_warn(context, ret, "kadm5_randkey_principal: %s:", client_name); + krb5_warn(context, ret, "kadm5_randkey_principal_3: %s:", client_name); free (client_name); return ret; } - free (client_name); + free(client_name); for (i = 0; i < num_keys; ++i) { krb5_keytab_entry new_entry; @@ -131,18 +138,55 @@ struct change_set { }; int -kt_change (struct change_options *opt, int argc, char **argv) +kt_change(struct change_options *opt, int argc, char **argv) { krb5_error_code ret; krb5_keytab keytab; krb5_kt_cursor cursor; krb5_keytab_entry entry; - int i, j, max; + krb5_key_salt_tuple *kstuple = NULL; + const char *enctype; + size_t i, j, max, nkstuple; + int keep = 1; struct change_set *changeset; int errors = 0; - if((keytab = ktutil_open_keytab()) == NULL) + i = 0; + + if (opt->keepold_flag) { + keep = 1; + i++; + } + if (opt->keepallold_flag) { + keep = 2; + i++; + } + if (opt->pruneall_flag) { + keep = 0; + i++; + } + if (i > 1) { + fprintf(stderr, "use only one of --keepold, --keepallold, or --pruneall\n"); + return EINVAL; + } + + enctype = opt->enctype_string; + if (enctype == NULL || enctype[0] == '\0') + enctype = krb5_config_get_string(context, NULL, "libdefaults", + "supported_enctypes", NULL); + if (enctype == NULL || enctype[0] == '\0') + enctype = "aes128-cts-hmac-sha1-96"; + ret = krb5_string_to_keysalts2(context, enctype, &nkstuple, &kstuple); + if (ret) { + fprintf(stderr, "enctype(s) unknown\n"); + return ret; + } + + /* XXX Parameterize keytab name */ + if ((keytab = ktutil_open_keytab()) == NULL) { + free(kstuple); return 1; + } j = 0; max = 0; @@ -217,7 +261,6 @@ kt_change (struct change_options *opt, int argc, char **argv) krb5_kt_end_seq_get(context, keytab, &cursor); if (ret == KRB5_KT_END) { - ret = 0; for (i = 0; i < j; i++) { if (verbose_flag) { char *client_name; @@ -232,11 +275,12 @@ kt_change (struct change_options *opt, int argc, char **argv) free(client_name); } } - ret = change_entry (keytab, - changeset[i].principal, changeset[i].kvno, - opt->realm_string, - opt->admin_server_string, - opt->server_port_integer); + ret = change_entry(keytab, + changeset[i].principal, changeset[i].kvno, + keep, nkstuple, kstuple, + opt->realm_string, + opt->admin_server_string, + opt->server_port_integer); if (ret != 0) errors = 1; } @@ -247,6 +291,7 @@ kt_change (struct change_options *opt, int argc, char **argv) free (changeset); out: + free(kstuple); krb5_kt_close(context, keytab); return errors; } diff --git a/admin/copy.c b/admin/copy.c index 7b50de1c3..8acd6e48e 100644 --- a/admin/copy.c +++ b/admin/copy.c @@ -47,7 +47,7 @@ compare_keyblock(const krb5_keyblock *a, const krb5_keyblock *b) } int -kt_copy (void *opt, int argc, char **argv) +kt_copy (struct copy_options *opt, int argc, char **argv) { krb5_error_code ret; krb5_keytab src_keytab, dst_keytab; @@ -106,11 +106,18 @@ kt_copy (void *opt, int argc, char **argv) "already exists for %s, keytype %s, kvno %d", name_str, etype_str, entry.vno); } - krb5_kt_free_entry(context, &dummy); - krb5_kt_free_entry (context, &entry); - free(name_str); - free(etype_str); - continue; + if (!opt->copy_duplicates_flag) { + krb5_kt_free_entry(context, &dummy); + krb5_kt_free_entry (context, &entry); + free(name_str); + free(etype_str); + continue; + } + /* + * Because we can end up trying all keys that match the enctype, + * copying entries with duplicate principal, vno, and enctype, but + * different keys, can be useful. + */ } else if(ret != KRB5_KT_NOTFOUND) { krb5_warn (context, ret, "%s: fetching %s/%s/%u", to, name_str, etype_str, entry.vno); diff --git a/admin/get.c b/admin/get.c index ee96e5eeb..1c0a6333a 100644 --- a/admin/get.c +++ b/admin/get.c @@ -82,56 +82,97 @@ open_kadmin_connection(char *principal, return kadm_handle; } +static int +parse_enctypes(struct get_options *opt, + size_t *nks, + krb5_key_salt_tuple **ks) +{ + const char *str; + char *s = NULL; + char *tmp; + size_t i; + int ret; + + *nks = 0; + *ks = NULL; + if (opt->enctypes_strings.num_strings == 0) { + str = krb5_config_get_string(context, NULL, "libdefaults", + "supported_enctypes", NULL); + if (str == NULL) + str = "aes128-cts-hmac-sha1-96"; + return krb5_string_to_keysalts2(context, str, nks, ks); + } + + for (i = 0; i < opt->enctypes_strings.num_strings; i++) { + if (asprintf(&tmp, "%s%s%s", i ? s : "", i ? "," : "", + opt->enctypes_strings.strings[i]) == -1) { + free(s); + return krb5_enomem(context); + } + free(s); + s = tmp; + } + ret = krb5_string_to_keysalts2(context, s, nks, ks); + free(s); + return ret; +} + int kt_get(struct get_options *opt, int argc, char **argv) { krb5_error_code ret = 0; krb5_keytab keytab; void *kadm_handle = NULL; - krb5_enctype *etypes = NULL; - size_t netypes = 0; - int i, j; + krb5_key_salt_tuple *ks = NULL; + size_t nks; + size_t i; + int a, j, keep; unsigned int failed = 0; - if((keytab = ktutil_open_keytab()) == NULL) + i = 0; + keep = 1; + if (opt->keepallold_flag) { + keep = 2; + i++; + } + if (opt->keepold_flag) { + keep = 1; + i++; + } + if (opt->pruneall_flag) { + keep = 0; + i++; + } + if (i > 1) { + fprintf(stderr, "use only one of --keepold, --keepallold, or --pruneall\n"); + return EINVAL; + } + + if ((ret = parse_enctypes(opt, &nks, &ks))) { + fprintf(stderr, "invalid enctype(s)\n"); + return ret; + } + + if((keytab = ktutil_open_keytab()) == NULL) { + free(ks); return 1; + } if(opt->realm_string) krb5_set_default_realm(context, opt->realm_string); - if (opt->enctypes_strings.num_strings != 0) { - - etypes = malloc (opt->enctypes_strings.num_strings * sizeof(*etypes)); - if (etypes == NULL) { - krb5_warnx(context, "malloc failed"); - goto out; - } - netypes = opt->enctypes_strings.num_strings; - for(i = 0; i < netypes; i++) { - ret = krb5_string_to_enctype(context, - opt->enctypes_strings.strings[i], - &etypes[i]); - if(ret) { - krb5_warnx(context, "unrecognized enctype: %s", - opt->enctypes_strings.strings[i]); - goto out; - } - } - } - - - for(i = 0; i < argc; i++){ + for(a = 0; a < argc; a++){ krb5_principal princ_ent; kadm5_principal_ent_rec princ; int mask = 0; krb5_keyblock *keys; - int n_keys; + int n_keys = 0; int created = 0; krb5_keytab_entry entry; - ret = krb5_parse_name(context, argv[i], &princ_ent); + ret = krb5_parse_name(context, argv[a], &princ_ent); if (ret) { - krb5_warn(context, ret, "can't parse principal %s", argv[i]); + krb5_warn(context, ret, "can't parse principal %s", argv[a]); failed++; continue; } @@ -156,28 +197,33 @@ kt_get(struct get_options *opt, int argc, char **argv) if(kadm_handle == NULL) break; } - - ret = kadm5_create_principal(kadm_handle, &princ, mask, "x"); - if(ret == 0) - created = 1; - else if(ret != KADM5_DUP) { - krb5_warn(context, ret, "kadm5_create_principal(%s)", argv[i]); - krb5_free_principal(context, princ_ent); - failed++; - continue; - } - ret = kadm5_randkey_principal(kadm_handle, princ_ent, &keys, &n_keys); - if (ret) { - krb5_warn(context, ret, "kadm5_randkey_principal(%s)", argv[i]); - krb5_free_principal(context, princ_ent); - failed++; - continue; - } - + + if (opt->create_flag) { + ret = kadm5_create_principal(kadm_handle, &princ, mask, "thisIs_aUseless.password123"); + if(ret == 0) + created = 1; + else if(ret != KADM5_DUP) { + krb5_warn(context, ret, "kadm5_create_principal(%s)", argv[a]); + krb5_free_principal(context, princ_ent); + failed++; + continue; + } + } + if (opt->change_keys_flag) { + ret = kadm5_randkey_principal_3(kadm_handle, princ_ent, keep, nks, ks, + &keys, &n_keys); + if (ret) { + krb5_warn(context, ret, "kadm5_randkey_principal(%s)", argv[a]); + krb5_free_principal(context, princ_ent); + failed++; + continue; + } + } + ret = kadm5_get_principal(kadm_handle, princ_ent, &princ, KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES); if (ret) { - krb5_warn(context, ret, "kadm5_get_principal(%s)", argv[i]); + krb5_warn(context, ret, "kadm5_get_principal(%s)", argv[a]); for (j = 0; j < n_keys; j++) krb5_free_keyblock_contents(context, &keys[j]); krb5_free_principal(context, princ_ent); @@ -185,7 +231,7 @@ kt_get(struct get_options *opt, int argc, char **argv) continue; } if(!created && (princ.attributes & KRB5_KDB_DISALLOW_ALL_TIX)) - krb5_warnx(context, "%s: disallow-all-tix flag set - clearing", argv[i]); + krb5_warnx(context, "%s: disallow-all-tix flag set - clearing", argv[a]); princ.attributes &= (~KRB5_KDB_DISALLOW_ALL_TIX); mask = KADM5_ATTRIBUTES; if(created) { @@ -194,7 +240,7 @@ kt_get(struct get_options *opt, int argc, char **argv) } ret = kadm5_modify_principal(kadm_handle, &princ, mask); if (ret) { - krb5_warn(context, ret, "kadm5_modify_principal(%s)", argv[i]); + krb5_warn(context, ret, "kadm5_modify_principal(%s)", argv[a]); for (j = 0; j < n_keys; j++) krb5_free_keyblock_contents(context, &keys[j]); krb5_free_principal(context, princ_ent); @@ -202,37 +248,22 @@ kt_get(struct get_options *opt, int argc, char **argv) continue; } for(j = 0; j < n_keys; j++) { - int do_add = TRUE; - - if (netypes) { - int k; - - do_add = FALSE; - for (k = 0; k < netypes; ++k) - if (keys[j].keytype == etypes[k]) { - do_add = TRUE; - break; - } - } - if (do_add) { - entry.principal = princ_ent; - entry.vno = princ.kvno; - entry.keyblock = keys[j]; - entry.timestamp = time (NULL); - ret = krb5_kt_add_entry(context, keytab, &entry); - if (ret) - krb5_warn(context, ret, "krb5_kt_add_entry"); - } + entry.principal = princ_ent; + entry.vno = princ.kvno; + entry.keyblock = keys[j]; + entry.timestamp = time (NULL); + ret = krb5_kt_add_entry(context, keytab, &entry); + if (ret) + krb5_warn(context, ret, "krb5_kt_add_entry"); krb5_free_keyblock_contents(context, &keys[j]); } - + kadm5_free_principal_ent(kadm_handle, &princ); krb5_free_principal(context, princ_ent); } - out: - free(etypes); if (kadm_handle) kadm5_destroy(kadm_handle); krb5_kt_close(context, keytab); + free(ks); return ret != 0 || failed > 0; } diff --git a/admin/ktutil-commands.in b/admin/ktutil-commands.in index dffcb8c2d..a85eb5c57 100644 --- a/admin/ktutil-commands.in +++ b/admin/ktutil-commands.in @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 Kungliga Tekniska Högskolan + * Copyright (c) 2004-2022 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -54,7 +54,7 @@ command = { short = "e" type = "string" argument = "enctype" - help = "encryption type" + help = "encryption type(s)" } option = { long = "password" @@ -75,6 +75,21 @@ command = { type = "flag" help = "generate random key" } + option = { + long = "keepold" + type = "flag" + help = "keep old keys/password needed to decrypt extant tickets (default)" + } + option = { + long = "keepallold" + type = "flag" + help = "keep all old keys/password" + } + option = { + long = "pruneall" + type = "flag" + help = "delete all old keys" + } option = { long = "hex" short = "H" @@ -94,6 +109,28 @@ command = { argument = "realm" help = "realm to use" } + option = { + long = "enctype" + short = "e" + type = "string" + argument = "enctype" + help = "encryption type(s)" + } + option = { + long = "keepold" + type = "flag" + help = "keep old keys/password needed to decrypt extant tickets (default)" + } + option = { + long = "keepallold" + type = "flag" + help = "keep all old keys/password" + } + option = { + long = "pruneall" + type = "flag" + help = "delete all old keys" + } option = { long = "admin-server" short = "a" @@ -114,11 +151,17 @@ command = { } command = { name = "copy" + name = "merge" function = "kt_copy" + option = { + long = "copy-duplicates" + type = "flag" + help = "copy entries for the same principal and kvno, but different keys" + } argument = "source destination" min_args = "2" max_args = "2" - help = "Copies one keytab to another." + help = "Merges one keytab into another." } command = { name = "get" @@ -129,6 +172,16 @@ command = { help = "admin principal" argument = "principal" } + option = { + long = "create" + type = "-flag" + help = "do not create the principal" + } + option = { + long = "change-keys" + type = "-flag" + help = "do not change the principal's keys" + } option = { long = "enctypes" short = "e" @@ -136,6 +189,21 @@ command = { help = "encryption types to use" argument = "enctype" } + option = { + long = "keepold" + type = "flag" + help = "keep old keys/password needed to decrypt extant tickets (default)" + } + option = { + long = "keepallold" + type = "flag" + help = "keep all old keys/password" + } + option = { + long = "pruneall" + type = "flag" + help = "delete all old keys" + } option = { long = "realm" short = "r" @@ -162,6 +230,14 @@ command = { argument = "principal..." help = "Change keys for specified principals, and add them to the keytab." } +command = { + name = "import" + function = "kt_import" + help = "Imports a keytab from JSON output of ktutil list --json --keys." + min_args = "0" + max_args = "1" + argument = "JSON-FILE" +} command = { name = "list" option = { @@ -174,6 +250,11 @@ command = { type = "flag" help = "show timestamps" } + option = { + long = "json" + type = "flag" + help = "output JSON representation" + } max_args = "0" function = "kt_list" help = "Show contents of keytab." @@ -206,7 +287,7 @@ command = { short = "V" type = "integer" help = "key version to remove" - argument = "enctype" + argument = "kvno" default = "0" } option = { diff --git a/admin/ktutil-version.rc b/admin/ktutil-version.rc new file mode 100644 index 000000000..e0e91c5ce --- /dev/null +++ b/admin/ktutil-version.rc @@ -0,0 +1,36 @@ +/*********************************************************************** + * Copyright (c) 2010, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#define RC_FILE_TYPE VFT_APP +#define RC_FILE_DESC_0409 "Kerberos Keytab Tool" +#define RC_FILE_ORIG_0409 "ktutil.exe" + +#include "../windows/version.rc" diff --git a/admin/ktutil.1 b/admin/ktutil.1 new file mode 100644 index 000000000..fb8bc382b --- /dev/null +++ b/admin/ktutil.1 @@ -0,0 +1,229 @@ +.\" Copyright (c) 1997-2004 Kungliga Tekniska Högskolan +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id$ +.\" +.Dd April 14, 2005 +.Dt KTUTIL 1 +.Os HEIMDAL +.Sh NAME +.Nm ktutil +.Nd manage Kerberos keytabs +.Sh SYNOPSIS +.Nm +.Oo Fl k Ar keytab \*(Ba Xo +.Fl Fl keytab= Ns Ar keytab +.Xc +.Oc +.Op Fl v | Fl Fl verbose +.Op Fl Fl version +.Op Fl h | Fl Fl help +.Ar command +.Op Ar args +.Sh DESCRIPTION +.Nm +is a program for managing keytabs. +Supported options: +.Bl -tag -width Ds +.It Fl v , Fl Fl verbose +Verbose output. +.El +.Pp +.Ar command +can be one of the following: +.Bl -tag -width srvconvert +.It Nm add Oo Fl p Ar principal Oc Oo Fl Fl principal= Ns Ar principal Oc \ +Oo Fl V Ar kvno Oc Oo Fl Fl kvno= Ns Ar kvno Oc Oo Fl e Ar enctype Oc \ +Oo Fl Fl keepold | Fl Fl keepallold | Fl Fl pruneall Oc \ +Oo Fl Fl enctype= Ns Ar enctype Oc Oo Fl w Ar password Oc \ +Oo Fl Fl password= Ns Ar password Oc Oo Fl r Oc Oo Fl Fl random Oc \ +Oo Fl s Oc Oo Fl Fl no-salt Oc Oo Fl H Oc Op Fl Fl hex +Adds a key to the keytab. Options that are not specified will be +prompted for. This requires that you know the password or the hex key of the +principal to add; if what you really want is to add a new principal to +the keytab, you should consider the +.Ar get +command, which talks to the kadmin server. +.It Nm change Oo Fl r Ar realm Oc Oo Fl Fl realm= Ns Ar realm Oc \ +Oo Fl Fl keepold | Fl Fl keepallold | Fl Fl pruneall Oc \ +Oo Fl Fl enctype= Ns Ar enctype Oc \ +Oo Fl Fl a Ar host Oc Oo Fl Fl admin-server= Ns Ar host Oc \ +Oo Fl Fl s Ar port Oc Op Fl Fl server-port= Ns Ar port +Update one or several keys to new versions. By default, use the admin +server for the realm of a keytab entry. Otherwise it will use the +values specified by the options. +.Pp +If no principals are given, all the ones in the keytab are updated. +.It Nm copy Oo Fl Fl copy-duplicates Oc Ar keytab-src Ar keytab-dest +Copies all the entries from +.Ar keytab-src +to +.Ar keytab-dest . +Because entries already in +.Ar keytab-dest +are kept, this command functions to merge keytabs. +Entries for the same principal, key version number, and +encryption type in the +.Ar keytab-src +that are also in the +.Ar keytab-dest +will not be copied to the +.Ar keytab-dest +unless the +.Fl Fl copy-duplicates +option is given. +.It Nm get Oo Fl p Ar admin principal Oc \ +Oo Fl Fl principal= Ns Ar admin principal Oc Oo Fl e Ar enctype Oc \ +Oo Fl Fl no-create Oc \ +Oo Fl Fl no-change-keys Oc \ +Oo Fl Fl keepold | Fl Fl keepallold | Fl Fl pruneall Oc \ +Oo Fl Fl enctypes= Ns Ar enctype Oc Oo Fl r Ar realm Oc \ +Oo Fl Fl realm= Ns Ar realm Oc Oo Fl a Ar admin server Oc \ +Oo Fl Fl admin-server= Ns Ar admin server Oc Oo Fl s Ar server port Oc \ +Oo Fl Fl server-port= Ns Ar server port Oc Ar principal ... +.Pp +For each +.Ar principal , +get a the principal's keys from the KDC via the kadmin protocol, +creating the principal if it doesn't exist (unless +.Fl Fl no-create +is given), and changing its keys to new random keys (unless +.Fl Fl no-change-keys +is given). +.Pp +If no +.Ar realm +is specified, the realm to operate on is taken from the first +principal. +.It Nm import Oo JSON-FILE Oc +Read an array of keytab entries in a JSON file and copy them to +the keytab. +Use the +.Nm list +command with its +.Fl Fl json +option +and +.Fl Fl keys +option to export a keytab. +.It Nm list Oo Fl Fl keys Oc Op Fl Fl timestamp Oo Op Fl Fl json Oc +List the keys stored in the keytab. +Use the +.Fl Fl json +and +.Fl Fl keys +options to export a keytab as JSON for importing with the +.Nm import +command. +.It Nm remove Oo Fl p Ar principal Oc Oo Fl Fl principal= Ns Ar principal Oc \ +Oo Fl V kvno Oc Oo Fl Fl kvno= Ns Ar kvno Oc Oo Fl e enctype Oc \ +Oo Fl Fl enctype= Ns Ar enctype Oc +Removes the specified key or keys. Not specifying a +.Ar kvno +removes keys with any version number. Not specifying an +.Ar enctype +removes keys of any type. +.It Nm merge Oo Fl Fl copy-duplicates Oc Ar keytab-src Ar keytab-dest +An alias for the +.Nm copy +command. +.It Nm rename Ar from-principal Ar to-principal +Renames all entries for the +.Ar from-principal +in the keytab +.Ar from-principal +to +.Ar to-principal . +.It Nm purge Op Fl Fl age= Ns Ar age +Removes all old versions of a key for which there is a newer version +that is at least +.Ar age +(default one week) old. +Note that this does not update the KDC database. +The +.Xr kadmin 1 +command has a +.Nm prune +command that can do this on the KDC side. +.El +.Sh ENVIRONMENT +.Bl -tag -width Ds +.It Ev KRB5_KTNAME +Specifies the default keytab. +.It Ev KRB5_CONFIG +The file name of +.Pa krb5.conf , +the default being +.Pa /etc/krb5.conf . +.El +.Sh KEYTAB NAMING +The syntax for the value of the +.Ql KRB5_KTNAME +environment variable and +.Oo Fl k Ar keytab \*(Ba Xo +.Fl Fl keytab= Ns Ar keytab +.Xc +.Oc +options is +.Ql TYPE:name +where the TYPE is one of +.Ql FILE , +.Ql HDBGET , +.Ql HDB , +or +.Ql ANY , +and the name syntax is specific to the keytab type. +.Pp +For the FILE keytab type the name is the path to a file whose +format is the well-known keytab file format used by MIT Kerberos, +Heimdal, Java, and others. +.Pp +For the HDB and HDBGET keytab types the name syntax is +.Ql [][:mkey=] +where the first path is the path to the HDB and the second path +is the path to the master key file. +Note that to use the HDB and HDBGET keytab types in a program +linked with Heimdal libraries one first load the +.Ql libhdb +library and then register their keytab methods using +.Xr krb5_kt_register 3 . +Note also that +.Nm ktutil +does not load and register the HDB and HDBGET keytab types at +this time. +.Pp +The ANY keytab type name syntax is a sequence of other keytab +names (including their TYPE: prefix) separated by commas. +Note that there is no escape sequence for commas in keytab names. +.Sh SEE ALSO +.Xr kadmin 1 +.Xr kinit 1 +.Xr krb5_kt_register 3 diff --git a/admin/ktutil.8 b/admin/ktutil.8 deleted file mode 100644 index d319ce538..000000000 --- a/admin/ktutil.8 +++ /dev/null @@ -1,196 +0,0 @@ -.\" Copyright (c) 1997-2004 Kungliga Tekniska Högskolan -.\" (Royal Institute of Technology, Stockholm, Sweden). -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" 3. Neither the name of the Institute nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" $Id$ -.\" -.Dd April 14, 2005 -.Dt KTUTIL 8 -.Os HEIMDAL -.Sh NAME -.Nm ktutil -.Nd manage Kerberos keytabs -.Sh SYNOPSIS -.Nm -.Oo Fl k Ar keytab \*(Ba Xo -.Fl -keytab= Ns Ar keytab -.Xc -.Oc -.Op Fl v | Fl -verbose -.Op Fl -version -.Op Fl h | Fl -help -.Ar command -.Op Ar args -.Sh DESCRIPTION -.Nm -is a program for managing keytabs. -Supported options: -.Bl -tag -width Ds -.It Xo -.Fl v , -.Fl -verbose -.Xc -Verbose output. -.El -.Pp -.Ar command -can be one of the following: -.Bl -tag -width srvconvert -.It add Xo -.Op Fl p Ar principal -.Op Fl -principal= Ns Ar principal -.Op Fl V Ar kvno -.Op Fl -kvno= Ns Ar kvno -.Op Fl e Ar enctype -.Op Fl -enctype= Ns Ar enctype -.Op Fl w Ar password -.Op Fl -password= Ns Ar password -.Op Fl r -.Op Fl -random -.Op Fl s -.Op Fl -no-salt -.Op Fl H -.Op Fl -hex -.Xc -Adds a key to the keytab. Options that are not specified will be -prompted for. This requires that you know the password or the hex key of the -principal to add; if what you really want is to add a new principal to -the keytab, you should consider the -.Ar get -command, which talks to the kadmin server. -.It change Xo -.Op Fl r Ar realm -.Op Fl -realm= Ns Ar realm -.Op Fl -a Ar host -.Op Fl -admin-server= Ns Ar host -.Op Fl -s Ar port -.Op Fl -server-port= Ns Ar port -.Xc -Update one or several keys to new versions. By default, use the admin -server for the realm of a keytab entry. Otherwise it will use the -values specified by the options. -.Pp -If no principals are given, all the ones in the keytab are updated. -.It copy Xo -.Ar keytab-src -.Ar keytab-dest -.Xc -Copies all the entries from -.Ar keytab-src -to -.Ar keytab-dest . -.It get Xo -.Op Fl p Ar admin principal -.Op Fl -principal= Ns Ar admin principal -.Op Fl e Ar enctype -.Op Fl -enctypes= Ns Ar enctype -.Op Fl r Ar realm -.Op Fl -realm= Ns Ar realm -.Op Fl a Ar admin server -.Op Fl -admin-server= Ns Ar admin server -.Op Fl s Ar server port -.Op Fl -server-port= Ns Ar server port -.Ar principal ... -.Xc -For each -.Ar principal , -generate a new key for it (creating it if it doesn't already exist), -and put that key in the keytab. -.Pp -If no -.Ar realm -is specified, the realm to operate on is taken from the first -principal. -.It list Xo -.Op Fl -keys -.Op Fl -timestamp -.Xc -List the keys stored in the keytab. -.It remove Xo -.Op Fl p Ar principal -.Op Fl -principal= Ns Ar principal -.Op Fl V kvno -.Op Fl -kvno= Ns Ar kvno -.Op Fl e enctype -.Op Fl -enctype= Ns Ar enctype -.Xc -Removes the specified key or keys. Not specifying a -.Ar kvno -removes keys with any version number. Not specifying an -.Ar enctype -removes keys of any type. -.It rename Xo -.Ar from-principal -.Ar to-principal -.Xc -Renames all entries in the keytab that match the -.Ar from-principal -to -.Ar to-principal . -.It purge Xo -.Op Fl -age= Ns Ar age -.Xc -Removes all old versions of a key for which there is a newer version -that is at least -.Ar age -(default one week) old. -.It srvconvert -.It srv2keytab Xo -.Op Fl s Ar srvtab -.Op Fl -srvtab= Ns Ar srvtab -.Xc -Converts the version 4 srvtab in -.Ar srvtab -to a version 5 keytab and stores it in -.Ar keytab . -Identical to: -.Bd -ragged -offset indent -.Li ktutil copy -.Li krb4: Ns Ar srvtab -.Ar keytab -.Ed -.It srvcreate -.It key2srvtab Xo -.Op Fl s Ar srvtab -.Op Fl -srvtab= Ns Ar srvtab -.Xc -Converts the version 5 keytab in -.Ar keytab -to a version 4 srvtab and stores it in -.Ar srvtab . -Identical to: -.Bd -ragged -offset indent -.Li ktutil copy -.Ar keytab -.Li krb4: Ns Ar srvtab -.Ed -.El -.Sh SEE ALSO -.Xr kadmin 8 diff --git a/admin/ktutil.c b/admin/ktutil.c index 756c595f5..27d0d5870 100644 --- a/admin/ktutil.c +++ b/admin/ktutil.c @@ -52,7 +52,7 @@ static struct getargs args[] = { NULL }, { - "help", + "help", 'h', arg_flag, &help_flag, @@ -60,7 +60,7 @@ static struct getargs args[] = { NULL }, { - "keytab", + "keytab", 'k', arg_string, &keytab_string, @@ -101,7 +101,7 @@ ktutil_open_keytab(void) } if (verbose_flag) fprintf (stderr, "Using keytab %s\n", keytab_string); - + return keytab; } @@ -118,8 +118,11 @@ help(void *opt, int argc, char **argv) argv[0]); } else { if(c->func) { - char *fake[] = { NULL, "--help", NULL }; + char shelp[] = "--help"; + char *fake[3]; fake[0] = argv[0]; + fake[1] = shelp; + fake[2] = NULL; (*c->func)(2, fake); fprintf(stderr, "\n"); } diff --git a/admin/list.c b/admin/list.c index 1dec14627..22ccdcac8 100644 --- a/admin/list.c +++ b/admin/list.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2004 Kungliga Tekniska Högskolan + * Copyright (c) 1997-2022 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -32,6 +32,7 @@ */ #include "ktutil_locl.h" +#include #include RCSID("$Id$"); @@ -76,7 +77,7 @@ do_list(struct list_options *opt, const char *keytab_str) } printf ("%s:\n\n", keytab_str); - + table = rtbl_create(); rtbl_add_column_by_id(table, 0, "Vno", RTBL_ALIGN_RIGHT); rtbl_add_column_by_id(table, 1, "Type", 0); @@ -113,7 +114,7 @@ do_list(struct list_options *opt, const char *keytab_str) rtbl_add_column_entry_by_id(table, 3, buf); } if(opt->keys_flag) { - int i; + size_t i; s = malloc(2 * entry.keyblock.keyvalue.length + 1); if (s == NULL) { krb5_warnx(context, "malloc failed"); @@ -129,14 +130,16 @@ do_list(struct list_options *opt, const char *keytab_str) if (entry.aliases) { unsigned int i; struct rk_strpool *p = NULL; - + for (i = 0; i< entry.aliases->len; i++) { - krb5_unparse_name_fixed(context, entry.principal, buf, sizeof(buf)); - rk_strpoolprintf(p, "%s%s", buf, - i + 1 < entry.aliases->len ? ", " : ""); - + krb5_unparse_name_fixed(context, &entry.aliases->val[i], + buf, sizeof(buf)); + p = rk_strpoolprintf(p, "%s%s", buf, + i + 1 < entry.aliases->len ? ", " : ""); + } - rtbl_add_column_entry_by_id(table, 5, rk_strpoolcollect(p)); + rtbl_add_column_entry_by_id(table, 5, (s = rk_strpoolcollect(p))); + free(s); } krb5_kt_free_entry(context, &entry); @@ -151,6 +154,136 @@ out: return ret; } +static int +do_list1_json(struct list_options *opt, + const char *keytab_str, + heim_array_t a) +{ + krb5_error_code ret; + krb5_keytab keytab; + krb5_keytab_entry entry; + krb5_kt_cursor cursor; + + ret = krb5_kt_resolve(context, keytab_str, &keytab); + if (ret) { + krb5_warn(context, ret, "resolving keytab %s", keytab_str); + return ret; + } + + ret = krb5_kt_start_seq_get(context, keytab, &cursor); + if(ret) { + krb5_warn(context, ret, "krb5_kt_start_seq_get %s", keytab_str); + krb5_kt_close(context, keytab); + return ret; + } + + //if (opt->timestamp_flag) + //if (opt->keys_flag) + + while (krb5_kt_next_entry(context, keytab, &entry, &cursor) == 0) { + heim_dict_t d = heim_dict_create(5); + heim_object_t o; + char *s; + + heim_array_append_value(a, d); + heim_dict_set_value(d, HSTR("keytab"), + o = heim_string_create(keytab_str)); heim_release(o); + heim_dict_set_value(d, HSTR("kvno"), o = heim_number_create(entry.vno)); + heim_release(o); + heim_dict_set_value(d, HSTR("enctype_number"), + o = heim_number_create(entry.keyblock.keytype)); + heim_release(o); + heim_dict_set_value(d, HSTR("flags"), + o = heim_number_create(entry.flags)); + heim_release(o); + ret = krb5_enctype_to_string(context, entry.keyblock.keytype, &s); + if (ret == 0) { + heim_dict_set_value(d, HSTR("enctype"), o = heim_string_create(s)); + heim_release(o); + free(s); + } + heim_dict_set_value(d, HSTR("timestamp"), + o = heim_number_create(entry.timestamp)); + heim_release(o); + + ret = krb5_unparse_name(context, entry.principal, &s); + if (ret) + krb5_err(context, 1, ret, "Could not format principal"); + heim_dict_set_value(d, HSTR("principal"), o = heim_string_create(s)); + heim_release(o); + free(s); + + if (opt->keys_flag) { + o = heim_data_create(entry.keyblock.keyvalue.data, + entry.keyblock.keyvalue.length); + heim_dict_set_value(d, HSTR("key"), o); + heim_release(o); + } + if (entry.aliases) { + heim_array_t aliases = heim_array_create(); + unsigned int i; + + for (i = 0; i< entry.aliases->len; i++) { + ret = krb5_unparse_name(context, &entry.aliases->val[i], &s); + if (ret) + krb5_err(context, 1, ret, "Could not format principal"); + heim_array_append_value(aliases, o = heim_string_create(s)); + heim_release(o); + free(s); + } + heim_dict_set_value(d, HSTR("aliases"), aliases); + heim_release(aliases); + } + + krb5_kt_free_entry(context, &entry); + heim_release(d); + } + + ret = krb5_kt_end_seq_get(context, keytab, &cursor); + krb5_kt_close(context, keytab); + return ret; +} + +static int +do_list_json(struct list_options *opt, const char *keytab_str) +{ + krb5_error_code ret = 0; + heim_json_flags_t flags = + (HEIM_JSON_F_STRICT | HEIM_JSON_F_INDENT2 | HEIM_JSON_F_NO_DATA_DICT) & + ~HEIM_JSON_F_NO_DATA; + heim_array_t a = heim_array_create(); + heim_string_t s; + + /* + * Special-case the ANY: keytab type. What do we get from this? We get to + * include the actual keytab name for each entry in its JSON + * representation. Otherwise there would be no point because the ANY: + * keytab type iterates all the keytabs it joins. + * + * Why strncasecmp() though? Because do_list() uses it, though it arguably + * never should have. + */ + if (strncasecmp(keytab_str, "ANY:", 4) == 0) { + char buf[1024]; + + keytab_str += 4; + ret = 0; + while (strsep_copy((const char**)&keytab_str, ",", + buf, sizeof(buf)) != -1) { + if (do_list1_json(opt, buf, a)) + ret = 1; + } + } else { + ret = do_list1_json(opt, keytab_str, a); + } + + s = heim_json_copy_serialize(a, flags, NULL); + printf("%s", heim_string_get_utf8(s)); + heim_release(a); + heim_release(s); + return ret; +} + int kt_list(struct list_options *opt, int argc, char **argv) { @@ -167,5 +300,7 @@ kt_list(struct list_options *opt, int argc, char **argv) } keytab_string = kt; } + if (opt->json_flag) + return do_list_json(opt, keytab_string) != 0; return do_list(opt, keytab_string) != 0; } diff --git a/appl/Makefile.am b/appl/Makefile.am index 2409b9549..ec896ff2a 100644 --- a/appl/Makefile.am +++ b/appl/Makefile.am @@ -8,20 +8,16 @@ endif if DCE dir_dce = dceutils endif +if !NO_AFS +dir_afsutil = afsutil +endif SUBDIRS = \ - afsutil \ - ftp \ - login \ + $(dir_afsutil) \ + dbutils \ $(dir_otp) \ gssmask \ - popper \ - push \ - rsh \ - rcp \ - su \ - xnlock \ - telnet \ test \ - kx \ kf \ $(dir_dce) + +EXTRA_DIST = NTMakefile diff --git a/appl/NTMakefile b/appl/NTMakefile new file mode 100644 index 000000000..6bae479d0 --- /dev/null +++ b/appl/NTMakefile @@ -0,0 +1,35 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=appl + +!include ../windows/NTMakefile.w32 + diff --git a/appl/afsutil/Makefile.am b/appl/afsutil/Makefile.am index 6650ed47d..705bdf1c8 100644 --- a/appl/afsutil/Makefile.am +++ b/appl/afsutil/Makefile.am @@ -2,8 +2,6 @@ include $(top_srcdir)/Makefile.am.common -AM_CPPFLAGS += $(INCLUDE_krb4) - bin_PROGRAMS = afslog pagsh afslog_SOURCES = afslog.c @@ -13,10 +11,9 @@ pagsh_SOURCES = pagsh.c man_MANS = afslog.1 pagsh.1 LDADD = $(LIB_kafs) \ - $(LIB_krb4) \ $(top_builddir)/lib/krb5/libkrb5.la \ $(top_builddir)/lib/asn1/libasn1.la \ $(LIB_hcrypto) \ $(LIB_roken) -EXTRA_DIST = $(man_MANS) +EXTRA_DIST = NTMakefile $(man_MANS) diff --git a/appl/afsutil/NTMakefile b/appl/afsutil/NTMakefile new file mode 100644 index 000000000..f1f696c02 --- /dev/null +++ b/appl/afsutil/NTMakefile @@ -0,0 +1,35 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=appl\afsutil + +!include ../../windows/NTMakefile.w32 + diff --git a/appl/afsutil/afslog.1 b/appl/afsutil/afslog.1 index 707798cf9..779d9cd50 100644 --- a/appl/afsutil/afslog.1 +++ b/appl/afsutil/afslog.1 @@ -1,34 +1,34 @@ .\" Copyright (c) 2002 - 2007 Kungliga Tekniska Högskolan -.\" (Royal Institute of Technology, Stockholm, Sweden). -.\" All rights reserved. +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. .\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: .\" -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. .\" -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. .\" -.\" 3. Neither the name of the Institute nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. .\" -.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" .\" $Id$ .\" .Dd November 26, 2002 @@ -36,31 +36,29 @@ .Os HEIMDAL .Sh NAME .Nm afslog -.Nd -obtain AFS tokens +.Nd obtain AFS tokens .Sh SYNOPSIS .Nm -.Op Fl h | Fl -help -.Op Fl -no-v4 -.Op Fl -no-v5 -.Op Fl u | Fl -unlog -.Op Fl v | Fl -verbose -.Op Fl -version +.Op Fl h | Fl Fl help +.Op Fl Fl no-v5 +.Op Fl u | Fl Fl unlog +.Op Fl v | Fl Fl verbose +.Op Fl Fl version .Oo Fl c Ar cell \*(Ba Xo -.Fl -cell= Ns Ar cell +.Fl Fl cell= Ns Ar cell .Xc .Oc .Oo Fl k Ar realm \*(Ba Xo -.Fl -realm= Ns Ar realm +.Fl Fl realm= Ns Ar realm .Xc .Oc .Oo Fl P Ar principal \*(Ba Xo -.Fl -principal= Ns Ar principal +.Fl Fl principal= Ns Ar principal .Xc .Oc .Bk -words .Oo Fl p Ar path \*(Ba Xo -.Fl -file= Ns Ar path +.Fl Fl file= Ns Ar path .Xc .Oc .Ek @@ -71,57 +69,53 @@ obtains AFS tokens for a number of cells. What cells to get tokens for can either be specified as an explicit list, as file paths to get tokens for, or be left unspecified, in which case .Nm -will use whatever magic +will use whatever magic .Xr krb_afslog 3 decides upon. .Pp Supported options: .Bl -tag -width Ds -.It Fl -no-v4 -This makes -.Nm -not try using Kerberos 4. -.It Fl -no-v5 +.It Fl Fl no-v5 This makes .Nm not try using Kerberos 5. .It Xo .Fl P Ar principal , -.Fl -principal Ar principal +.Fl Fl principal Ar principal .Xc select what Kerberos 5 principal to use. -.It Fl -cache Ar cache +.It Fl Fl cache Ar cache select what Kerberos 5 credential cache to use. -.Fl -principal +.Fl Fl principal overrides this option. .It Xo .Fl u , -.Fl -unlog +.Fl Fl unlog .Xc Destroy tokens instead of obtaining new. If this is specified, all other options are ignored (except for -.Fl -help +.Fl Fl help and -.Fl -version ) . +.Fl Fl version ) . .It Xo .Fl v , -.Fl -verbose +.Fl Fl verbose .Xc Adds more verbosity for what is actually going on. .It Xo .Fl c Ar cell, -.Fl -cell= Ns Ar cell +.Fl Fl cell= Ns Ar cell .Xc This specified one or more cell names to get tokens for. .It Xo .Fl k Ar realm , -.Fl -realm= Ns Ar realm +.Fl Fl realm= Ns Ar realm .Xc This is the Kerberos realm the AFS servers live in, this should normally not be specified. .It Xo .Fl p Ar path , -.Fl -file= Ns Ar path +.Fl Fl file= Ns Ar path .Xc This specified one or more file paths for which tokens should be obtained. @@ -132,22 +126,22 @@ Instead of using and .Fl p , you may also pass a list of cells and file paths after any other -options. These arguments are considered files if they are either +options. These arguments are considered files if they are either the strings .Do . Dc or -.Dq .. +.Dq .. or they contain a slash, or if there exists a file by that name. .Sh EXAMPLES -Assuming that there is no file called +Assuming that there is no file called .Dq openafs.org -in the current directory, and that +in the current directory, and that .Pa /afs/openafs.org points to that cell, the follwing should be identical: .Bd -literal -offset indent $ afslog -c openafs.org $ afslog openafs.org $ afslog /afs/openafs.org/some/file -.Ed +.Ed .Sh SEE ALSO .Xr krb_afslog 3 diff --git a/appl/afsutil/afslog.c b/appl/afsutil/afslog.c index fe24a5371..05078ee8e 100644 --- a/appl/afsutil/afslog.c +++ b/appl/afsutil/afslog.c @@ -61,15 +61,16 @@ struct getargs args[] = { { "cell", 'c', arg_strings, &cells, "cells to get tokens for", "cell" }, { "file", 'p', arg_strings, &files, "files to get tokens for", "path" }, { "realm", 'k', arg_string, &realm, "realm for afs cell", "realm" }, - { "unlog", 'u', arg_flag, &unlog_flag, "remove tokens" }, + { "unlog", 'u', arg_flag, &unlog_flag, "remove tokens", NULL }, #ifdef KRB5 { "principal",'P',arg_string,&client_string,"principal to use","principal"}, { "cache", 0, arg_string, &cache_string, "ccache to use", "cache"}, - { "v5", 0, arg_negative_flag, &use_krb5, "don't use Kerberos 5" }, + { "v5", 0, arg_negative_flag, &use_krb5, "don't use Kerberos 5", + NULL }, #endif - { "verbose",'v', arg_flag, &verbose }, - { "version", 0, arg_flag, &version_flag }, - { "help", 'h', arg_flag, &help_flag }, + { "verbose",'v', arg_flag, &verbose, NULL, NULL }, + { "version", 0, arg_flag, &version_flag, NULL, NULL }, + { "help", 'h', arg_flag, &help_flag, NULL, NULL }, }; static int num_args = sizeof(args) / sizeof(args[0]); @@ -103,12 +104,12 @@ expand_cell_name(const char *cell) { FILE *f; const char *c; - const char **fn, *files[] = { _PATH_CELLSERVDB, - _PATH_ARLA_CELLSERVDB, - _PATH_OPENAFS_DEBIAN_CELLSERVDB, - _PATH_ARLA_DEBIAN_CELLSERVDB, - NULL }; - for(fn = files; *fn; fn++) { + const char **fn, *fns[] = { _PATH_CELLSERVDB, + _PATH_ARLA_CELLSERVDB, + _PATH_OPENAFS_DEBIAN_CELLSERVDB, + _PATH_ARLA_DEBIAN_CELLSERVDB, + NULL }; + for(fn = fns; *fn; fn++) { f = fopen(*fn, "r"); if(f == NULL) continue; @@ -117,7 +118,7 @@ expand_cell_name(const char *cell) if(c) return c; } - return cell; + return NULL; } static void @@ -180,9 +181,9 @@ afslog_file(const char *path) static int do_afslog(const char *cell) { - int k5ret, k4ret; + int k5ret; - k5ret = k4ret = 0; + k5ret = 0; #ifdef KRB5 if(context != NULL && id != NULL && use_krb5) { @@ -195,9 +196,9 @@ do_afslog(const char *cell) cell = ""; #ifdef KRB5 if (k5ret) - warnx("krb5_afslog(%s): %s", cell, krb5_get_err_text(context, k5ret)); + krb5_warn(context, k5ret, "krb5_afslog(%s)", cell); #endif - if (k5ret || k4ret) + if (k5ret) return 1; return 0; } @@ -211,7 +212,7 @@ log_func(void *ctx, const char *str) int main(int argc, char **argv) { - int optind = 0; + int optidx = 0; int i; int num; int ret = 0; @@ -220,7 +221,7 @@ main(int argc, char **argv) setprogname(argv[0]); - if(getarg(args, num_args, argc, argv, &optind)) + if(getarg(args, num_args, argc, argv, &optidx)) usage(1); if(help_flag) usage(0); @@ -277,7 +278,7 @@ main(int argc, char **argv) num++; } free_getarg_strings (&cells); - for(i = optind; i < argc; i++){ + for(i = optidx; i < argc; i++){ num++; if(strcmp(argv[i], ".") == 0 || strcmp(argv[i], "..") == 0 || diff --git a/appl/afsutil/pagsh.1 b/appl/afsutil/pagsh.1 index 27eb54241..3c1fd9643 100644 --- a/appl/afsutil/pagsh.1 +++ b/appl/afsutil/pagsh.1 @@ -1,79 +1,80 @@ .\" Copyright (c) 2005 Kungliga Tekniska Högskolan -.\" (Royal Institute of Technology, Stockholm, Sweden). -.\" All rights reserved. +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. .\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: .\" -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. .\" -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. .\" -.\" 3. Neither the name of the Institute nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. .\" -.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" .\" $Id$ .\" .Dd February 12, 2005 .Dt PAGSH 1 -.Os Heimdal +.Os .Sh NAME .Nm pagsh -.Nd -creates a new credential cache sandbox +.Nd creates a new credential cache sandbox .Sh SYNOPSIS .Nm -.Op Fl c -.Op Fl h | Fl -help -.Op Fl -version -.Op Fl -cache-type= Ns Ar string +.Op Fl c Ar command-string +.Op Fl h | Fl Fl help +.Op Fl Fl version +.Op Fl Fl cache-type= Ns Ar string .Ar command [args...] .Sh DESCRIPTION Supported options: .Bl -tag -width Ds .It Xo -.Fl c +.Fl c Ar command-string +Executes command(s) contained in +.Ar command-string . .Xc .It Xo -.Fl -cache-type= Ns Ar string +.Fl Fl cache-type= Ns Ar string .Xc .It Xo .Fl h , -.Fl -help +.Fl Fl help .Xc .It Xo -.Fl -version +.Fl Fl version .Xc .El .Pp .Nm creates a new credential cache sandbox for the user to live in. If AFS is installed on the computer, the user is put in a newly -created PAG. +created Process Authentication Group (PAG). .Pp For Kerberos 5, the credential cache type that is used is the same as the credential cache type that was used at the time of .Nm invocation. The credential cache type can be controlled by the option -.Fl -cache-type . +.Fl Fl cache-type . .Sh EXAMPLES Create a new sandbox where new credentials can be used, while the old credentials can be used by other processes. @@ -89,4 +90,5 @@ $ klist klist: No ticket file: /tmp/krb5cc_03014a .Ed .Sh SEE ALSO -.Xr afslog 1 +.Xr afslog 1 , +.Xr kinit 1 diff --git a/appl/afsutil/pagsh.c b/appl/afsutil/pagsh.c index 9794b37c6..377ac6174 100644 --- a/appl/afsutil/pagsh.c +++ b/appl/afsutil/pagsh.c @@ -73,12 +73,12 @@ static char *typename_arg; #endif struct getargs getargs[] = { - { NULL, 'c', arg_flag, &c_flag }, + { NULL, 'c', arg_flag, &c_flag, NULL, NULL }, #ifdef KRB5 - { "cache-type", 0, arg_string, &typename_arg }, + { "cache-type", 0, arg_string, &typename_arg, NULL, NULL }, #endif - { "version", 0, arg_flag, &version_flag }, - { "help", 'h', arg_flag, &help_flag }, + { "version", 0, arg_flag, &version_flag, NULL, NULL }, + { "help", 'h', arg_flag, &help_flag, NULL, NULL }, }; static int num_args = sizeof(getargs) / sizeof(getargs[0]); @@ -99,15 +99,16 @@ main(int argc, char **argv) { int f; char tf[1024]; + char shellbuf[MAX_PATH]; char *p; char *path; char **args; unsigned int i; - int optind = 0; + int optidx = 0; setprogname(argv[0]); - if(getarg(getargs, num_args, argc, argv, &optind)) + if(getarg(getargs, num_args, argc, argv, &optidx)) usage(1); if(help_flag) usage(0); @@ -116,8 +117,8 @@ main(int argc, char **argv) exit(0); } - argc -= optind; - argv += optind; + argc -= optidx; + argv += optidx; #ifdef KRB5 { @@ -138,7 +139,7 @@ main(int argc, char **argv) if (name == NULL) krb5_errx(context, 1, "Generated credential cache have no name"); - snprintf(tf, sizeof(tf), "%s:%s", typename_arg, name); + snprintf(tf, sizeof(tf), "%s:%s", krb5_cc_get_type(context, id), name); ret = krb5_cc_close(context, id); if (ret) @@ -166,13 +167,10 @@ main(int argc, char **argv) (unsigned long)((argc + 10)*sizeof(char *))); if(*argv == NULL) { - path = getenv("SHELL"); - if(path == NULL){ - struct passwd *pw = k_getpwuid(geteuid()); - if (pw == NULL) - errx(1, "no such user: %d", (int)geteuid()); - path = strdup(pw->pw_shell); - } + if (roken_get_shell(shellbuf, sizeof(shellbuf)) != NULL) + path = strdup(shellbuf); + else + path = strdup("/bin/sh"); } else { path = strdup(*argv++); } diff --git a/appl/dbutils/Makefile.am b/appl/dbutils/Makefile.am new file mode 100644 index 000000000..a1fc3842a --- /dev/null +++ b/appl/dbutils/Makefile.am @@ -0,0 +1,13 @@ +# $Id$ + +include $(top_srcdir)/Makefile.am.common + +bin_PROGRAMS = bsearch + +bsearch_SOURCES = bsearch.c + +man_MANS = bsearch.1 + +EXTRA_DIST = NTMakefile $(man_MANS) + +LDADD = $(LIB_roken) $(LIB_vers) $(LIB_heimbase) diff --git a/appl/dbutils/NTMakefile b/appl/dbutils/NTMakefile new file mode 100644 index 000000000..73ea8168d --- /dev/null +++ b/appl/dbutils/NTMakefile @@ -0,0 +1,35 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=appl\dbutils + +!include ../../windows/NTMakefile.w32 + diff --git a/appl/dbutils/bsearch.1 b/appl/dbutils/bsearch.1 new file mode 100644 index 000000000..0ea919c95 --- /dev/null +++ b/appl/dbutils/bsearch.1 @@ -0,0 +1,115 @@ +.\" +.\" Copyright (c) 2011, Secure Endpoints Inc. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" - Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" - Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +.\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +.\" COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +.\" OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd November 30, 2011 +.Dt BSEARCH 1 +.Os KTH-KRB +.Sh NAME +.Nm bsearch +.Nd manages one-time passwords +.Sh SYNOPSIS +.Nm bsearch +.Op Fl KVvh +.Op Fl b Ar block-size +.Op Fl m Ar max-cache-size +.Ar file +.Ar [key ...] +.Sh DESCRIPTION +The +.Nm +program performs binary searches of +.Ar file +which must be a sorted flat text file. +.Pp +Each line is a record. Each record starts with a key +that is optionally followed by whitespace and a value. +Whitespace may be quoted with a backslash, but newline +and carriage-return characters must be quoted in some +other manner (e.g., as backslash-n and backslash-r). +Escapes are not interpreted nor removed. +.Pp +If no key arguments are given on the comman-line, then +keys will be read from standard input. +.Pp +By default only values are printed to standard output. +Use the -K option to also print keys. The exit status +will be non-zero if any key lookups fail. +.Pp +Options are: +.Bl -tag -width Ds +.It Fl K +Print keys. +.It Fl V +Don't print values. +.It Fl h +Print usage and exit. +.It Fl v +Print statistic and debug information to standard +error. +.Ar file +A sorted flat text file. NOTE: use the "C" locale for +sorting this file, as in "LC_ALL=C sort -u -o file +file". +.It Fl h +For getting a help message. +.It Fl m +Set +.Ar max-cache-size +as the maximum cache size. If the +.Ar file +is smaller than this size then the whole file will be +read into memory, else the program will read blocks. +Defaults to 1MB. +.It Fl b +Set +.Ar block-size +as the block size for block-wise I/O. This must be a +power of 2, must be no smaller than 512 and no larger +than 1MB. Defaults to the +.Ar file's +filesystem's preferred blocksize. +.El +.Sh EXAMPLES +.Bd -literal -offset indent +$ env LC_ALL=C sort -o /tmp/words /usr/share/dict/words +$ bsearch -Kv /tmp/words day +Using whole-file method +Key day found at offset 327695 in 12 loops and 0 reads +day +$ +.Ed +.Sh NOTES +.Pp +Records must not be longer than one block's size. +.Pp +Flat text files must be sorted in the "C" locale. In +some systems the default locale may result in +case-insensitive sorting by the sort command. +.Sh SEE ALSO +.Xr sort 1 diff --git a/appl/dbutils/bsearch.c b/appl/dbutils/bsearch.c new file mode 100644 index 000000000..da37251d3 --- /dev/null +++ b/appl/dbutils/bsearch.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2011, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int help_flag; +int version_flag; +int verbose_flag; +int print_keys_flag; +int no_values_flag; +int block_size_int; +int max_size_int; + +struct getargs args[] = { + { "print-keys", 'K', arg_flag, &print_keys_flag, + "print keys", NULL }, + { "no-values", 'V', arg_flag, &no_values_flag, + "don't print values", NULL }, + { "verbose", 'v', arg_flag, &verbose_flag, + "print statistics and informative messages", NULL }, + { "help", 'h', arg_flag, &help_flag, + "print usage message", NULL }, + { "block-size", 'b', arg_integer, &block_size_int, + "block size", "integer" }, + { "max-cache-size", 'm', arg_integer, &max_size_int, + "maximum cache size", "integer" }, + { "version", '\0', arg_flag, &version_flag, NULL, NULL } +}; + +static int num_args = sizeof(args) / sizeof(args[0]); + +static void +usage(int status) +{ + arg_printusage(args, num_args, NULL, "file [key ...]"); + exit(status); +} + +#define MAX_BLOCK_SIZE (1024 * 1024) +#define DEFAULT_MAX_FILE_SIZE (1024 * 1024) + +int +main(int argc, char **argv) +{ + char keybuf[1024]; + char *fname; + char *key = keybuf; + char *value; + char *p; + bsearch_file_handle bfh = NULL; + size_t num; + size_t loc; /* index where record is located or to be inserted */ + size_t loops; /* number of loops/comparisons needed for lookup */ + size_t reads = 0; /* number of reads needed for a lookup */ + size_t failures = 0; /* number of lookup failures -- for exit status */ + size_t block_size = 0; + size_t max_size = 0; + int optidx = 0; + int blockwise; + int ret = 0; + + setprogname(argv[0]); + if (getarg(args, num_args, argc, argv, &optidx)) + usage(1); + + if (version_flag) { + print_version(NULL); + return 0; + } + + if (help_flag) + usage(0); + + if (block_size_int != 0 && block_size_int < 512) { + fprintf(stderr, "Invalid block size: too small\n"); + return 1; + } + if (block_size_int > 0) { + /* Check that block_size is a power of 2 */ + num = block_size_int; + while (num) { + if ((num % 2) && (num >> 1)) { + fprintf(stderr, "Invalid block size: must be power " + "of two\n"); + return 1; + } + num >>= 1; + } + if (block_size_int > MAX_BLOCK_SIZE) + fprintf(stderr, "Invalid block size: too large\n"); + block_size = block_size_int; + } + if (max_size_int < 0) + usage(1); + max_size = max_size_int; + + argc -= optind; + argv += optind; + + if (argc == 0) + usage(1); + + fname = argv[0]; + argc--; + argv++; + + ret = _bsearch_file_open(fname, max_size, block_size, &bfh, &reads); + if (ret != 0) { + perror("bsearch_file_open"); + return 1; + } + + _bsearch_file_info(bfh, &block_size, &max_size, &blockwise); + if (verbose_flag && blockwise) { + fprintf(stderr, "Using block-wise method with block size %lu and " + "cache size %lu\n", + (long unsigned)block_size, (long unsigned)max_size); + } else if (verbose_flag) { + fprintf(stderr, "Using whole-file method\n"); + } + + for (;;) { + loops = 0; /* reset stats */ + /* Eww */ + if (argc) { + key = *(argv++); + if (!key) + break; + } else { + if (!fgets(keybuf, sizeof (keybuf), stdin)) + break; + p = strchr(key, '\n'); + if (!p) + break; + *p = '\0'; + if (!*key) + continue; + } + ret = _bsearch_file(bfh, key, &value, &loc, &loops, &reads); + if (ret != 0) { + if (ret > 0) { + fprintf(stderr, "Error: %s\n", strerror(ret)); + _bsearch_file_close(&bfh); + return 1; + } + if (verbose_flag) + fprintf(stderr, "Key %s not found in %lu loops and %lu reads; " + "insert at %lu\n", key, (long unsigned)loops, + (long unsigned)reads, (long unsigned)loc); + failures++; + continue; + } + if (verbose_flag) + fprintf(stderr, "Key %s found at offset %lu in %lu loops and " + "%lu reads\n", key, (long unsigned)loc, + (long unsigned)loops, (long unsigned)reads); + if (print_keys_flag && !no_values_flag && value) + printf("%s %s\n", key, value); + else if (print_keys_flag) + printf("%s\n", key); + else if (no_values_flag && value) + printf("%s\n", value); + free(value); + } + if (failures) + return 2; + _bsearch_file_close(&bfh); + return 0; +} diff --git a/appl/dceutils/Makefile.am b/appl/dceutils/Makefile.am index 0c3a3d3ce..6fa9d1a10 100644 --- a/appl/dceutils/Makefile.am +++ b/appl/dceutils/Makefile.am @@ -24,6 +24,7 @@ k5dcecon_SOURCES = k5dcecon.c k5dce.h dpagaix_SOURCES = dpagaix.c EXTRA_DIST = \ + NTMakefile \ dfspag.exp \ README.dcedfs \ README.original \ diff --git a/appl/dceutils/NTMakefile b/appl/dceutils/NTMakefile new file mode 100644 index 000000000..eb27eb4f6 --- /dev/null +++ b/appl/dceutils/NTMakefile @@ -0,0 +1,35 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=appl\dceutils + +!include ../../windows/NTMakefile.w32 + diff --git a/appl/dceutils/dfspag.exp b/appl/dceutils/dfspag.exp index ed39788d5..c30c98b48 100644 --- a/appl/dceutils/dfspag.exp +++ b/appl/dceutils/dfspag.exp @@ -1,3 +1,3 @@ #!/unix -* kernel extentions used to get the pag +* kernel extensions used to get the pag kafs_syscall syscall diff --git a/appl/dceutils/dpagaix.c b/appl/dceutils/dpagaix.c index 304a9a230..7694c5445 100644 --- a/appl/dceutils/dpagaix.c +++ b/appl/dceutils/dpagaix.c @@ -1,6 +1,6 @@ /* * dpagaix.c - * On AIX we need to get the kernel extentions + * On AIX we need to get the kernel extensions * with the DFS kafs_syscall in it. * We might be running on a system * where DFS is not active. diff --git a/appl/dceutils/k5dce.h b/appl/dceutils/k5dce.h index 258a3c598..dd3286582 100644 --- a/appl/dceutils/k5dce.h +++ b/appl/dceutils/k5dce.h @@ -6,7 +6,7 @@ */ #ifdef sun -/* Transarc obfascates these routines */ +/* Transarc obfuscates these routines */ #ifdef DCE_1_1 #define krb5_init_ets _dce_PkjKqOaklP @@ -55,7 +55,7 @@ typedef unsigned char krb5_octet; typedef krb5_octet krb5_boolean; typedef krb5short krb5_keytype; /* in k5.2 it's a short */ typedef krb5_int32 krb5_flags; -typedef krb5_int32 krb5_timestamp; +typedef krb5_int32 krb5_timestamp; /* is a time_t in krb5.h */ typedef char * krb5_pointer; /* pointer to unexposed data */ diff --git a/appl/dceutils/k5dcecon.c b/appl/dceutils/k5dcecon.c index c20eaae55..c905625f3 100644 --- a/appl/dceutils/k5dcecon.c +++ b/appl/dceutils/k5dcecon.c @@ -163,8 +163,8 @@ int k5dcesession(luid, pname, tgt, ppag, tflags) /* * (but root has the ffffffff which we are not interested in) */ - if (!strncmp(direntp->d_name,"dcecred_",8) - && (strlen(direntp->d_name) == 16)) { + if (strncmp(direntp->d_name,"dcecred_",8) == 0 && + (strlen(direntp->d_name) == 16)) { /* looks like a cache name, lets do the stat, etc */ @@ -246,7 +246,7 @@ int k5dcematch(luid, pname, ccname, sizep, tgt) /* DEEDEBUG2("k5dcematch called: cache=%s\n",ccname+38); */ - if (!strncmp(ccname,"FILE:",5)) { + if (strncmp(ccname,"FILE:",5) == 0) { strcpy(ccdata,ccname+5); strcat(ccdata,".data"); @@ -343,7 +343,7 @@ int k5dcegettgt(pcache, ccname, pname, tgt) DEEDEBUG2("Unparsed to \"%s\"\n", kusername); DEEDEBUG2("pname is \"%s\"\n", pname); - if (strcmp(kusername, pname)) { + if (strcmp(kusername, pname) != 0) { DEEDEBUG("Principals not equal\n"); goto return1; } @@ -473,7 +473,7 @@ int k5dcecon(luid, luser, pname) /* * Destroy the Kerberos5 cred cache file. - * but dont care aout the return code. + * but don't care about the return code. */ DEEDEBUG("Destroying the old cache\n"); @@ -574,7 +574,7 @@ int k5dcecreate(luid, luser, pname, krbtgt) } - if (!strcmp(urealm,defrealm)) { + if (strcmp(urealm,defrealm) == 0) { strcpy(username,pname); } else { strcpy(username,"/.../"); @@ -601,7 +601,7 @@ int k5dcecreate(luid, luser, pname, krbtgt) "Error while adding credentials for %s because %s\n", username, err_string); goto abort; - } + } DEEDEBUG("validating and certifying\n"); /* * Now "validate" and certify the identity, diff --git a/appl/ftp/ChangeLog b/appl/ftp/ChangeLog deleted file mode 100644 index 72df672d6..000000000 --- a/appl/ftp/ChangeLog +++ /dev/null @@ -1,1038 +0,0 @@ -2008-05-29 Love Hörnquist Åstrand - - * ftp/ftp.c: use the correct length to munmap and use msync. - -2008-05-28 Love Hörnquist Åstrand - - * ftp/ftp.c: Rewrite sliding window code so it doesn't have a - integer overrun. - - * ftp/ftp.c: Try sliding mmap window over memory file (10MB - window), works better with larger files (ie doesn't fail). - -2008-04-10 Love Hörnquist Åstrand - - * ftpd/logwtmp.c: Use asl for logging ftpd wtmp messages. - -2007-07-12 Love Hörnquist Åstrand - - * ftp/gssapi.c: Fix pointer vs strict alias rules. - -2007-06-20 Love Hörnquist Åstrand - - * ftp/security.c: if no mech have no session, its ok, just don't - call it. - - * ftp/security.h: provide prototype for sec_userok(). - - * move ksetpag after initgroups to make it work on Linux when its - without syscall hooks to change sys_setgroups preserve the - pag. From Alexsander Boström. - -2007-06-09 Love Hörnquist Åstrand - - * ftpd/Makefile.am: don't clean yacc/lex files in CLEANFILES, - maintainers clean will do that for us. - -2006-10-07 Love Hörnquist Åstrand - - * ftpd/Makefile.am: Add man_MANS to EXTRA_DIST - - * ftp/Makefile.am: Add man_MANS to EXTRA_DIST - -2006-08-08 Love Hörnquist Åstrand - - * ftpd/ftpd.c: Add comment by seteuid call isn't not needed. - - * ftpd/ftpd.c: Check return values from seteuid, prompted by MIT - advisory. Thanks to Tom Yu at MIT, and Michael Calmer and Marcus - Meissner at SUSE. Either of CVE-2006-3083 or CVE-2006-3084. - -2006-06-27 Love Hörnquist Åstrand - - * ftpd/gss_userok.c (gss_userok): create a local krb5_context and - use that instead of the libgssapi context (that might not exist). - -2006-05-05 Love Hörnquist Åstrand - - * Rename u_intXX_t to uintXX_t - -2006-03-23 Love Hörnquist Åstrand - - * ftp/ftp.1: Add undocument flags and spelling, from Ted Percival - - -2006-02-27 Johan Danielsson - - * ftpd/ftpd.8: fix grammar in --no-insecure-oob option (partly - from Thomas Klausner) - -2006-01-24 Love Hörnquist Åstrand - - * ftp/ftp.c: Indent. - -2006-01-12 Johan Danielsson - - * ftpd/ftpd.c (pass): remove unused variable in the !OTP case - -2005-10-22 Love Hörnquist Åstrand - - * ftpd/ls.c: Check return value from asprintf instead of string != - NULL since it undefined behavior on Linux. From Björn Sandell - - * ftpd/gss_userok.c: Check return value from asprintf instead of - string != NULL since it undefined behavior on Linux. From Björn - Sandell - - * ftpd/ftpd.c: Check return value from asprintf instead of string - != NULL since it undefined behavior on Linux. From Björn Sandell - - * ftp/gssapi.c: Check return value from asprintf instead of string - != NULL since it undefined behavior on Linux. From Björn Sandell - -2005-10-12 Johan Danielsson - - * ftp/ftp.1: document -x - - * ftp/security.h: implement cprotect (from MIT) - - * ftp/security.c: add -x (encrypt) option; implement cprotect - (from MIT); make sure we CCC if switching to clear-text command - channel - - * ftp/cmdtab.c: implement cprotect (from MIT) - - * ftp/ruserpass.c: if doing command line encryption (-x), ignore - prot commands in .netrc - - * ftp/ftp_var.h: add -x (encrypt) option - - * ftp/globals.c: add -x (encrypt) option - - * ftp/main.c: add -x (encrypt) option - -2005-07-19 Love Hörnquist Åstrand - - * ftpd/ftpcmd.y: Fix shadow warning. - - * ftp/security.c: Fix shadow warning. - * ftp/security.c: Fix shadow warnings. - - * ftp/ruserpass.c: Fix shadow warnings. - - * ftp/ftp.c: Fix shadow warnings. - - * ftp/cmds.c: fix shadow warnings - - * Add Kerberos 5 klist, old patch from Tomas Nyström (remove krb4 - support). Support klist in client for kerberos 5 clase. - Clean up delegation of gss tokens and do afslog. - -2005-07-13 Love Hörnquist Åstrand - - * ftp/gssapi.c (gss_adat): avoid leaking memory - (gss_auth): always try next kname if there is one, independant of - min_stat - - * ftp/gssapi.c: avoid const warning, use sin4 instead of sin to - avoid shadow warning, free target_name - -2005-07-09 Love Hörnquist Åstrand - - * ftp/security.c: keep track of if CCC was passed - - * ftpd/extern.h: variable to keep track of if CCC was passed - - * ftpd/ftpcmd.y: sprinkel check_secure, check if CCC was passed in - check_secure - -2005-06-02 Love Hörnquist Åstrand - - * ftpd/ftpd.c (filename_check): change signednes of p to avoid - warning, move typecasts - -2005-05-29 Love Hörnquist Åstrand - - * ftpd/ftpd.c: avoid 'unused variable' warnings - -2005-05-10 David Love - - * ftpd/pathnames.h: #ifdef protect _PATH_ISSUE - -2005-04-25 Love Hörnquist Åstrand - - * ftp/domacro.c: handle string trunctions - -2005-04-24 Love Hörnquist Åstrand - - * ftp/security.c: use strlcat - - * ftp/domacro.c: use strlcpy - -2005-04-20 Love Hörnquist Åstrand - - * ftp/security.c: cast size_t to unsigned long - -2005-04-18 Love Hörnquist Åstrand - - * ftpd/ftpd.c (statcmd): cast argument to isdigit to unsigned char - - * ftp/cmds.c (mget): cast char to unsigned char to make sure its - not negative when passing it to tolower - -2005-04-07 Love Hörnquist Åstrand - - * ftp/ftp.c: fix 3 'var' might be used uninitialized warnings - -2005-04-04 Love Hörnquist Åstrand - - * ftp/cmds.c: MacOS is also a unix that doesn't define - __unix__/unix While here, rewrite this part of the function to not - modify that string, but rather take a copy of it and them modify - is, all this just to pacify gcc - -2005-01-09 Love Hörnquist Åstrand - - * ftp/domacro.c: cast argument to is* to unsigned char - - * ftp/ftp.c: cast argument to tolower to unsigned char - -2004-08-20 Love Hörnquist Åstrand - - * ftp/ftp.c: send ABOR protect with security layer if its there - - * ftpd/{ftpd_locl.h, extern.h, ftpcmd.y, ftpd.8, ftpd.c}: - Remove all traces of setjmp/longjmp. - Handle those command that is needed in oobhandler, - those are ABOR, STAT, ENC, CONF, MIC. - add options to turn off insecure OOB handling and document the option - - Changes inspired by openbsd and netbsd changes but quite diffrent is - most places since the code no longer look and is structured the same - way. - -2004-08-16 Johan Danielsson - - * ftp/main.c: reverse help strings for --no-gss-bindings and - --no-gss-delegate - -2004-06-20 Love Hörnquist Åstrand - - * ftpd/ftpcmd.y: make cbuf 64k to handle lager tickets From: - MAAAAA MOOOR - -2004-03-14 Love Hörnquist Åstrand - - * ftpd/ftpd.c (main): setpag if there is krb4 OR krb5 support - -2003-12-19 Love Hörnquist Åstrand - - * ftp/security.h: add ftp_do_gss_delegate - - * ftp/main.c (getargs): negative flag for delegating gss creds - - * ftp/gssapi.c (ftp_do_gss_delegate): delegate creds (default on) - -2003-09-03 Love Hörnquist Åstrand - - * ftp/ftp.c: s/des_read_pw_string/UI_UTIL_read_pw_string/ - - * ftp/cmds.c: s/des_read_pw_string/UI_UTIL_read_pw_string/ - -2003-07-19 Love Hörnquist Åstrand - - * ftp/security.h: add ftp_do_gss_bindings - - * ftp/ftp.1: fix mdoc bug - - * ftp/ftp.1: document --no-gss-bindings - - * ftp/gssapi.c: Optionally support gss bindings, client does it by - default, server not. This is to make it work for clients behind - NAT. - - * ftp/main.c (args): add gss-bindings - (main): set ftp_do_gss_bindings to 1 to make client use them - - * ftpd/ftpd.c (args): add gss-bindings - - * ftpd/ftpd.8: document --gss-bindings - -2003-06-13 Johan Danielsson - - * ftp/gssapi.c (gss_adat): fix name allocation bug - -2003-05-21 Love Hörnquist Åstrand - - * ftpd/gss_userok.c (gss_userok): release delegated cred handle - - * ftp/gssapi.c (gss_adat): remove poking inside the delegated - handle, also fixes problem where to much memory was allocated - - * ftpd/gss_userok.c (gss_userok): remove poking inside the - delegated handle - -2003-05-14 Love Hörnquist Åstrand - - * ftpd/ftpcmd.y: support afslog and afslog when compiled - with krb5 - -2003-05-07 Love Hörnquist Åstrand - - * ftp/cmdtab.c: include afslog in both the krb4 and krb5 case - - * ftp/kauth.c: include afslog in both the krb4 and krb5 case - - * ftp/Makefile.am: always include auth.c - -2003-05-07 Love Hörnquist Åstrand - - * ftpd/Makefile.am: always include auth.c - - * ftpd/kauth.c: do afslog in the krb5 case too - -2003-04-22 Love Hörnquist Åstrand - - * ftp/ftp.1: replace > with \*[Gt] - -2003-04-16 Love Hörnquist Åstrand - - * ftpd/ftpd.c: make sure argument to is* functions are unsigned - -2003-04-06 Love Hörnquist Åstrand - - * ftpd/ftpd.8: s/kerberos/Kerberos/ - -2003-03-23 Assar Westerlund - - * ftpd/pathnames.h (_PATH_FTPUSERS): conditionalize - -2003-03-18 Love Hörnquist Åstrand - - * ftpd/ftpd.c (krb5_verify): always do krb5_afslog, remove setpag - (its done in main) - - * ftpd/gss_userok.c: drop setpag - - * ftpd/ftpd.c (main): set afs PAG - - * ftpd/gss_userok.c: always try krb5_afslog, and while here do a - setpag too - - * ftpd/ftpd_locl.h: always include kafs - -2003-03-16 Love Hörnquist Åstrand - - * ftp/gssapi.c (gss_adat): now that gss_export_name exports a - principal, bandaid with gss_display_name, and check that oid is - GSS_KRB5_NT_PRINCIPAL_NAME, also free memory - -2003-02-25 Love Hörnquist Åstrand - - * ftp/gssapi.c (gss_auth): print out the name we authenticated too - -2003-02-25 Love Hörnquist Åstrand - - * ftpd/ls.c: use readlink with bufsize - 1, From NetBSD - - * ftp/ftp.1: s/utilizes/uses/ from NetBSD - - * ftpd/ftpd.8: s/utilize/use/ from NetBSD - -2003-02-10 Assar Westerlund - - * ftpd/ftpd.c (accept_with_timeout): use socklen_t - -2002-10-29 Johan Danielsson - - * ftp/main.c: reinstate -n flag (from Torbjörn Granlund) - -2002-10-16 Johan Danielsson - - * ftp/ftp.c: fix parsing of epsv ports (from Love) - -2002-09-05 Johan Danielsson - - * ftp/security.c (sec_vfprintf): free encoded data - - * ftp/gssapi.c (gss_decode): release buffer - - * ftp/ftp.c (active_mode): no need to allocate buffer for EPRT - -2002-08-28 Johan Danielsson - - * ftp/ftp.c (command): clean up va_{start,end}ing (from NetBSD) - -2002-08-23 Assar Westerlund - - * ftp/main.c: start using getarg - -2002-08-22 Johan Danielsson - - * ftpd/ls.c: uxp/v lacks _S_IFMT, but has S_IFMT - -2002-08-20 Johan Danielsson - - * ftp/gssapi.c: remove unused variable - -2002-04-24 Johan Danielsson - - * ftp/ftp.c: fix buffer overrun when receiving long replies - -2002-04-02 Johan Danielsson - - * ftpd/popen.c: make sure gl_pathc != 0 before referencing - gl_pathv - -2002-03-15 Johan Danielsson - - * ftp/gssapi.c (gss_adat): if accept_sec_context fails, syslog a - reason and give a temporary error message - -2002-02-28 Johan Danielsson - - * ftpd/ftpd.c: if builtin_ls failes, return error - - * ftpd/ls.c (builtin_ls): return status; also don't print fatal - error messages to the output stream, instead use syslog - -2001-09-14 Johan Danielsson - - * ftpd/ls.c: make sure we don't include . in recursive listings - -2001-09-13 Johan Danielsson - - * ftpd/ftpd.c (dataconn): don't wait forever on accept - -2001-09-04 Assar Westerlund - - * ftp/gssapi.c (gss_adat): leak less memory and check return value - from asprintf - -2001-08-28 Jacques Vidrine - - * ftpd/ftpd.c, ftpd/ftpd.8: On systems with IP_PORTRANGE, have - ftpd use `high-numbered' ports by default. Add a -U option - to get the old behavior. - -2001-08-28 Johan Danielsson - - * ftp/gssapi.c: try using "host" if there's no "ftp" principal - -2001-08-26 Johan Danielsson - - * ftpd/ls.c: implement -R - -2001-08-08 Assar Westerlund - - * ftpd/ls.c: make -a and -A do the same as in ls(1) - -2001-08-05 Assar Westerlund - - * ftpd/ftpcmd.y: add some (unsigned char) casts to is* - * ftp/cmds.c: add some (unsigned char) casts to is* - * ftpd/gss_userok.c (gss_userok): make argument to printf type - correct - -2001-08-05 Assar Westerlund - - * ftp/cmds.c (setpeer): __NetBSD__ is also a unix-like OS - -2001-06-19 Assar Westerlund - - * ftpd/popen.c, ftpd/ftpd.c: try to handle GLOB_MAXPATH (FreeBSD) - -2001-04-19 Johan Danielsson - - * ftpd/ftpd.c (do_store): call closefunc before claiming that - everything went ok, if the close fails the file might not have - been stored properly - -2001-03-26 Assar Westerlund - - * ftpd/ftpd.c, ftpd/popen.c: always use GLOB_LIMIT - * ftpd/popen.c (ftpd_popen): use GLOB_LIMIT if defined - * ftpd/ftpd.c (send_file_list): use GLOB_LIMIT if defined - -2001-02-15 Assar Westerlund - - * ftp/cmds.c (setpeer): handle both service names and port numbers - for the second optional argument. also make parsing more robust - -2001-02-07 Assar Westerlund - - * ftp/security.c (sec_end): only clean app_data if there is any - (*): do realloc consistently - -2001-02-05 Assar Westerlund - - * ftpd/popen.c (ftpd_popen): avoid overwriting the bounds of argv - and gargv - -2001-01-30 Assar Westerlund - - * ftpd/gss_userok.c: use gss_krb5_copy_ccache - -2001-01-29 Assar Westerlund - - * ftpd/Makefile.am: move up LIB_otp so we do not end up picking - one from /usr/athena - -2001-01-25 Johan Danielsson - - * ftpd/ls.c: fix bug in previous; make it easier to build test - version - -2001-01-19 Johan Danielsson - - * ftpd/ls.c (lstat_file): handle case where file lives in `/' - -2001-01-18 Johan Danielsson - - * ftpd/ftpd.c (pasv): close already open passive port - -2000-12-14 Johan Danielsson - - * ftpd/ls.c: reverse time and size sort order (pointed out by - tege) - -2000-12-11 Johan Danielsson - - * ftpd/ftpd.c: make it possible to set list of good filename - characters from command line - -2000-12-10 Johan Danielsson - - * ftpd/ftpd.c: some spec-violating mirror software assumes that - you can do things like `LIST -CF'; don't pass `--' to ls so this - actually works - - * ftpd/ls.c: implement -1CFx flags - -2000-12-08 Assar Westerlund - - * ftpd/gss_userok.c (gss_userok): handle getpwnam failing - * ftp/gssapi.c (gss_auth): be more explicit in error message - -2000-11-29 Johan Danielsson - - * ftpd/ftpd.8: close list - -2000-11-15 Assar Westerlund - - * ftp/main.c: add `-l' for no line-editing - * ftp/globals.c (readline): add - * ftp/ftp_var.h (lineedit): add variable indicated if we should - use readline - -2000-11-09 Johan Danielsson - - * ftp/security.c (sec_read): fix bug in previous (from Jacques A. - Vidrine ) - -2000-11-05 Johan Danielsson - - * ftpd/ftpcmd.y: only allow pasv if logged in - -2000-10-23 Johan Danielsson - - * ftpd/ftpd.c: change bad filename message slightly - - * common/buffer.c: HAVE_ST_BLKSIZE -> HAVE_STRUCT_STAT_ST_BLKSIZE - -2000-10-08 Assar Westerlund - - * ftp/ftp.c (*): check that fds are not too large to select on - * ftp/main.c (cmdscanner): print a newline upon EOF - -2000-09-19 Assar Westerlund - - * ftp/security.h: add some attributes to prototypes of sec* - * ftp/extern.h (command): add attributes - -2000-08-31 Johan Danielsson - - * ftpd/ftpd.c: change redundant password message to something - people can understand - -2000-07-27 Assar Westerlund - - * ftpd/gss_userok.c (gss_userok): only do AFS iff KRB4 - * ftpd/ftpd.c (krb5_verify): only do AFS stuff if KRB4 - -2000-07-07 Assar Westerlund - - * ftpd/ftpd.c: do not call setproctitle with a variable as the - format string - -2000-07-01 Assar Westerlund - - * ftpd/ftpd_locl.h: krb5.h before kafs.h - * ftpd/ftpd.c (krb5_verify): static-ize - * ftpd/ftpd.c (krb5_verify): conditionalize on KRB5 - -2000-06-21 Assar Westerlund - - * ftpd: support for authenticating passwords with krb5, by Daniel - Kouril - -2000-06-06 Johan Danielsson - - * ftpd/ftpcmd.y: change unix test to be negative - -2000-05-18 Assar Westerlund - - * ftpd/ftpd.c (args): should use `debug'. From Onno van der - Linden . - -2000-04-25 Assar Westerlund - - * ftp/ftp.c (login): re-structure code so that we prompt for - password for ftp/anonymous - -2000-04-11 Assar Westerlund - - * ftp/ftp.c (login): initialize tmp before calling fgets - -2000-04-02 Assar Westerlund - - * ftpd/ls.c: rename all st_mtime variables to avoid conflict with - #define. - * ftpd/ftpcmd.y: rename all st_mtime variables to avoid conflict - with #define. - * ftp/cmds.c: rename all st_mtime variables to avoid conflict with - #define. - -2000-03-26 Assar Westerlund - - * ftpd/ls.c, ftpd/ftpcmd.y, ftp/cmds.c: make sure to always call - time, ctime, and gmtime with `time_t's. there were some types - (like in lastlog) that we believed to always be time_t. this has - proven wrong on Solaris 8 in 64-bit mode, where they are stored as - 32-bit quantities but time_t has gone up to 64 bits - -2000-03-09 Johan Danielsson - - * call list_file for broken usages of nlst too - - * ftpd/ftpd.c: call list_file for broken usages of nlst too - -2000-02-07 Assar Westerlund - - * ftp/security.c (sec_read): more paranoia with return value from - sec_get_data - -2000-01-08 Assar Westerlund - - * ftp/ftp.c (hookup): handle ai_canonname being set in any of the - addresses returnedby getaddrinfo. glibc apparently returns the - reverse lookup of every address in ai_canonname. - * ftp/ruserpass.c (guess_domain): dito - -1999-12-21 Assar Westerlund - - * ftpd/ftpd.c: don't use sa_len as a parameter, it's defined on - Irix - -1999-12-21 Johan Danielsson - - * ftpd/ftpd.c (dataconn): make sure from points to actual data - -1999-12-16 Assar Westerlund - - * ftp/ruserpass.c (guess_domain): handle ai_canonname not being - set - * ftp/ftp.c (hookup): handle ai_canonname not being set - -1999-12-06 Assar Westerlund - - * ftp/krb4.c (krb4_auth): the nat-IP address might not be realm - bounded. - -1999-12-05 Assar Westerlund - - * ftpd/ftpd.c (dolog): update prototype - * ftpd/ftpd.c (dolog): use getnameinfo_verified - * ftpd/ftpd.c: replace inaddr2str by getnameinfo - -1999-12-04 Assar Westerlund - - * ftp/ruserpass.c (guess_domain): re-write to use getaddrinfo - * ftp/ftp.c (hookup): re-write to use getaddrinfo - -1999-11-30 Assar Westerlund - - * ftpd/ftpd.c (getdatasock): make sure to keep the port-number of - the outgoing connections. It has to be `ftp-data' or some people - might get upset. - - * ftpd/ftpd.c (args): set correct variable when `-l' so that - logging actually works - -1999-11-29 Assar Westerlund - - * ftp/security.c (sec_login): check return value from realloc - (sec_end): set app_data to NULL - -1999-11-25 Assar Westerlund - - * ftp/krb4.c (krb4_auth): obtain the `local' address when doing - NAT. also turn on passive mode. From - -1999-11-20 Assar Westerlund - - * ftpd/ls.c (make_fileinfo): cast to allow for non-const - prototypes of readlink - -1999-11-12 Assar Westerlund - - * ftpd/ftpd.c (args): use arg_counter for `l' - -1999-11-04 Assar Westerlund - - * ftpd/ls.c (S_ISSOCK, S_ISLNK): fallback definitions for systems - that don't have them (such as ultrix) - -1999-10-29 Assar Westerlund - - * ftpd/ls.c (make_fileinfo): cast uid's and gid's to unsigned in - printf, we don't know what types they might be. - (lstat_file): conditionalize the kafs part on KRB4 - - * ftpd/ftpd_locl.h: is needed for kafs.h - -1999-10-28 Assar Westerlund - - * ftpd/ls.c (lstat_file): don't set st_mode, it should already be - correct - - * ftpd/ls.c: don't use warnx to print errors - - * ftpd/ls.c (builtin_ls): fix typo, 'd' shouldn't imply 'f' - - * ftpd/ls.c (lstat_file): new function for avoiding stating AFS - mount points. From Love - (list_files): use `lstat_file' - - * ftpd/ftpd.c: some const-poisoning - - * ftpd/ftpd.c (args): add `-B' as an alias for `--builtin-ls' to - allow for stupid inetds that only support two arguments. From - Love - -1999-10-26 Assar Westerlund - - * ftpd/ftpcmd.y (help): it's unnecessary to interpret help strings - as printf commands - - * ftpd/ftpd.c (show_issue): don't interpret contents of - /etc/issue* as printf commands. From Brian A May - - -1999-10-21 Johan Danielsson - - * ftpd/kauth.c (kauth): complain if protection level isn't - `private' - - * ftp/krb4.c (krb4_decode): syslog failure reason - - * ftp/kauth.c (kauth): set private level earlier - - * ftp/security.c: get_command_prot; (sec_prot): partially match - `command' and `data' - -1999-10-18 Johan Danielsson - - * ftpd/ftpd.c: change `-l' flag to use arg_collect (this makes - `-ll' work again) - - * ftpd/ftpd.c (list_file): pass filename to ls - -1999-10-04 Johan Danielsson - - * ftpd/ftpcmd.y: FEAT - -1999-10-03 Assar Westerlund - - * ftpd/ls.c: fall-back definitions for constans and casts for - printfs - -1999-10-03 Johan Danielsson - - * ftpd/ftpd.c (main): make this use getarg; add `list_file' - - * ftpd/ftpcmd.y (LIST): call list_file - - * ftpd/ls.c: add simple built-in ls - - * ftp/security.c: add `sec_vfprintf2' and `sec_fprintf2' that - prints to the data stream - - * ftp/kauth.c (kauth): make sure we're using private protection - level - - * ftp/security.c (set_command_prot): set command protection level - - * ftp/security.c: make it possible to set the command protection - level with `prot' - -1999-09-30 Assar Westerlund - - * ftpd/ftpd_locl.h: add prototype for fclose to make sunos happy - -1999-08-19 Johan Danielsson - - * ftpd/ftpd.c (do_login): show issue-file - (send_data): change handling of zero-byte files - -1999-08-18 Assar Westerlund - - * ftp/cmds.c (getit): be more suspicious when parsing the result - of MDTM. Do the comparison of timestamps correctly. - -1999-08-13 Assar Westerlund - - * ftpd/ftpd.c (send_data): avoid calling mmap with `len == 0'. - Some mmap:s rather dislike that (Solaris) and some munmap (Linux) - get grumpy later. - - * ftp/ftp.c (copy_stream): avoid calling mmap with `len == 0'. - Some mmap:s rather dislike that (Solaris) and some munmap (Linux) - get grumpy later. - -1999-08-03 Assar Westerlund - - * ftp/ftp.c (active_mode): hide failure of EPRT by setting verbose - - * ftp/gssapi.c (gss_auth): initialize application_data in bindings - -1999-08-02 Assar Westerlund - - * ftpd/ftpcmd.y: save file names when doing commands that might - get aborted (and longjmp:ed out of) to avoid overwriting them also - remove extra closing brace - -1999-08-01 Johan Danielsson - - * ftpd/ftpcmd.y: change `site find' to `site locate' (to match - what it does, and other implementations) keep find as an alias - -1999-07-28 Assar Westerlund - - * common/socket.c: moved to roken - - * common/socket.c: new file with generic socket functions - - * ftpd/ftpd.c: make it more AF-neutral and v6-capable - - * ftpd/ftpcmd.y: add EPRT and EPSV - - * ftpd/extern.h: update prototypes and variables - - * ftp/krb4.c: update to new types of addresses - - * ftp/gssapi.c: add support for both AF_INET and AF_INET6 - addresses - - * ftp/ftp.c: make it more AF-neutral and v6-capable - - * ftp/extern.h (hookup): change prototype - - * common/common.h: add prototypes for functions in socket.c - - * common/Makefile.am (libcommon_a_SOURCES): add socket.c - - * ftp/gssapi.c (gss_auth): check return value from - `gss_import_name' and print error messages if it fails - -1999-06-15 Assar Westerlund - - * ftp/krb4.c (krb4_auth): type correctness - -1999-06-02 Johan Danielsson - - * ftp/ftp.c (sendrequest): lmode != rmode - -1999-05-21 Assar Westerlund - - * ftp/extern.h (sendrequest): update prototype - - * ftp/cmds.c: update calls to sendrequest and recvrequest to send - "b" when appropriate - - * ftp/ftp.c (sendrequest): add argument for mode to open file in. - -1999-05-08 Assar Westerlund - - * ftpd/ftpcmd.y: rename getline -> ftpd_getline - - * ftp/main.c (makeargv): fill in unused slots with NULL - -Thu Apr 8 15:06:40 1999 Johan Danielsson - - * ftpd/ftpd.c: remove definition of KRB_VERIFY_USER (moved to - config.h) - -Wed Apr 7 16:15:21 1999 Johan Danielsson - - * ftp/gssapi.c (gss_auth): call gss_display_status to get a sane - error message; return AUTH_{CONTINUE,ERROR}, where appropriate - - * ftp/krb4.c: return AUTH_{CONTINUE,ERROR}, where appropriate - - * ftp/security.c (sec_login): if mechanism returns AUTH_CONTINUE, - just continue with the next mechanism, this fixes the case of - having GSSAPI fail because of non-existant of expired tickets - - * ftp/security.h: add AUTH_{OK,CONTINUE,ERROR} - -Thu Apr 1 16:59:04 1999 Johan Danielsson - - * ftpd/Makefile.am: don't run check-local - - * ftp/Makefile.am: don't run check-local - -Mon Mar 22 22:15:18 1999 Assar Westerlund - - * ftpd/ftpd.c (pass): fall-back for KRB_VERIFY_SECURE - - * ftpd/ftpd.c (pass): 1 -> KRB_VERIFY_SECURE - -Thu Mar 18 12:07:09 1999 Johan Danielsson - - * ftpd/Makefile.am: clean ftpcmd.c - - * ftpd/ftpd_locl.h: remove krb5.h (breaks in ftpcmd.y) - - * ftpd/ftpd.c: move include of krb5.h here - - * ftpd/Makefile.am: include Makefile.am.common - - * Makefile.am: include Makefile.am.common - - * ftp/Makefile.am: include Makefile.am.common - - * common/Makefile.am: include Makefile.am.common - -Tue Mar 16 22:28:37 1999 Assar Westerlund - - * ftpd/ftpd_locl.h: add krb5.h to get heimdal_version - - * ftpd/ftpd.c: krb_verify_user_multiple -> krb_verify_user - -Thu Mar 11 14:54:59 1999 Johan Danielsson - - * ftp/Makefile.in: WFLAGS - - * ftp/ruserpass.c: add some if-braces - -Wed Mar 10 20:02:55 1999 Johan Danielsson - - * ftpd/ftpd_locl.h: remove ifdef HAVE_FNMATCH - -Mon Mar 8 21:29:24 1999 Johan Danielsson - - * ftpd/ftpd.c: re-add version in greeting message - -Mon Mar 1 10:49:38 1999 Johan Danielsson - - * ftpd/logwtmp.c: HAVE_UT_* -> HAVE_STRUCT_UTMP*_UT_* - -Mon Feb 22 19:20:51 1999 Johan Danielsson - - * common/Makefile.in: remove glob - -Sat Feb 13 17:19:35 1999 Assar Westerlund - - * ftpd/ftpd.c (match): remove #ifdef HAVE_FNMATCH. We have a - fnmatch implementation in roken and therefore always have it. - - * ftp/ftp.c (copy_stream): initialize `werr' - -Wed Jan 13 23:52:57 1999 Assar Westerlund - - * ftpd/ftpcmd.y: moved all check_login and check_login_no_guest to - the end of the rules to ensure we don't generate several - (independent) error messages. once again, having a yacc-grammar - for FTP with embedded actions doesn't strike me as the most - optimal way of doing it. - -Tue Dec 1 14:44:29 1998 Johan Danielsson - - * ftpd/Makefile.am: link with extra libs for aix - -Sun Nov 22 10:28:20 1998 Assar Westerlund - - * ftpd/ftpd.c (retrying): support on-the-fly decompression - - * ftpd/Makefile.in (WFLAGS): set - - * ftp/ruserpass.c (guess_domain): new function - (ruserpass): use it - - * common/Makefile.in (WFLAGS): set - - * Makefile.in (WFLAGS): set - -Sat Nov 21 23:13:03 1998 Assar Westerlund - - * ftp/security.c: some more type correctness. - - * ftp/gssapi.c (gss_adat): more braces to shut up warnings - -Wed Nov 18 21:47:55 1998 Assar Westerlund - - * ftp/main.c (main): new option `-p' for enable passive mode. - -Mon Nov 2 01:57:49 1998 Assar Westerlund - - * ftp/ftp.c (getreply): remove extra `break' - - * ftp/gssapi.c (gss_auth): fixo typo(copyo?) - - * ftp/security.c (sec_login): fix loop and return value - -Tue Sep 1 16:56:42 1998 Johan Danielsson - - * ftp/cmds.c (quote1): fix % quoting bug - -Fri Aug 14 17:10:06 1998 Johan Danielsson - - * ftp/krb4.c: krb_put_int -> KRB_PUT_INT - -Tue Jun 30 18:07:15 1998 Assar Westerlund - - * ftp/security.c (auth): free `app_data' - (sec_end): only destroy if it was initialized - -Tue Jun 9 21:01:59 1998 Johan Danielsson - - * ftp/krb4.c: pass client address to krb_rd_req - -Sat May 16 00:02:07 1998 Assar Westerlund - - * ftpd/Makefile.am: link with DBLIB - -Tue May 12 14:15:32 1998 Johan Danielsson - - * ftp/gssapi.c: Save client name for userok(). - - * ftpd/gss_userok.c: Userok for gssapi. - -Fri May 1 07:15:01 1998 Assar Westerlund - - * ftp/ftp.c: unifdef -DHAVE_H_ERRNO - -Fri Mar 27 00:46:07 1998 Johan Danielsson - - * Make compile w/o krb4. - -Thu Mar 26 03:49:12 1998 Johan Danielsson - - * ftp/*, ftpd/*: Changes for new framework. - - * ftp/gssapi.c: GSS-API backend for the new security framework. - - * ftp/krb4.c: Updated for new framework. - - * ftp/security.{c,h}: New unified security framework. diff --git a/appl/ftp/Makefile.am b/appl/ftp/Makefile.am deleted file mode 100644 index 07f260bfb..000000000 --- a/appl/ftp/Makefile.am +++ /dev/null @@ -1,5 +0,0 @@ -# $Id$ - -include $(top_srcdir)/Makefile.am.common - -SUBDIRS = common ftp ftpd diff --git a/appl/ftp/common/Makefile.am b/appl/ftp/common/Makefile.am deleted file mode 100644 index cfe1bb625..000000000 --- a/appl/ftp/common/Makefile.am +++ /dev/null @@ -1,12 +0,0 @@ -# $Id$ - -include $(top_srcdir)/Makefile.am.common - -AM_CPPFLAGS += $(INCLUDE_krb4) - -noinst_LIBRARIES = libcommon.a - -libcommon_a_SOURCES = \ - sockbuf.c \ - buffer.c \ - common.h diff --git a/appl/ftp/ftp/Makefile.am b/appl/ftp/ftp/Makefile.am deleted file mode 100644 index c53d858e9..000000000 --- a/appl/ftp/ftp/Makefile.am +++ /dev/null @@ -1,44 +0,0 @@ -# $Id$ - -include $(top_srcdir)/Makefile.am.common - -AM_CPPFLAGS += -I$(srcdir)/../common $(INCLUDE_readline) $(INCLUDE_hcrypto) - -bin_PROGRAMS = ftp - -CHECK_LOCAL = - -if KRB5 -krb5_sources = gssapi.c -endif - -ftp_SOURCES = \ - cmds.c \ - cmdtab.c \ - extern.h \ - ftp.c \ - ftp_locl.h \ - ftp_var.h \ - main.c \ - pathnames.h \ - ruserpass.c \ - domacro.c \ - globals.c \ - security.c \ - security.h \ - kauth.c \ - $(krb5_sources) - -EXTRA_ftp_SOURCES = gssapi.c - -man_MANS = ftp.1 - -LDADD = \ - ../common/libcommon.a \ - $(LIB_gssapi) \ - $(LIB_krb5) \ - $(LIB_hcrypto) \ - $(LIB_roken) \ - $(LIB_readline) - -EXTRA_DIST = $(man_MANS) diff --git a/appl/ftp/ftp/cmds.c b/appl/ftp/ftp/cmds.c deleted file mode 100644 index 0c1355a8e..000000000 --- a/appl/ftp/ftp/cmds.c +++ /dev/null @@ -1,2148 +0,0 @@ -/* - * Copyright (c) 1985, 1989, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * FTP User Program -- Command Routines. - */ - -#include "ftp_locl.h" -RCSID("$Id$"); - -typedef void (*sighand)(int); - -jmp_buf jabort; -char *mname; -char *home = "/"; - -/* - * `Another' gets another argument, and stores the new argc and argv. - * It reverts to the top level (via main.c's intr()) on EOF/error. - * - * Returns false if no new arguments have been added. - */ -int -another(int *pargc, char ***pargv, char *prompt) -{ - int len = strlen(line), ret; - - if (len >= sizeof(line) - 3) { - printf("sorry, arguments too long\n"); - intr(0); - } - printf("(%s) ", prompt); - line[len++] = ' '; - if (fgets(&line[len], sizeof(line) - len, stdin) == NULL) - intr(0); - len += strlen(&line[len]); - if (len > 0 && line[len - 1] == '\n') - line[len - 1] = '\0'; - makeargv(); - ret = margc > *pargc; - *pargc = margc; - *pargv = margv; - return (ret); -} - -/* - * Connect to peer server and - * auto-login, if possible. - */ -void -setpeer(int argc, char **argv) -{ - char *host; - u_short port; - struct servent *sp; - - if (connected) { - printf("Already connected to %s, use close first.\n", - hostname); - code = -1; - return; - } - if (argc < 2) - another(&argc, &argv, "to"); - if (argc < 2 || argc > 3) { - printf("usage: %s host-name [port]\n", argv[0]); - code = -1; - return; - } - sp = getservbyname("ftp", "tcp"); - if (sp == NULL) - errx(1, "You bastard. You removed ftp/tcp from services"); - port = sp->s_port; - if (argc > 2) { - sp = getservbyname(argv[2], "tcp"); - if (sp != NULL) { - port = sp->s_port; - } else { - char *ep; - - port = strtol(argv[2], &ep, 0); - if (argv[2] == ep) { - printf("%s: bad port number-- %s\n", - argv[1], argv[2]); - printf ("usage: %s host-name [port]\n", - argv[0]); - code = -1; - return; - } - port = htons(port); - } - } - host = hookup(argv[1], port); - if (host) { - int overbose; - - connected = 1; - /* - * Set up defaults for FTP. - */ - strlcpy(typename, "ascii", sizeof(typename)); - type = TYPE_A; - curtype = TYPE_A; - strlcpy(formname, "non-print", sizeof(formname)); - form = FORM_N; - strlcpy(modename, "stream", sizeof(modename)); - mode = MODE_S; - strlcpy(structname, "file", sizeof(structname)); - stru = STRU_F; - strlcpy(bytename, "8", sizeof(bytename)); - bytesize = 8; - if (autologin) - login(argv[1]); - -#if (defined(unix) || defined(__unix__) || defined(__unix) || defined(_AIX) || defined(_CRAY) || defined(__NetBSD__) || defined(__APPLE__)) && NBBY == 8 -/* - * this ifdef is to keep someone form "porting" this to an incompatible - * system and not checking this out. This way they have to think about it. - */ - overbose = verbose; - if (debug == 0) - verbose = -1; - if (command("SYST") == COMPLETE && overbose && strlen(reply_string) > 4) { - char *cp, *p; - - cp = strdup(reply_string + 4); - if (cp == NULL) - errx(1, "strdup: out of memory"); - p = strchr(cp, ' '); - if (p == NULL) - p = strchr(cp, '\r'); - if (p) { - if (p[-1] == '.') - p--; - *p = '\0'; - } - - printf("Remote system type is %s.\n", cp); - free(cp); - } - if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) { - if (proxy) - unix_proxy = 1; - else - unix_server = 1; - /* - * Set type to 0 (not specified by user), - * meaning binary by default, but don't bother - * telling server. We can use binary - * for text files unless changed by the user. - */ - type = 0; - strlcpy(typename, "binary", sizeof(typename)); - if (overbose) - printf("Using %s mode to transfer files.\n", - typename); - } else { - if (proxy) - unix_proxy = 0; - else - unix_server = 0; - if (overbose && - !strncmp(reply_string, "215 TOPS20", 10)) - printf( -"Remember to set tenex mode when transfering binary files from this machine.\n"); - } - verbose = overbose; -#endif /* unix */ - } -} - -struct types { - char *t_name; - char *t_mode; - int t_type; - char *t_arg; -} types[] = { - { "ascii", "A", TYPE_A, 0 }, - { "binary", "I", TYPE_I, 0 }, - { "image", "I", TYPE_I, 0 }, - { "ebcdic", "E", TYPE_E, 0 }, - { "tenex", "L", TYPE_L, bytename }, - { NULL } -}; - -/* - * Set transfer type. - */ -void -settype(int argc, char **argv) -{ - struct types *p; - int comret; - - if (argc > 2) { - char *sep; - - printf("usage: %s [", argv[0]); - sep = " "; - for (p = types; p->t_name; p++) { - printf("%s%s", sep, p->t_name); - sep = " | "; - } - printf(" ]\n"); - code = -1; - return; - } - if (argc < 2) { - printf("Using %s mode to transfer files.\n", typename); - code = 0; - return; - } - for (p = types; p->t_name; p++) - if (strcmp(argv[1], p->t_name) == 0) - break; - if (p->t_name == 0) { - printf("%s: unknown mode\n", argv[1]); - code = -1; - return; - } - if ((p->t_arg != NULL) && (*(p->t_arg) != '\0')) - comret = command ("TYPE %s %s", p->t_mode, p->t_arg); - else - comret = command("TYPE %s", p->t_mode); - if (comret == COMPLETE) { - strlcpy(typename, p->t_name, sizeof(typename)); - curtype = type = p->t_type; - } -} - -/* - * Internal form of settype; changes current type in use with server - * without changing our notion of the type for data transfers. - * Used to change to and from ascii for listings. - */ -void -changetype(int newtype, int show) -{ - struct types *p; - int comret, oldverbose = verbose; - - if (newtype == 0) - newtype = TYPE_I; - if (newtype == curtype) - return; - if (debug == 0 && show == 0) - verbose = 0; - for (p = types; p->t_name; p++) - if (newtype == p->t_type) - break; - if (p->t_name == 0) { - printf("ftp: internal error: unknown type %d\n", newtype); - return; - } - if (newtype == TYPE_L && bytename[0] != '\0') - comret = command("TYPE %s %s", p->t_mode, bytename); - else - comret = command("TYPE %s", p->t_mode); - if (comret == COMPLETE) - curtype = newtype; - verbose = oldverbose; -} - -char *stype[] = { - "type", - "", - 0 -}; - -/* - * Set binary transfer type. - */ -/*VARARGS*/ -void -setbinary(int argc, char **argv) -{ - - stype[1] = "binary"; - settype(2, stype); -} - -/* - * Set ascii transfer type. - */ -/*VARARGS*/ -void -setascii(int argc, char **argv) -{ - - stype[1] = "ascii"; - settype(2, stype); -} - -/* - * Set tenex transfer type. - */ -/*VARARGS*/ -void -settenex(int argc, char **argv) -{ - - stype[1] = "tenex"; - settype(2, stype); -} - -/* - * Set file transfer mode. - */ -/*ARGSUSED*/ -void -setftmode(int argc, char **argv) -{ - - printf("We only support %s mode, sorry.\n", modename); - code = -1; -} - -/* - * Set file transfer format. - */ -/*ARGSUSED*/ -void -setform(int argc, char **argv) -{ - - printf("We only support %s format, sorry.\n", formname); - code = -1; -} - -/* - * Set file transfer structure. - */ -/*ARGSUSED*/ -void -setstruct(int argc, char **argv) -{ - - printf("We only support %s structure, sorry.\n", structname); - code = -1; -} - -/* - * Send a single file. - */ -void -put(int argc, char **argv) -{ - char *cmd; - int loc = 0; - char *oldargv1, *oldargv2; - - if (argc == 2) { - argc++; - argv[2] = argv[1]; - loc++; - } - if (argc < 2 && !another(&argc, &argv, "local-file")) - goto usage; - if (argc < 3 && !another(&argc, &argv, "remote-file")) { -usage: - printf("usage: %s local-file remote-file\n", argv[0]); - code = -1; - return; - } - oldargv1 = argv[1]; - oldargv2 = argv[2]; - if (!globulize(&argv[1])) { - code = -1; - return; - } - /* - * If "globulize" modifies argv[1], and argv[2] is a copy of - * the old argv[1], make it a copy of the new argv[1]. - */ - if (argv[1] != oldargv1 && argv[2] == oldargv1) { - argv[2] = argv[1]; - } - cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR"); - if (loc && ntflag) { - argv[2] = dotrans(argv[2]); - } - if (loc && mapflag) { - argv[2] = domap(argv[2]); - } - sendrequest(cmd, argv[1], argv[2], - curtype == TYPE_I ? "rb" : "r", - argv[1] != oldargv1 || argv[2] != oldargv2); -} - -/* ARGSUSED */ -static RETSIGTYPE -mabort(int signo) -{ - int ointer; - - printf("\n"); - fflush(stdout); - if (mflag && fromatty) { - ointer = interactive; - interactive = 1; - if (confirm("Continue with", mname)) { - interactive = ointer; - longjmp(jabort,0); - } - interactive = ointer; - } - mflag = 0; - longjmp(jabort,0); -} - -/* - * Send multiple files. - */ -void -mput(int argc, char **argv) -{ - int i; - RETSIGTYPE (*oldintr)(int); - int ointer; - char *tp; - - if (argc < 2 && !another(&argc, &argv, "local-files")) { - printf("usage: %s local-files\n", argv[0]); - code = -1; - return; - } - mname = argv[0]; - mflag = 1; - oldintr = signal(SIGINT, mabort); - setjmp(jabort); - if (proxy) { - char *cp, *tp2, tmpbuf[MaxPathLen]; - - while ((cp = remglob(argv,0)) != NULL) { - if (*cp == 0) { - mflag = 0; - continue; - } - if (mflag && confirm(argv[0], cp)) { - tp = cp; - if (mcase) { - while (*tp && !islower((unsigned char)*tp)) { - tp++; - } - if (!*tp) { - tp = cp; - tp2 = tmpbuf; - while ((*tp2 = *tp) != '\0') { - if (isupper((unsigned char)*tp2)) { - *tp2 = 'a' + *tp2 - 'A'; - } - tp++; - tp2++; - } - } - tp = tmpbuf; - } - if (ntflag) { - tp = dotrans(tp); - } - if (mapflag) { - tp = domap(tp); - } - sendrequest((sunique) ? "STOU" : "STOR", - cp, tp, - curtype == TYPE_I ? "rb" : "r", - cp != tp || !interactive); - if (!mflag && fromatty) { - ointer = interactive; - interactive = 1; - if (confirm("Continue with","mput")) { - mflag++; - } - interactive = ointer; - } - } - } - signal(SIGINT, oldintr); - mflag = 0; - return; - } - for (i = 1; i < argc; i++) { - char **cpp; - glob_t gl; - int flags; - - if (!doglob) { - if (mflag && confirm(argv[0], argv[i])) { - tp = (ntflag) ? dotrans(argv[i]) : argv[i]; - tp = (mapflag) ? domap(tp) : tp; - sendrequest((sunique) ? "STOU" : "STOR", - argv[i], - curtype == TYPE_I ? "rb" : "r", - tp, tp != argv[i] || !interactive); - if (!mflag && fromatty) { - ointer = interactive; - interactive = 1; - if (confirm("Continue with","mput")) { - mflag++; - } - interactive = ointer; - } - } - continue; - } - - memset(&gl, 0, sizeof(gl)); - flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE; - if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) { - warnx("%s: not found", argv[i]); - globfree(&gl); - continue; - } - for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) { - if (mflag && confirm(argv[0], *cpp)) { - tp = (ntflag) ? dotrans(*cpp) : *cpp; - tp = (mapflag) ? domap(tp) : tp; - sendrequest((sunique) ? "STOU" : "STOR", - *cpp, tp, - curtype == TYPE_I ? "rb" : "r", - *cpp != tp || !interactive); - if (!mflag && fromatty) { - ointer = interactive; - interactive = 1; - if (confirm("Continue with","mput")) { - mflag++; - } - interactive = ointer; - } - } - } - globfree(&gl); - } - signal(SIGINT, oldintr); - mflag = 0; -} - -void -reget(int argc, char **argv) -{ - getit(argc, argv, 1, curtype == TYPE_I ? "r+wb" : "r+w"); -} - -void -get(int argc, char **argv) -{ - char *filemode; - - if (restart_point) { - if (curtype == TYPE_I) - filemode = "r+wb"; - else - filemode = "r+w"; - } else { - if (curtype == TYPE_I) - filemode = "wb"; - else - filemode = "w"; - } - - getit(argc, argv, 0, filemode); -} - -/* - * Receive one file. - */ -int -getit(int argc, char **argv, int restartit, char *filemode) -{ - int loc = 0; - int local_given = 1; - char *oldargv1, *oldargv2; - - if (argc == 2) { - argc++; - local_given = 0; - argv[2] = argv[1]; - loc++; - } - if ((argc < 2 && !another(&argc, &argv, "remote-file")) || - (argc < 3 && !another(&argc, &argv, "local-file"))) { - printf("usage: %s remote-file [ local-file ]\n", argv[0]); - code = -1; - return (0); - } - oldargv1 = argv[1]; - oldargv2 = argv[2]; - if (!globulize(&argv[2])) { - code = -1; - return (0); - } - if (loc && mcase) { - char *tp = argv[1], *tp2, tmpbuf[MaxPathLen]; - - while (*tp && !islower((unsigned char)*tp)) { - tp++; - } - if (!*tp) { - tp = argv[2]; - tp2 = tmpbuf; - while ((*tp2 = *tp) != '\0') { - if (isupper((unsigned char)*tp2)) { - *tp2 = 'a' + *tp2 - 'A'; - } - tp++; - tp2++; - } - argv[2] = tmpbuf; - } - } - if (loc && ntflag) - argv[2] = dotrans(argv[2]); - if (loc && mapflag) - argv[2] = domap(argv[2]); - if (restartit) { - struct stat stbuf; - int ret; - - ret = stat(argv[2], &stbuf); - if (restartit == 1) { - if (ret < 0) { - warn("local: %s", argv[2]); - return (0); - } - restart_point = stbuf.st_size; - } else if (ret == 0) { - int overbose; - int cmdret; - int yy, mo, day, hour, min, sec; - struct tm *tm; - time_t mtime = stbuf.st_mtime; - - overbose = verbose; - if (debug == 0) - verbose = -1; - cmdret = command("MDTM %s", argv[1]); - verbose = overbose; - if (cmdret != COMPLETE) { - printf("%s\n", reply_string); - return (0); - } - if (sscanf(reply_string, - "%*s %04d%02d%02d%02d%02d%02d", - &yy, &mo, &day, &hour, &min, &sec) - != 6) { - printf ("bad MDTM result\n"); - return (0); - } - - tm = gmtime(&mtime); - tm->tm_mon++; - tm->tm_year += 1900; - - if ((tm->tm_year > yy) || - (tm->tm_year == yy && - tm->tm_mon > mo) || - (tm->tm_mon == mo && - tm->tm_mday > day) || - (tm->tm_mday == day && - tm->tm_hour > hour) || - (tm->tm_hour == hour && - tm->tm_min > min) || - (tm->tm_min == min && - tm->tm_sec > sec)) - return (1); - } - } - - recvrequest("RETR", argv[2], argv[1], filemode, - argv[1] != oldargv1 || argv[2] != oldargv2, local_given); - restart_point = 0; - return (0); -} - -static int -suspicious_filename(const char *fn) -{ - return strstr(fn, "../") != NULL || *fn == '/'; -} - -/* - * Get multiple files. - */ -void -mget(int argc, char **argv) -{ - sighand oldintr; - int ch, ointer; - char *cp, *tp, *tp2, tmpbuf[MaxPathLen]; - - if (argc < 2 && !another(&argc, &argv, "remote-files")) { - printf("usage: %s remote-files\n", argv[0]); - code = -1; - return; - } - mname = argv[0]; - mflag = 1; - oldintr = signal(SIGINT, mabort); - setjmp(jabort); - while ((cp = remglob(argv,proxy)) != NULL) { - if (*cp == '\0') { - mflag = 0; - continue; - } - if (mflag && suspicious_filename(cp)) - printf("*** Suspicious filename: %s\n", cp); - if (mflag && confirm(argv[0], cp)) { - tp = cp; - if (mcase) { - for (tp2 = tmpbuf;(ch = (unsigned char)*tp++);) - *tp2++ = tolower(ch); - *tp2 = '\0'; - tp = tmpbuf; - } - if (ntflag) { - tp = dotrans(tp); - } - if (mapflag) { - tp = domap(tp); - } - recvrequest("RETR", tp, cp, - curtype == TYPE_I ? "wb" : "w", - tp != cp || !interactive, 0); - if (!mflag && fromatty) { - ointer = interactive; - interactive = 1; - if (confirm("Continue with","mget")) { - mflag++; - } - interactive = ointer; - } - } - } - signal(SIGINT,oldintr); - mflag = 0; -} - -char * -remglob(char **argv, int doswitch) -{ - char temp[16]; - static char buf[MaxPathLen]; - static FILE *ftemp = NULL; - static char **args; - int oldverbose, oldhash; - char *cp, *filemode; - - if (!mflag) { - if (!doglob) { - args = NULL; - } - else { - if (ftemp) { - fclose(ftemp); - ftemp = NULL; - } - } - return (NULL); - } - if (!doglob) { - if (args == NULL) - args = argv; - if ((cp = *++args) == NULL) - args = NULL; - return (cp); - } - if (ftemp == NULL) { - int fd; - strlcpy(temp, _PATH_TMP_XXX, sizeof(temp)); - fd = mkstemp(temp); - if(fd < 0){ - warn("unable to create temporary file %s", temp); - return NULL; - } - close(fd); - oldverbose = verbose, verbose = 0; - oldhash = hash, hash = 0; - if (doswitch) { - pswitch(!proxy); - } - for (filemode = "w"; *++argv != NULL; filemode = "a") - recvrequest ("NLST", temp, *argv, filemode, 0, 0); - if (doswitch) { - pswitch(!proxy); - } - verbose = oldverbose; hash = oldhash; - ftemp = fopen(temp, "r"); - unlink(temp); - if (ftemp == NULL) { - printf("can't find list of remote files, oops\n"); - return (NULL); - } - } - while(fgets(buf, sizeof (buf), ftemp)) { - if ((cp = strchr(buf, '\n')) != NULL) - *cp = '\0'; - if(!interactive && suspicious_filename(buf)){ - printf("Ignoring remote globbed file `%s'\n", buf); - continue; - } - return buf; - } - fclose(ftemp); - ftemp = NULL; - return (NULL); -} - -char * -onoff(int bool) -{ - - return (bool ? "on" : "off"); -} - -/* - * Show status. - */ -/*ARGSUSED*/ -void -status(int argc, char **argv) -{ - int i; - - if (connected) - printf("Connected to %s.\n", hostname); - else - printf("Not connected.\n"); - if (!proxy) { - pswitch(1); - if (connected) { - printf("Connected for proxy commands to %s.\n", hostname); - } - else { - printf("No proxy connection.\n"); - } - pswitch(0); - } - sec_status(); - printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n", - modename, typename, formname, structname); - printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", - onoff(verbose), onoff(bell), onoff(interactive), - onoff(doglob)); - printf("Store unique: %s; Receive unique: %s\n", onoff(sunique), - onoff(runique)); - printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag)); - if (ntflag) { - printf("Ntrans: (in) %s (out) %s\n", ntin,ntout); - } - else { - printf("Ntrans: off\n"); - } - if (mapflag) { - printf("Nmap: (in) %s (out) %s\n", mapin, mapout); - } - else { - printf("Nmap: off\n"); - } - printf("Hash mark printing: %s; Use of PORT cmds: %s\n", - onoff(hash), onoff(sendport)); - if (macnum > 0) { - printf("Macros:\n"); - for (i=0; i 1) { - val = atoi(argv[1]); - if (val < 0) { - printf("%s: bad debugging value.\n", argv[1]); - code = -1; - return; - } - } else - val = !debug; - debug = val; - if (debug) - options |= SO_DEBUG; - else - options &= ~SO_DEBUG; - printf("Debugging %s (debug=%d).\n", onoff(debug), debug); - code = debug > 0; -} - -/* - * Set current working directory - * on remote machine. - */ -void -cd(int argc, char **argv) -{ - - if (argc < 2 && !another(&argc, &argv, "remote-directory")) { - printf("usage: %s remote-directory\n", argv[0]); - code = -1; - return; - } - if (command("CWD %s", argv[1]) == ERROR && code == 500) { - if (verbose) - printf("CWD command not recognized, trying XCWD\n"); - command("XCWD %s", argv[1]); - } -} - -/* - * Set current working directory - * on local machine. - */ -void -lcd(int argc, char **argv) -{ - char buf[MaxPathLen]; - - if (argc < 2) - argc++, argv[1] = home; - if (argc != 2) { - printf("usage: %s local-directory\n", argv[0]); - code = -1; - return; - } - if (!globulize(&argv[1])) { - code = -1; - return; - } - if (chdir(argv[1]) < 0) { - warn("local: %s", argv[1]); - code = -1; - return; - } - if (getcwd(buf, sizeof(buf)) != NULL) - printf("Local directory now %s\n", buf); - else - warnx("getwd: %s", buf); - code = 0; -} - -/* - * Delete a single file. - */ -void -delete(int argc, char **argv) -{ - - if (argc < 2 && !another(&argc, &argv, "remote-file")) { - printf("usage: %s remote-file\n", argv[0]); - code = -1; - return; - } - command("DELE %s", argv[1]); -} - -/* - * Delete multiple files. - */ -void -mdelete(int argc, char **argv) -{ - sighand oldintr; - int ointer; - char *cp; - - if (argc < 2 && !another(&argc, &argv, "remote-files")) { - printf("usage: %s remote-files\n", argv[0]); - code = -1; - return; - } - mname = argv[0]; - mflag = 1; - oldintr = signal(SIGINT, mabort); - setjmp(jabort); - while ((cp = remglob(argv,0)) != NULL) { - if (*cp == '\0') { - mflag = 0; - continue; - } - if (mflag && confirm(argv[0], cp)) { - command("DELE %s", cp); - if (!mflag && fromatty) { - ointer = interactive; - interactive = 1; - if (confirm("Continue with", "mdelete")) { - mflag++; - } - interactive = ointer; - } - } - } - signal(SIGINT, oldintr); - mflag = 0; -} - -/* - * Rename a remote file. - */ -void -renamefile(int argc, char **argv) -{ - - if (argc < 2 && !another(&argc, &argv, "from-name")) - goto usage; - if (argc < 3 && !another(&argc, &argv, "to-name")) { -usage: - printf("%s from-name to-name\n", argv[0]); - code = -1; - return; - } - if (command("RNFR %s", argv[1]) == CONTINUE) - command("RNTO %s", argv[2]); -} - -/* - * Get a directory listing - * of remote files. - */ -void -ls(int argc, char **argv) -{ - char *cmd; - - if (argc < 2) - argc++, argv[1] = NULL; - if (argc < 3) - argc++, argv[2] = "-"; - if (argc > 3) { - printf("usage: %s remote-directory local-file\n", argv[0]); - code = -1; - return; - } - cmd = argv[0][0] == 'n' ? "NLST" : "LIST"; - if (strcmp(argv[2], "-") && !globulize(&argv[2])) { - code = -1; - return; - } - if (strcmp(argv[2], "-") && *argv[2] != '|') - if (!globulize(&argv[2]) || !confirm("output to local-file:", - argv[2])) { - code = -1; - return; - } - recvrequest(cmd, argv[2], argv[1], "w", 0, 1); -} - -/* - * Get a directory listing - * of multiple remote files. - */ -void -mls(int argc, char **argv) -{ - sighand oldintr; - int ointer, i; - char *cmd, filemode[2], *dest; - - if (argc < 2 && !another(&argc, &argv, "remote-files")) - goto usage; - if (argc < 3 && !another(&argc, &argv, "local-file")) { -usage: - printf("usage: %s remote-files local-file\n", argv[0]); - code = -1; - return; - } - dest = argv[argc - 1]; - argv[argc - 1] = NULL; - if (strcmp(dest, "-") && *dest != '|') - if (!globulize(&dest) || - !confirm("output to local-file:", dest)) { - code = -1; - return; - } - cmd = argv[0][1] == 'l' ? "NLST" : "LIST"; - mname = argv[0]; - mflag = 1; - oldintr = signal(SIGINT, mabort); - setjmp(jabort); - filemode[1] = '\0'; - for (i = 1; mflag && i < argc-1; ++i) { - *filemode = (i == 1) ? 'w' : 'a'; - recvrequest(cmd, dest, argv[i], filemode, 0, 1); - if (!mflag && fromatty) { - ointer = interactive; - interactive = 1; - if (confirm("Continue with", argv[0])) { - mflag ++; - } - interactive = ointer; - } - } - signal(SIGINT, oldintr); - mflag = 0; -} - -/* - * Do a shell escape - */ -/*ARGSUSED*/ -void -shell(int argc, char **argv) -{ - pid_t pid; - RETSIGTYPE (*old1)(int), (*old2)(int); - char shellnam[40], *shellpath, *namep; - int waitstatus; - - old1 = signal (SIGINT, SIG_IGN); - old2 = signal (SIGQUIT, SIG_IGN); - if ((pid = fork()) == 0) { - for (pid = 3; pid < 20; pid++) - close(pid); - signal(SIGINT, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - shellpath = getenv("SHELL"); - if (shellpath == NULL) - shellpath = _PATH_BSHELL; - namep = strrchr(shellpath, '/'); - if (namep == NULL) - namep = shellpath; - snprintf (shellnam, sizeof(shellnam), - "-%s", ++namep); - if (strcmp(namep, "sh") != 0) - shellnam[0] = '+'; - if (debug) { - printf ("%s\n", shellpath); - fflush (stdout); - } - if (argc > 1) { - execl(shellpath,shellnam,"-c",altarg,(char *)0); - } - else { - execl(shellpath,shellnam,(char *)0); - } - warn("%s", shellpath); - code = -1; - exit(1); - } - if (pid > 0) - while (waitpid(-1, &waitstatus, 0) != pid) - ; - signal(SIGINT, old1); - signal(SIGQUIT, old2); - if (pid == -1) { - warn("%s", "Try again later"); - code = -1; - } - else { - code = 0; - } -} - -/* - * Send new user information (re-login) - */ -void -user(int argc, char **argv) -{ - char acctstr[80]; - int n, aflag = 0; - char tmp[256]; - - if (argc < 2) - another(&argc, &argv, "username"); - if (argc < 2 || argc > 4) { - printf("usage: %s username [password] [account]\n", argv[0]); - code = -1; - return; - } - n = command("USER %s", argv[1]); - if (n == CONTINUE) { - if (argc < 3 ) { - UI_UTIL_read_pw_string (tmp, - sizeof(tmp), - "Password: ", 0); - argv[2] = tmp; - argc++; - } - n = command("PASS %s", argv[2]); - } - if (n == CONTINUE) { - if (argc < 4) { - printf("Account: "); fflush(stdout); - fgets(acctstr, sizeof(acctstr) - 1, stdin); - acctstr[strcspn(acctstr, "\r\n")] = '\0'; - argv[3] = acctstr; argc++; - } - n = command("ACCT %s", argv[3]); - aflag++; - } - if (n != COMPLETE) { - fprintf(stdout, "Login failed.\n"); - return; - } - if (!aflag && argc == 4) { - command("ACCT %s", argv[3]); - } -} - -/* - * Print working directory. - */ -/*VARARGS*/ -void -pwd(int argc, char **argv) -{ - int oldverbose = verbose; - - /* - * If we aren't verbose, this doesn't do anything! - */ - verbose = 1; - if (command("PWD") == ERROR && code == 500) { - printf("PWD command not recognized, trying XPWD\n"); - command("XPWD"); - } - verbose = oldverbose; -} - -/* - * Make a directory. - */ -void -makedir(int argc, char **argv) -{ - - if (argc < 2 && !another(&argc, &argv, "directory-name")) { - printf("usage: %s directory-name\n", argv[0]); - code = -1; - return; - } - if (command("MKD %s", argv[1]) == ERROR && code == 500) { - if (verbose) - printf("MKD command not recognized, trying XMKD\n"); - command("XMKD %s", argv[1]); - } -} - -/* - * Remove a directory. - */ -void -removedir(int argc, char **argv) -{ - - if (argc < 2 && !another(&argc, &argv, "directory-name")) { - printf("usage: %s directory-name\n", argv[0]); - code = -1; - return; - } - if (command("RMD %s", argv[1]) == ERROR && code == 500) { - if (verbose) - printf("RMD command not recognized, trying XRMD\n"); - command("XRMD %s", argv[1]); - } -} - -/* - * Send a line, verbatim, to the remote machine. - */ -void -quote(int argc, char **argv) -{ - - if (argc < 2 && !another(&argc, &argv, "command line to send")) { - printf("usage: %s line-to-send\n", argv[0]); - code = -1; - return; - } - quote1("", argc, argv); -} - -/* - * Send a SITE command to the remote machine. The line - * is sent verbatim to the remote machine, except that the - * word "SITE" is added at the front. - */ -void -site(int argc, char **argv) -{ - - if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) { - printf("usage: %s line-to-send\n", argv[0]); - code = -1; - return; - } - quote1("SITE ", argc, argv); -} - -/* - * Turn argv[1..argc) into a space-separated string, then prepend initial text. - * Send the result as a one-line command and get response. - */ -void -quote1(char *initial, int argc, char **argv) -{ - int i; - char buf[BUFSIZ]; /* must be >= sizeof(line) */ - - strlcpy(buf, initial, sizeof(buf)); - for(i = 1; i < argc; i++) { - if(i > 1) - strlcat(buf, " ", sizeof(buf)); - strlcat(buf, argv[i], sizeof(buf)); - } - if (command("%s", buf) == PRELIM) { - while (getreply(0) == PRELIM) - continue; - } -} - -void -do_chmod(int argc, char **argv) -{ - - if (argc < 2 && !another(&argc, &argv, "mode")) - goto usage; - if (argc < 3 && !another(&argc, &argv, "file-name")) { -usage: - printf("usage: %s mode file-name\n", argv[0]); - code = -1; - return; - } - command("SITE CHMOD %s %s", argv[1], argv[2]); -} - -void -do_umask(int argc, char **argv) -{ - int oldverbose = verbose; - - verbose = 1; - command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]); - verbose = oldverbose; -} - -void -ftp_idle(int argc, char **argv) -{ - int oldverbose = verbose; - - verbose = 1; - command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]); - verbose = oldverbose; -} - -/* - * Ask the other side for help. - */ -void -rmthelp(int argc, char **argv) -{ - int oldverbose = verbose; - - verbose = 1; - command(argc == 1 ? "HELP" : "HELP %s", argv[1]); - verbose = oldverbose; -} - -/* - * Terminate session and exit. - */ -/*VARARGS*/ -void -quit(int argc, char **argv) -{ - - if (connected) - disconnect(0, 0); - pswitch(1); - if (connected) { - disconnect(0, 0); - } - exit(0); -} - -/* - * Terminate session, but don't exit. - */ -void -disconnect(int argc, char **argv) -{ - - if (!connected) - return; - command("QUIT"); - if (cout) { - fclose(cout); - } - cout = NULL; - connected = 0; - sec_end(); - data = -1; - if (!proxy) { - macnum = 0; - } -} - -int -confirm(char *cmd, char *file) -{ - char buf[BUFSIZ]; - - if (!interactive) - return (1); - printf("%s %s? ", cmd, file); - fflush(stdout); - if (fgets(buf, sizeof buf, stdin) == NULL) - return (0); - return (*buf == 'y' || *buf == 'Y'); -} - -void -fatal(char *msg) -{ - - errx(1, "%s", msg); -} - -/* - * Glob a local file name specification with - * the expectation of a single return value. - * Can't control multiple values being expanded - * from the expression, we return only the first. - */ -int -globulize(char **cpp) -{ - glob_t gl; - int flags; - - if (!doglob) - return (1); - - flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE; - memset(&gl, 0, sizeof(gl)); - if (glob(*cpp, flags, NULL, &gl) || - gl.gl_pathc == 0) { - warnx("%s: not found", *cpp); - globfree(&gl); - return (0); - } - *cpp = strdup(gl.gl_pathv[0]); /* XXX - wasted memory */ - globfree(&gl); - return (1); -} - -void -account(int argc, char **argv) -{ - char acctstr[50]; - - if (argc > 1) { - ++argv; - --argc; - strlcpy (acctstr, *argv, sizeof(acctstr)); - while (argc > 1) { - --argc; - ++argv; - strlcat(acctstr, *argv, sizeof(acctstr)); - } - } - else { - UI_UTIL_read_pw_string(acctstr, sizeof(acctstr), "Account:", 0); - } - command("ACCT %s", acctstr); -} - -jmp_buf abortprox; - -static RETSIGTYPE -proxabort(int sig) -{ - - if (!proxy) { - pswitch(1); - } - if (connected) { - proxflag = 1; - } - else { - proxflag = 0; - } - pswitch(0); - longjmp(abortprox,1); -} - -void -doproxy(int argc, char **argv) -{ - struct cmd *c; - RETSIGTYPE (*oldintr)(int); - - if (argc < 2 && !another(&argc, &argv, "command")) { - printf("usage: %s command\n", argv[0]); - code = -1; - return; - } - c = getcmd(argv[1]); - if (c == (struct cmd *) -1) { - printf("?Ambiguous command\n"); - fflush(stdout); - code = -1; - return; - } - if (c == 0) { - printf("?Invalid command\n"); - fflush(stdout); - code = -1; - return; - } - if (!c->c_proxy) { - printf("?Invalid proxy command\n"); - fflush(stdout); - code = -1; - return; - } - if (setjmp(abortprox)) { - code = -1; - return; - } - oldintr = signal(SIGINT, proxabort); - pswitch(1); - if (c->c_conn && !connected) { - printf("Not connected\n"); - fflush(stdout); - pswitch(0); - signal(SIGINT, oldintr); - code = -1; - return; - } - (*c->c_handler)(argc-1, argv+1); - if (connected) { - proxflag = 1; - } - else { - proxflag = 0; - } - pswitch(0); - signal(SIGINT, oldintr); -} - -void -setcase(int argc, char **argv) -{ - - mcase = !mcase; - printf("Case mapping %s.\n", onoff(mcase)); - code = mcase; -} - -void -setcr(int argc, char **argv) -{ - - crflag = !crflag; - printf("Carriage Return stripping %s.\n", onoff(crflag)); - code = crflag; -} - -void -setntrans(int argc, char **argv) -{ - if (argc == 1) { - ntflag = 0; - printf("Ntrans off.\n"); - code = ntflag; - return; - } - ntflag++; - code = ntflag; - strlcpy (ntin, argv[1], 17); - if (argc == 2) { - ntout[0] = '\0'; - return; - } - strlcpy (ntout, argv[2], 17); -} - -char * -dotrans(char *name) -{ - static char new[MaxPathLen]; - char *cp1, *cp2 = new; - int i, ostop, found; - - for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++) - continue; - for (cp1 = name; *cp1; cp1++) { - found = 0; - for (i = 0; *(ntin + i) && i < 16; i++) { - if (*cp1 == *(ntin + i)) { - found++; - if (i < ostop) { - *cp2++ = *(ntout + i); - } - break; - } - } - if (!found) { - *cp2++ = *cp1; - } - } - *cp2 = '\0'; - return (new); -} - -void -setnmap(int argc, char **argv) -{ - char *cp; - - if (argc == 1) { - mapflag = 0; - printf("Nmap off.\n"); - code = mapflag; - return; - } - if (argc < 3 && !another(&argc, &argv, "mapout")) { - printf("Usage: %s [mapin mapout]\n",argv[0]); - code = -1; - return; - } - mapflag = 1; - code = 1; - cp = strchr(altarg, ' '); - if (cp == NULL) { - printf("Usage: %s missing space\n",argv[0]); - code = -1; - return; - } - if (proxy) { - while(*++cp == ' ') - continue; - altarg = cp; - cp = strchr(altarg, ' '); - } - *cp = '\0'; - strlcpy(mapin, altarg, MaxPathLen); - while (*++cp == ' ') - continue; - strlcpy(mapout, cp, MaxPathLen); -} - -char * -domap(char *name) -{ - static char new[MaxPathLen]; - char *cp1 = name, *cp2 = mapin; - char *tp[9], *te[9]; - int i, toks[9], toknum = 0, match = 1; - - for (i=0; i < 9; ++i) { - toks[i] = 0; - } - while (match && *cp1 && *cp2) { - switch (*cp2) { - case '\\': - if (*++cp2 != *cp1) { - match = 0; - } - break; - case '$': - if (*(cp2+1) >= '1' && (*cp2+1) <= '9') { - if (*cp1 != *(++cp2+1)) { - toks[toknum = *cp2 - '1']++; - tp[toknum] = cp1; - while (*++cp1 && *(cp2+1) - != *cp1); - te[toknum] = cp1; - } - cp2++; - break; - } - /* FALLTHROUGH */ - default: - if (*cp2 != *cp1) { - match = 0; - } - break; - } - if (match && *cp1) { - cp1++; - } - if (match && *cp2) { - cp2++; - } - } - if (!match && *cp1) /* last token mismatch */ - { - toks[toknum] = 0; - } - cp1 = new; - *cp1 = '\0'; - cp2 = mapout; - while (*cp2) { - match = 0; - switch (*cp2) { - case '\\': - if (*(cp2 + 1)) { - *cp1++ = *++cp2; - } - break; - case '[': -LOOP: - if (*++cp2 == '$' && isdigit((unsigned char)*(cp2+1))) { - if (*++cp2 == '0') { - char *cp3 = name; - - while (*cp3) { - *cp1++ = *cp3++; - } - match = 1; - } - else if (toks[toknum = *cp2 - '1']) { - char *cp3 = tp[toknum]; - - while (cp3 != te[toknum]) { - *cp1++ = *cp3++; - } - match = 1; - } - } - else { - while (*cp2 && *cp2 != ',' && - *cp2 != ']') { - if (*cp2 == '\\') { - cp2++; - } - else if (*cp2 == '$' && - isdigit((unsigned char)*(cp2+1))) { - if (*++cp2 == '0') { - char *cp3 = name; - - while (*cp3) { - *cp1++ = *cp3++; - } - } - else if (toks[toknum = - *cp2 - '1']) { - char *cp3=tp[toknum]; - - while (cp3 != - te[toknum]) { - *cp1++ = *cp3++; - } - } - } - else if (*cp2) { - *cp1++ = *cp2++; - } - } - if (!*cp2) { - printf("nmap: unbalanced brackets\n"); - return (name); - } - match = 1; - cp2--; - } - if (match) { - while (*++cp2 && *cp2 != ']') { - if (*cp2 == '\\' && *(cp2 + 1)) { - cp2++; - } - } - if (!*cp2) { - printf("nmap: unbalanced brackets\n"); - return (name); - } - break; - } - switch (*++cp2) { - case ',': - goto LOOP; - case ']': - break; - default: - cp2--; - goto LOOP; - } - break; - case '$': - if (isdigit((unsigned char)*(cp2 + 1))) { - if (*++cp2 == '0') { - char *cp3 = name; - - while (*cp3) { - *cp1++ = *cp3++; - } - } - else if (toks[toknum = *cp2 - '1']) { - char *cp3 = tp[toknum]; - - while (cp3 != te[toknum]) { - *cp1++ = *cp3++; - } - } - break; - } - /* intentional drop through */ - default: - *cp1++ = *cp2; - break; - } - cp2++; - } - *cp1 = '\0'; - if (!*new) { - return (name); - } - return (new); -} - -void -setpassive(int argc, char **argv) -{ - - passivemode = !passivemode; - printf("Passive mode %s.\n", onoff(passivemode)); - code = passivemode; -} - -void -setsunique(int argc, char **argv) -{ - - sunique = !sunique; - printf("Store unique %s.\n", onoff(sunique)); - code = sunique; -} - -void -setrunique(int argc, char **argv) -{ - - runique = !runique; - printf("Receive unique %s.\n", onoff(runique)); - code = runique; -} - -/* change directory to perent directory */ -void -cdup(int argc, char **argv) -{ - - if (command("CDUP") == ERROR && code == 500) { - if (verbose) - printf("CDUP command not recognized, trying XCUP\n"); - command("XCUP"); - } -} - -/* restart transfer at specific point */ -void -restart(int argc, char **argv) -{ - - if (argc != 2) - printf("restart: offset not specified\n"); - else { - restart_point = atol(argv[1]); - printf("restarting at %ld. %s\n", (long)restart_point, - "execute get, put or append to initiate transfer"); - } -} - -/* show remote system type */ -void -syst(int argc, char **argv) -{ - - command("SYST"); -} - -void -macdef(int argc, char **argv) -{ - char *tmp; - int c; - - if (macnum == 16) { - printf("Limit of 16 macros have already been defined\n"); - code = -1; - return; - } - if (argc < 2 && !another(&argc, &argv, "macro name")) { - printf("Usage: %s macro_name\n",argv[0]); - code = -1; - return; - } - if (interactive) { - printf("Enter macro line by line, terminating it with a null line\n"); - } - strlcpy(macros[macnum].mac_name, - argv[1], - sizeof(macros[macnum].mac_name)); - if (macnum == 0) { - macros[macnum].mac_start = macbuf; - } - else { - macros[macnum].mac_start = macros[macnum - 1].mac_end + 1; - } - tmp = macros[macnum].mac_start; - while (tmp != macbuf+4096) { - if ((c = getchar()) == EOF) { - printf("macdef:end of file encountered\n"); - code = -1; - return; - } - if ((*tmp = c) == '\n') { - if (tmp == macros[macnum].mac_start) { - macros[macnum++].mac_end = tmp; - code = 0; - return; - } - if (*(tmp-1) == '\0') { - macros[macnum++].mac_end = tmp - 1; - code = 0; - return; - } - *tmp = '\0'; - } - tmp++; - } - while (1) { - while ((c = getchar()) != '\n' && c != EOF) - /* LOOP */; - if (c == EOF || getchar() == '\n') { - printf("Macro not defined - 4k buffer exceeded\n"); - code = -1; - return; - } - } -} - -/* - * get size of file on remote machine - */ -void -sizecmd(int argc, char **argv) -{ - - if (argc < 2 && !another(&argc, &argv, "filename")) { - printf("usage: %s filename\n", argv[0]); - code = -1; - return; - } - command("SIZE %s", argv[1]); -} - -/* - * get last modification time of file on remote machine - */ -void -modtime(int argc, char **argv) -{ - int overbose; - - if (argc < 2 && !another(&argc, &argv, "filename")) { - printf("usage: %s filename\n", argv[0]); - code = -1; - return; - } - overbose = verbose; - if (debug == 0) - verbose = -1; - if (command("MDTM %s", argv[1]) == COMPLETE) { - int yy, mo, day, hour, min, sec; - sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo, - &day, &hour, &min, &sec); - /* might want to print this in local time */ - printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1], - mo, day, yy, hour, min, sec); - } else - printf("%s\n", reply_string); - verbose = overbose; -} - -/* - * show status on reomte machine - */ -void -rmtstatus(int argc, char **argv) -{ - - command(argc > 1 ? "STAT %s" : "STAT" , argv[1]); -} - -/* - * get file if modtime is more recent than current file - */ -void -newer(int argc, char **argv) -{ - - if (getit(argc, argv, -1, curtype == TYPE_I ? "wb" : "w")) - printf("Local file \"%s\" is newer than remote file \"%s\"\n", - argv[2], argv[1]); -} - -void -klist(int argc, char **argv) -{ - int ret; - if(argc != 1){ - printf("usage: %s\n", argv[0]); - code = -1; - return; - } - - ret = command("SITE KLIST"); - code = (ret == COMPLETE); -} diff --git a/appl/ftp/ftp/cmdtab.c b/appl/ftp/ftp/cmdtab.c deleted file mode 100644 index d4483c510..000000000 --- a/appl/ftp/ftp/cmdtab.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 1985, 1989, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "ftp_locl.h" - -/* - * User FTP -- Command Tables. - */ - -char accounthelp[] = "send account command to remote server"; -char appendhelp[] = "append to a file"; -char asciihelp[] = "set ascii transfer type"; -char beephelp[] = "beep when command completed"; -char binaryhelp[] = "set binary transfer type"; -char casehelp[] = "toggle mget upper/lower case id mapping"; -char cdhelp[] = "change remote working directory"; -char cduphelp[] = "change remote working directory to parent directory"; -char chmodhelp[] = "change file permissions of remote file"; -char connecthelp[] = "connect to remote tftp"; -char crhelp[] = "toggle carriage return stripping on ascii gets"; -char deletehelp[] = "delete remote file"; -char debughelp[] = "toggle/set debugging mode"; -char dirhelp[] = "list contents of remote directory"; -char disconhelp[] = "terminate ftp session"; -char domachelp[] = "execute macro"; -char formhelp[] = "set file transfer format"; -char globhelp[] = "toggle metacharacter expansion of local file names"; -char hashhelp[] = "toggle printing `#' for each buffer transferred"; -char helphelp[] = "print local help information"; -char idlehelp[] = "get (set) idle timer on remote side"; -char lcdhelp[] = "change local working directory"; -char lshelp[] = "list contents of remote directory"; -char macdefhelp[] = "define a macro"; -char mdeletehelp[] = "delete multiple files"; -char mdirhelp[] = "list contents of multiple remote directories"; -char mgethelp[] = "get multiple files"; -char mkdirhelp[] = "make directory on the remote machine"; -char mlshelp[] = "list contents of multiple remote directories"; -char modtimehelp[] = "show last modification time of remote file"; -char modehelp[] = "set file transfer mode"; -char mputhelp[] = "send multiple files"; -char newerhelp[] = "get file if remote file is newer than local file "; -char nlisthelp[] = "nlist contents of remote directory"; -char nmaphelp[] = "set templates for default file name mapping"; -char ntranshelp[] = "set translation table for default file name mapping"; -char porthelp[] = "toggle use of PORT cmd for each data connection"; -char prompthelp[] = "force interactive prompting on multiple commands"; -char proxyhelp[] = "issue command on alternate connection"; -char pwdhelp[] = "print working directory on remote machine"; -char quithelp[] = "terminate ftp session and exit"; -char quotehelp[] = "send arbitrary ftp command"; -char receivehelp[] = "receive file"; -char regethelp[] = "get file restarting at end of local file"; -char remotehelp[] = "get help from remote server"; -char renamehelp[] = "rename file"; -char restarthelp[]= "restart file transfer at bytecount"; -char rmdirhelp[] = "remove directory on the remote machine"; -char rmtstatushelp[]="show status of remote machine"; -char runiquehelp[] = "toggle store unique for local files"; -char resethelp[] = "clear queued command replies"; -char sendhelp[] = "send one file"; -char passivehelp[] = "enter passive transfer mode"; -char sitehelp[] = "send site specific command to remote server\n\t\tTry \"rhelp site\" or \"site help\" for more information"; -char shellhelp[] = "escape to the shell"; -char sizecmdhelp[] = "show size of remote file"; -char statushelp[] = "show current status"; -char structhelp[] = "set file transfer structure"; -char suniquehelp[] = "toggle store unique on remote machine"; -char systemhelp[] = "show remote system type"; -char tenexhelp[] = "set tenex file transfer type"; -char tracehelp[] = "toggle packet tracing"; -char typehelp[] = "set file transfer type"; -char umaskhelp[] = "get (set) umask on remote side"; -char userhelp[] = "send new user information"; -char verbosehelp[] = "toggle verbose mode"; - -char prothelp[] = "set protection level"; -char prothelp_c[] = "set command protection level"; -#if defined(KRB5) -char klisthelp[] = "show remote tickets"; -#endif -#if defined(KRB5) -char afsloghelp[] = "obtain remote AFS tokens"; -#endif - -struct cmd cmdtab[] = { - { "!", shellhelp, 0, 0, 0, shell }, - { "$", domachelp, 1, 0, 0, domacro }, - { "account", accounthelp, 0, 1, 1, account}, - { "append", appendhelp, 1, 1, 1, put }, - { "ascii", asciihelp, 0, 1, 1, setascii }, - { "bell", beephelp, 0, 0, 0, setbell }, - { "binary", binaryhelp, 0, 1, 1, setbinary }, - { "bye", quithelp, 0, 0, 0, quit }, - { "case", casehelp, 0, 0, 1, setcase }, - { "cd", cdhelp, 0, 1, 1, cd }, - { "cdup", cduphelp, 0, 1, 1, cdup }, - { "chmod", chmodhelp, 0, 1, 1, do_chmod }, - { "close", disconhelp, 0, 1, 1, disconnect }, - { "cr", crhelp, 0, 0, 0, setcr }, - { "delete", deletehelp, 0, 1, 1, delete }, - { "debug", debughelp, 0, 0, 0, setdebug }, - { "dir", dirhelp, 1, 1, 1, ls }, - { "disconnect", disconhelp, 0, 1, 1, disconnect }, - { "form", formhelp, 0, 1, 1, setform }, - { "get", receivehelp, 1, 1, 1, get }, - { "glob", globhelp, 0, 0, 0, setglob }, - { "hash", hashhelp, 0, 0, 0, sethash }, - { "help", helphelp, 0, 0, 1, help }, - { "idle", idlehelp, 0, 1, 1, ftp_idle }, - { "image", binaryhelp, 0, 1, 1, setbinary }, - { "lcd", lcdhelp, 0, 0, 0, lcd }, - { "ls", lshelp, 1, 1, 1, ls }, - { "macdef", macdefhelp, 0, 0, 0, macdef }, - { "mdelete", mdeletehelp, 1, 1, 1, mdelete }, - { "mdir", mdirhelp, 1, 1, 1, mls }, - { "mget", mgethelp, 1, 1, 1, mget }, - { "mkdir", mkdirhelp, 0, 1, 1, makedir }, - { "mls", mlshelp, 1, 1, 1, mls }, - { "mode", modehelp, 0, 1, 1, setftmode }, - { "modtime", modtimehelp, 0, 1, 1, modtime }, - { "mput", mputhelp, 1, 1, 1, mput }, - { "newer", newerhelp, 1, 1, 1, newer }, - { "nmap", nmaphelp, 0, 0, 1, setnmap }, - { "nlist", nlisthelp, 1, 1, 1, ls }, - { "ntrans", ntranshelp, 0, 0, 1, setntrans }, - { "open", connecthelp, 0, 0, 1, setpeer }, - { "passive", passivehelp, 0, 0, 0, setpassive }, - { "prompt", prompthelp, 0, 0, 0, setprompt }, - { "proxy", proxyhelp, 0, 0, 1, doproxy }, - { "sendport", porthelp, 0, 0, 0, setport }, - { "put", sendhelp, 1, 1, 1, put }, - { "pwd", pwdhelp, 0, 1, 1, pwd }, - { "quit", quithelp, 0, 0, 0, quit }, - { "quote", quotehelp, 1, 1, 1, quote }, - { "recv", receivehelp, 1, 1, 1, get }, - { "reget", regethelp, 1, 1, 1, reget }, - { "rstatus", rmtstatushelp, 0, 1, 1, rmtstatus }, - { "rhelp", remotehelp, 0, 1, 1, rmthelp }, - { "rename", renamehelp, 0, 1, 1, renamefile }, - { "reset", resethelp, 0, 1, 1, reset }, - { "restart", restarthelp, 1, 1, 1, restart }, - { "rmdir", rmdirhelp, 0, 1, 1, removedir }, - { "runique", runiquehelp, 0, 0, 1, setrunique }, - { "send", sendhelp, 1, 1, 1, put }, - { "site", sitehelp, 0, 1, 1, site }, - { "size", sizecmdhelp, 1, 1, 1, sizecmd }, - { "status", statushelp, 0, 0, 1, status }, - { "struct", structhelp, 0, 1, 1, setstruct }, - { "system", systemhelp, 0, 1, 1, syst }, - { "sunique", suniquehelp, 0, 0, 1, setsunique }, - { "tenex", tenexhelp, 0, 1, 1, settenex }, - { "trace", tracehelp, 0, 0, 0, settrace }, - { "type", typehelp, 0, 1, 1, settype }, - { "user", userhelp, 0, 1, 1, user }, - { "umask", umaskhelp, 0, 1, 1, do_umask }, - { "verbose", verbosehelp, 0, 0, 0, setverbose }, - { "?", helphelp, 0, 0, 1, help }, - - { "protect", prothelp, 0, 1, 0, sec_prot }, - /* what MIT uses */ - { "cprotect", prothelp_c, 0, 1, 1, sec_prot_command }, -#if defined(KRB5) - { "klist", klisthelp, 0, 1, 0, klist }, -#endif -#if defined(KRB5) - { "afslog", afsloghelp, 0, 1, 0, afslog }, -#endif - - { 0 }, -}; - -int NCMDS = (sizeof (cmdtab) / sizeof (cmdtab[0])) - 1; diff --git a/appl/ftp/ftp/domacro.c b/appl/ftp/ftp/domacro.c deleted file mode 100644 index 4311d69e0..000000000 --- a/appl/ftp/ftp/domacro.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 1985, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "ftp_locl.h" -RCSID("$Id$"); - -void -domacro(int argc, char **argv) -{ - int i, j, count = 2, loopflg = 0; - char *cp1, *cp2, line2[200]; - struct cmd *c; - - if (argc < 2 && !another(&argc, &argv, "macro name")) { - printf("Usage: %s macro_name.\n", argv[0]); - code = -1; - return; - } - for (i = 0; i < macnum; ++i) { - if (!strncmp(argv[1], macros[i].mac_name, 9)) { - break; - } - } - if (i == macnum) { - printf("'%s' macro not found.\n", argv[1]); - code = -1; - return; - } - strlcpy(line2, line, sizeof(line2)); -TOP: - cp1 = macros[i].mac_start; - while (cp1 != macros[i].mac_end) { - while (isspace((unsigned char)*cp1)) { - cp1++; - } - cp2 = line; - while (*cp1 != '\0') { - size_t len; - switch(*cp1) { - case '\\': - if (line + sizeof(line) - 2 < cp2) - goto out; - *cp2++ = *++cp1; - break; - case '$': - if (isdigit((unsigned char)*(cp1+1))) { - j = 0; - while (isdigit((unsigned char)*++cp1)) { - j = 10*j + *cp1 - '0'; - } - cp1--; - if (argc - 2 >= j) { - len = sizeof(line) - (cp2 - line) - 1; - if (strlcpy(cp2, argv[j+1], len) >= len) - goto out; - cp2 += strlen(argv[j+1]); - } - break; - } - if (*(cp1+1) == 'i') { - loopflg = 1; - cp1++; - if (count < argc) { - len = sizeof(line) - (cp2 - line) - 1; - if (strlcpy(cp2, argv[count], len) >= len) - goto out; - cp2 += strlen(argv[count]); - } - break; - } - /* intentional drop through */ - default: - if (line + sizeof(line) - 2 < cp2) - goto out; - *cp2++ = *cp1; - break; - } - if (*cp1 != '\0') { - cp1++; - } - } - out: - *cp2 = '\0'; - makeargv(); - c = getcmd(margv[0]); - if (c == (struct cmd *)-1) { - printf("?Ambiguous command\n"); - code = -1; - } - else if (c == 0) { - printf("?Invalid command\n"); - code = -1; - } - else if (c->c_conn && !connected) { - printf("Not connected.\n"); - code = -1; - } - else { - if (verbose) { - printf("%s\n",line); - } - (*c->c_handler)(margc, margv); - if (bell && c->c_bell) { - putchar('\007'); - } - strlcpy(line, line2, sizeof(line)); - makeargv(); - argc = margc; - argv = margv; - } - if (cp1 != macros[i].mac_end) { - cp1++; - } - } - if (loopflg && ++count < argc) { - goto TOP; - } -} diff --git a/appl/ftp/ftp/extern.h b/appl/ftp/ftp/extern.h deleted file mode 100644 index ee5184957..000000000 --- a/appl/ftp/ftp/extern.h +++ /dev/null @@ -1,174 +0,0 @@ -/*- - * Copyright (c) 1994 The Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)extern.h 8.3 (Berkeley) 10/9/94 - */ - -/* $Id$ */ - -#include -#include -#ifdef TIME_WITH_SYS_TIME -#include -#include -#elif defined(HAVE_SYS_TIME_H) -#include -#else -#include -#endif -#ifdef HAVE_SYS_SELECT_H -#include -#endif - -void abort_remote (FILE *); -void abortpt (int); -void abortrecv (int); -void account (int, char **); -int another (int *, char ***, char *); -void blkfree (char **); -void cd (int, char **); -void cdup (int, char **); -void changetype (int, int); -void cmdabort (int); -void cmdscanner (int); -int command (char *fmt, ...) - __attribute__ ((format (printf, 1,2))); -int confirm (char *, char *); -FILE *dataconn (const char *); -void delete (int, char **); -void disconnect (int, char **); -void do_chmod (int, char **); -void do_umask (int, char **); -void domacro (int, char **); -char *domap (char *); -void doproxy (int, char **); -char *dotrans (char *); -int empty (fd_set *, int); -void fatal (char *); -void get (int, char **); -struct cmd *getcmd (char *); -int getit (int, char **, int, char *); -int getreply (int); -int globulize (char **); -char *gunique (char *); -void help (int, char **); -char *hookup (const char *, int); -void ftp_idle (int, char **); -int initconn (void); -void intr (int); -void lcd (int, char **); -int login (char *); -RETSIGTYPE lostpeer (int); -void ls (int, char **); -void macdef (int, char **); -void makeargv (void); -void makedir (int, char **); -void mdelete (int, char **); -void mget (int, char **); -void mls (int, char **); -void modtime (int, char **); -void mput (int, char **); -char *onoff (int); -void newer (int, char **); -void proxtrans (char *, char *, char *); -void psabort (int); -void pswitch (int); -void ptransfer (char *, long, struct timeval *, struct timeval *); -void put (int, char **); -void pwd (int, char **); -void quit (int, char **); -void quote (int, char **); -void quote1 (char *, int, char **); -void recvrequest (char *, char *, char *, char *, int, int); -void reget (int, char **); -char *remglob (char **, int); -void removedir (int, char **); -void renamefile (int, char **); -void reset (int, char **); -void restart (int, char **); -void rmthelp (int, char **); -void rmtstatus (int, char **); -int ruserpassword (char *, char **, char **, char **); -void sendrequest (char *, char *, char *, char *, int); -void setascii (int, char **); -void setbell (int, char **); -void setbinary (int, char **); -void setcase (int, char **); -void setcr (int, char **); -void setdebug (int, char **); -void setform (int, char **); -void setftmode (int, char **); -void setglob (int, char **); -void sethash (int, char **); -void setnmap (int, char **); -void setntrans (int, char **); -void setpassive (int, char **); -void setpeer (int, char **); -void setport (int, char **); -void setprompt (int, char **); -void setrunique (int, char **); -void setstruct (int, char **); -void setsunique (int, char **); -void settenex (int, char **); -void settrace (int, char **); -void settype (int, char **); -void setverbose (int, char **); -void shell (int, char **); -void site (int, char **); -void sizecmd (int, char **); -char *slurpstring (void); -void status (int, char **); -void syst (int, char **); -void tvsub (struct timeval *, struct timeval *, struct timeval *); -void user (int, char **); - -extern jmp_buf abortprox; -extern int abrtflag; -extern struct cmd cmdtab[]; -extern FILE *cout; -extern int data; -extern char *home; -extern jmp_buf jabort; -extern int proxy; -extern char reply_string[]; -extern off_t restart_point; -extern int NCMDS; - -extern char username[32]; -extern char myhostname[]; -extern char *mydomain; - -void afslog (int, char **); -void kauth (int, char **); -void kdestroy (int, char **); -void klist (int, char **); -void krbtkfile (int, char **); diff --git a/appl/ftp/ftp/ftp.1 b/appl/ftp/ftp/ftp.1 deleted file mode 100644 index 5b8b8f642..000000000 --- a/appl/ftp/ftp/ftp.1 +++ /dev/null @@ -1,1211 +0,0 @@ -.\" $NetBSD: ftp.1,v 1.11 1995/09/08 01:06:24 tls Exp $ -.\" -.\" Copyright (c) 1985, 1989, 1990, 1993 -.\" The Regents of the University of California. All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. -.\" 4. Neither the name of the University nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" @(#)ftp.1 8.3 (Berkeley) 10/9/94 -.\" -.Dd March 23, 2006 -.Dt FTP 1 -.Os BSD 4.2 -.Sh NAME -.Nm ftp -.Nd -.Tn ARPANET -file transfer program -.Sh SYNOPSIS -.Nm ftp -.Op Fl K -.Op Fl d -.Op Fl g -.Op Fl i -.Op Fl l -.Op Fl n -.Op Fl p -.Op Fl t -.Op Fl v -.Op Fl x -.Op Fl -no-gss-bindings -.Op Fl -no-gss-delegate -.Op Ar host -.Sh DESCRIPTION -.Nm -is the user interface to the -.Tn ARPANET -standard File Transfer Protocol. -The program allows a user to transfer files to and from a -remote network site. -.Pp -Modifications have been made so that it almost follows the FTP -Security Extensions, RFC 2228. -.Pp -Options may be specified at the command line, or to the -command interpreter. -.Bl -tag -width flag -.It Fl K -Disable Kerberos authentication. -.It Fl t -Enables packet tracing. -.It Fl v -Verbose option forces -.Nm ftp -to show all responses from the remote server, as well -as report on data transfer statistics. -.It Fl n -Restrains -.Nm ftp -from attempting \*(Lqauto-login\*(Rq upon initial connection. -If auto-login is enabled, -.Nm ftp -will check the -.Pa .netrc -(see below) file in the user's home directory for an entry describing -an account on the remote machine. -If no entry exists, -.Nm ftp -will prompt for the remote machine login name (default is the user -identity on the local machine), and, if necessary, prompt for a password -and an account with which to login. -.It Fl i -Turns off interactive prompting during -multiple file transfers. -.It Fl p -Turn on passive mode. -.It Fl d -Enables debugging. -.It Fl g -Disables file name globbing. - .It Fl -no-gss-bindings -Don't use GSS-API bindings when talking to peer. IP addresses will not -be checked to ensure they match. -.It Fl -no-gss-delegate -Disable delegation of GSSAPI credentials. -.It Fl l -Disables command line editing. -.It Fl x -Encrypt command and data channel. -.El -.Pp -The client host with which -.Nm ftp -is to communicate may be specified on the command line. -If this is done, -.Nm ftp -will immediately attempt to establish a connection to an -.Tn FTP -server on that host; otherwise, -.Nm ftp -will enter its command interpreter and await instructions -from the user. -When -.Nm ftp -is awaiting commands from the user the prompt -.Ql ftp\*[Gt] -is provided to the user. -The following commands are recognized -by -.Nm ftp : -.Bl -tag -width Fl -.It Ic \&! Op Ar command Op Ar args -Invoke an interactive shell on the local machine. -If there are arguments, the first is taken to be a command to execute -directly, with the rest of the arguments as its arguments. -.It Ic \&$ Ar macro-name Op Ar args -Execute the macro -.Ar macro-name -that was defined with the -.Ic macdef -command. -Arguments are passed to the macro unglobbed. -.It Ic account Op Ar passwd -Supply a supplemental password required by a remote system for access -to resources once a login has been successfully completed. -If no argument is included, the user will be prompted for an account -password in a non-echoing input mode. -.It Ic append Ar local-file Op Ar remote-file -Append a local file to a file on the remote machine. -If -.Ar remote-file -is left unspecified, the local file name is used in naming the -remote file after being altered by any -.Ic ntrans -or -.Ic nmap -setting. -File transfer uses the current settings for -.Ic type , -.Ic format , -.Ic mode , -and -.Ic structure . -.It Ic ascii -Set the file transfer -.Ic type -to network -.Tn ASCII . -This is the default type. -.It Ic bell -Arrange that a bell be sounded after each file transfer -command is completed. -.It Ic binary -Set the file transfer -.Ic type -to support binary image transfer. -.It Ic bye -Terminate the -.Tn FTP -session with the remote server -and exit -.Nm ftp . -An end of file will also terminate the session and exit. -.It Ic case -Toggle remote computer file name case mapping during -.Ic mget -commands. -When -.Ic case -is on (default is off), remote computer file names with all letters in -upper case are written in the local directory with the letters mapped -to lower case. -.It Ic \&cd Ar remote-directory -Change the working directory on the remote machine -to -.Ar remote-directory . -.It Ic cdup -Change the remote machine working directory to the parent of the -current remote machine working directory. -.It Ic chmod Ar mode file-name -Change the permission modes of the file -.Ar file-name -on the remote -sytem to -.Ar mode . -.It Ic close -Terminate the -.Tn FTP -session with the remote server, and -return to the command interpreter. -Any defined macros are erased. -.It Ic \&cr -Toggle carriage return stripping during -ascii type file retrieval. -Records are denoted by a carriage return/linefeed sequence -during ascii type file transfer. -When -.Ic \&cr -is on (the default), carriage returns are stripped from this -sequence to conform with the -.Ux -single linefeed record -delimiter. -Records on -.Pf non\- Ns Ux -remote systems may contain single linefeeds; -when an ascii type transfer is made, these linefeeds may be -distinguished from a record delimiter only when -.Ic \&cr -is off. -.It Ic delete Ar remote-file -Delete the file -.Ar remote-file -on the remote machine. -.It Ic debug Op Ar debug-value -Toggle debugging mode. -If an optional -.Ar debug-value -is specified it is used to set the debugging level. -When debugging is on, -.Nm ftp -prints each command sent to the remote machine, preceded -by the string -.Ql \-\-\*[Gt] -.It Xo -.Ic dir -.Op Ar remote-directory -.Op Ar local-file -.Xc -Print a listing of the directory contents in the -directory, -.Ar remote-directory , -and, optionally, placing the output in -.Ar local-file . -If interactive prompting is on, -.Nm ftp -will prompt the user to verify that the last argument is indeed the -target local file for receiving -.Ic dir -output. -If no directory is specified, the current working -directory on the remote machine is used. -If no local -file is specified, or -.Ar local-file -is -.Fl , -output comes to the terminal. -.It Ic disconnect -A synonym for -.Ar close . -.It Ic form Ar format -Set the file transfer -.Ic form -to -.Ar format . -The default format is \*(Lqfile\*(Rq. -.It Ic get Ar remote-file Op Ar local-file -Retrieve the -.Ar remote-file -and store it on the local machine. -If the local -file name is not specified, it is given the same -name it has on the remote machine, subject to -alteration by the current -.Ic case , -.Ic ntrans , -and -.Ic nmap -settings. -The current settings for -.Ic type , -.Ic form , -.Ic mode , -and -.Ic structure -are used while transferring the file. -.It Ic glob -Toggle filename expansion for -.Ic mdelete , -.Ic mget -and -.Ic mput . -If globbing is turned off with -.Ic glob , -the file name arguments -are taken literally and not expanded. -Globbing for -.Ic mput -is done as in -.Xr csh 1 . -For -.Ic mdelete -and -.Ic mget , -each remote file name is expanded -separately on the remote machine and the lists are not merged. -Expansion of a directory name is likely to be -different from expansion of the name of an ordinary file: -the exact result depends on the foreign operating system and ftp server, -and can be previewed by doing -.Ql mls remote-files \- . -As a security measure, remotely globbed files that starts with -.Sq / -or contains -.Sq ../ , -will not be automatically received. If you have interactive prompting -turned off, these filenames will be ignored. Note: -.Ic mget -and -.Ic mput -are not meant to transfer -entire directory subtrees of files. -That can be done by -transferring a -.Xr tar 1 -archive of the subtree (in binary mode). -.It Ic hash -Toggle hash-sign (``#'') printing for each data block -transferred. -The size of a data block is 1024 bytes. -.It Ic help Op Ar command -Print an informative message about the meaning of -.Ar command . -If no argument is given, -.Nm ftp -prints a list of the known commands. -.It Ic idle Op Ar seconds -Set the inactivity timer on the remote server to -.Ar seconds -seconds. -If -.Ar seconds -is omitted, the current inactivity timer is printed. -.It Ic lcd Op Ar directory -Change the working directory on the local machine. -If -no -.Ar directory -is specified, the user's home directory is used. -.It Xo -.Ic \&ls -.Op Ar remote-directory -.Op Ar local-file -.Xc -Print a listing of the contents of a -directory on the remote machine. -The listing includes any system-dependent information that the server -chooses to include; for example, most -.Ux -systems will produce -output from the command -.Ql ls \-l . -(See also -.Ic nlist . ) -If -.Ar remote-directory -is left unspecified, the current working directory is used. -If interactive prompting is on, -.Nm ftp -will prompt the user to verify that the last argument is indeed the -target local file for receiving -.Ic \&ls -output. -If no local file is specified, or if -.Ar local-file -is -.Sq Fl , -the output is sent to the terminal. -.It Ic macdef Ar macro-name -Define a macro. -Subsequent lines are stored as the macro -.Ar macro-name ; -a null line (consecutive newline characters -in a file or -carriage returns from the terminal) terminates macro input mode. -There is a limit of 16 macros and 4096 total characters in all -defined macros. -Macros remain defined until a -.Ic close -command is executed. -The macro processor interprets `$' and `\e' as special characters. -A `$' followed by a number (or numbers) is replaced by the -corresponding argument on the macro invocation command line. -A `$' followed by an `i' signals that macro processor that the -executing macro is to be looped. -On the first pass `$i' is -replaced by the first argument on the macro invocation command line, -on the second pass it is replaced by the second argument, and so on. -A `\e' followed by any character is replaced by that character. -Use the `\e' to prevent special treatment of the `$'. -.It Ic mdelete Op Ar remote-files -Delete the -.Ar remote-files -on the remote machine. -.It Ic mdir Ar remote-files local-file -Like -.Ic dir , -except multiple remote files may be specified. -If interactive prompting is on, -.Nm ftp -will prompt the user to verify that the last argument is indeed the -target local file for receiving -.Ic mdir -output. -.It Ic mget Ar remote-files -Expand the -.Ar remote-files -on the remote machine -and do a -.Ic get -for each file name thus produced. -See -.Ic glob -for details on the filename expansion. -Resulting file names will then be processed according to -.Ic case , -.Ic ntrans , -and -.Ic nmap -settings. -Files are transferred into the local working directory, -which can be changed with -.Ql lcd directory ; -new local directories can be created with -.Ql "\&! mkdir directory" . -.It Ic mkdir Ar directory-name -Make a directory on the remote machine. -.It Ic mls Ar remote-files local-file -Like -.Ic nlist , -except multiple remote files may be specified, -and the -.Ar local-file -must be specified. -If interactive prompting is on, -.Nm ftp -will prompt the user to verify that the last argument is indeed the -target local file for receiving -.Ic mls -output. -.It Ic mode Op Ar mode-name -Set the file transfer -.Ic mode -to -.Ar mode-name . -The default mode is \*(Lqstream\*(Rq mode. -.It Ic modtime Ar file-name -Show the last modification time of the file on the remote machine. -.It Ic mput Ar local-files -Expand wild cards in the list of local files given as arguments -and do a -.Ic put -for each file in the resulting list. -See -.Ic glob -for details of filename expansion. -Resulting file names will then be processed according to -.Ic ntrans -and -.Ic nmap -settings. -.It Ic newer Ar file-name -Get the file only if the modification time of the remote file is more -recent that the file on the current system. -If the file does not -exist on the current system, the remote file is considered -.Ic newer . -Otherwise, this command is identical to -.Ar get . -.It Xo -.Ic nlist -.Op Ar remote-directory -.Op Ar local-file -.Xc -Print a list of the files in a -directory on the remote machine. -If -.Ar remote-directory -is left unspecified, the current working directory is used. -If interactive prompting is on, -.Nm ftp -will prompt the user to verify that the last argument is indeed the -target local file for receiving -.Ic nlist -output. -If no local file is specified, or if -.Ar local-file -is -.Fl , -the output is sent to the terminal. -.It Ic nmap Op Ar inpattern outpattern -Set or unset the filename mapping mechanism. -If no arguments are specified, the filename mapping mechanism is unset. -If arguments are specified, remote filenames are mapped during -.Ic mput -commands and -.Ic put -commands issued without a specified remote target filename. -If arguments are specified, local filenames are mapped during -.Ic mget -commands and -.Ic get -commands issued without a specified local target filename. -This command is useful when connecting to a -.No non\- Ns Ux -remote computer -with different file naming conventions or practices. -The mapping follows the pattern set by -.Ar inpattern -and -.Ar outpattern . -.Op Ar Inpattern -is a template for incoming filenames (which may have already been -processed according to the -.Ic ntrans -and -.Ic case -settings). -Variable templating is accomplished by including the -sequences `$1', `$2', ..., `$9' in -.Ar inpattern . -Use `\\' to prevent this special treatment of the `$' character. -All other characters are treated literally, and are used to determine the -.Ic nmap -.Op Ar inpattern -variable values. -For example, given -.Ar inpattern -$1.$2 and the remote file name "mydata.data", $1 would have the value -"mydata", and $2 would have the value "data". -The -.Ar outpattern -determines the resulting mapped filename. -The sequences `$1', `$2', ...., `$9' are replaced by any value resulting -from the -.Ar inpattern -template. -The sequence `$0' is replace by the original filename. -Additionally, the sequence -.Ql Op Ar seq1 , Ar seq2 -is replaced by -.Op Ar seq1 -if -.Ar seq1 -is not a null string; otherwise it is replaced by -.Ar seq2 . -For example, the command -.Pp -.Bd -literal -offset indent -compact -nmap $1.$2.$3 [$1,$2].[$2,file] -.Ed -.Pp -would yield -the output filename "myfile.data" for input filenames "myfile.data" and -"myfile.data.old", "myfile.file" for the input filename "myfile", and -"myfile.myfile" for the input filename ".myfile". -Spaces may be included in -.Ar outpattern , -as in the example: `nmap $1 sed "s/ *$//" \*[Gt] $1' . -Use the `\e' character to prevent special treatment -of the `$','[','[', and `,' characters. -.It Ic ntrans Op Ar inchars Op Ar outchars -Set or unset the filename character translation mechanism. -If no arguments are specified, the filename character -translation mechanism is unset. -If arguments are specified, characters in -remote filenames are translated during -.Ic mput -commands and -.Ic put -commands issued without a specified remote target filename. -If arguments are specified, characters in -local filenames are translated during -.Ic mget -commands and -.Ic get -commands issued without a specified local target filename. -This command is useful when connecting to a -.No non\- Ns Ux -remote computer -with different file naming conventions or practices. -Characters in a filename matching a character in -.Ar inchars -are replaced with the corresponding character in -.Ar outchars . -If the character's position in -.Ar inchars -is longer than the length of -.Ar outchars , -the character is deleted from the file name. -.It Ic open Ar host Op Ar port -Establish a connection to the specified -.Ar host -.Tn FTP -server. -An optional port number may be supplied, -in which case, -.Nm ftp -will attempt to contact an -.Tn FTP -server at that port. -If the -.Ic auto-login -option is on (default), -.Nm ftp -will also attempt to automatically log the user in to -the -.Tn FTP -server (see below). -.It Ic passive -Toggle passive mode. If passive mode is turned on -(default is off), the ftp client will -send a -.Dv PASV -command for all data connections instead of the usual -.Dv PORT -command. The -.Dv PASV -command requests that the remote server open a port for the data connection -and return the address of that port. The remote server listens on that -port and the client connects to it. When using the more traditional -.Dv PORT -command, the client listens on a port and sends that address to the remote -server, who connects back to it. Passive mode is useful when using -.Nm ftp -through a gateway router or host that controls the directionality of -traffic. -(Note that though ftp servers are required to support the -.Dv PASV -command by RFC 1123, some do not.) -.It Ic prompt -Toggle interactive prompting. -Interactive prompting -occurs during multiple file transfers to allow the -user to selectively retrieve or store files. -If prompting is turned off (default is on), any -.Ic mget -or -.Ic mput -will transfer all files, and any -.Ic mdelete -will delete all files. -.It Ic proxy Ar ftp-command -Execute an ftp command on a secondary control connection. -This command allows simultaneous connection to two remote ftp -servers for transferring files between the two servers. -The first -.Ic proxy -command should be an -.Ic open , -to establish the secondary control connection. -Enter the command "proxy ?" to see other ftp commands executable on the -secondary connection. -The following commands behave differently when prefaced by -.Ic proxy : -.Ic open -will not define new macros during the auto-login process, -.Ic close -will not erase existing macro definitions, -.Ic get -and -.Ic mget -transfer files from the host on the primary control connection -to the host on the secondary control connection, and -.Ic put , -.Ic mput , -and -.Ic append -transfer files from the host on the secondary control connection -to the host on the primary control connection. -Third party file transfers depend upon support of the ftp protocol -.Dv PASV -command by the server on the secondary control connection. -.It Ic put Ar local-file Op Ar remote-file -Store a local file on the remote machine. -If -.Ar remote-file -is left unspecified, the local file name is used -after processing according to any -.Ic ntrans -or -.Ic nmap -settings -in naming the remote file. -File transfer uses the -current settings for -.Ic type , -.Ic format , -.Ic mode , -and -.Ic structure . -.It Ic pwd -Print the name of the current working directory on the remote -machine. -.It Ic quit -A synonym for -.Ic bye . -.It Ic quote Ar arg1 arg2 ... -The arguments specified are sent, verbatim, to the remote -.Tn FTP -server. -.It Ic recv Ar remote-file Op Ar local-file -A synonym for get. -.It Ic reget Ar remote-file Op Ar local-file -Reget acts like get, except that if -.Ar local-file -exists and is -smaller than -.Ar remote-file , -.Ar local-file -is presumed to be -a partially transferred copy of -.Ar remote-file -and the transfer -is continued from the apparent point of failure. -This command -is useful when transferring very large files over networks that -are prone to dropping connections. -.It Ic remotehelp Op Ar command-name -Request help from the remote -.Tn FTP -server. -If a -.Ar command-name -is specified it is supplied to the server as well. -.It Ic remotestatus Op Ar file-name -With no arguments, show status of remote machine. -If -.Ar file-name -is specified, show status of -.Ar file-name -on remote machine. -.It Xo -.Ic rename -.Op Ar from -.Op Ar to -.Xc -Rename the file -.Ar from -on the remote machine, to the file -.Ar to . -.It Ic reset -Clear reply queue. -This command re-synchronizes command/reply sequencing with the remote -ftp server. -Resynchronization may be necessary following a violation of the ftp protocol -by the remote server. -.It Ic restart Ar marker -Restart the immediately following -.Ic get -or -.Ic put -at the -indicated -.Ar marker . -On -.Ux -systems, marker is usually a byte -offset into the file. -.It Ic rmdir Ar directory-name -Delete a directory on the remote machine. -.It Ic runique -Toggle storing of files on the local system with unique filenames. -If a file already exists with a name equal to the target -local filename for a -.Ic get -or -.Ic mget -command, a ".1" is appended to the name. -If the resulting name matches another existing file, -a ".2" is appended to the original name. -If this process continues up to ".99", an error -message is printed, and the transfer does not take place. -The generated unique filename will be reported. -Note that -.Ic runique -will not affect local files generated from a shell command -(see below). -The default value is off. -.It Ic send Ar local-file Op Ar remote-file -A synonym for put. -.It Ic sendport -Toggle the use of -.Dv PORT -commands. -By default, -.Nm ftp -will attempt to use a -.Dv PORT -command when establishing -a connection for each data transfer. -The use of -.Dv PORT -commands can prevent delays -when performing multiple file transfers. -If the -.Dv PORT -command fails, -.Nm ftp -will use the default data port. -When the use of -.Dv PORT -commands is disabled, no attempt will be made to use -.Dv PORT -commands for each data transfer. -This is useful -for certain -.Tn FTP -implementations which do ignore -.Dv PORT -commands but, incorrectly, indicate they've been accepted. -.It Ic site Ar arg1 arg2 ... -The arguments specified are sent, verbatim, to the remote -.Tn FTP -server as a -.Dv SITE -command. -.It Ic size Ar file-name -Return size of -.Ar file-name -on remote machine. -.It Ic status -Show the current status of -.Nm ftp . -.It Ic struct Op Ar struct-name -Set the file transfer -.Ar structure -to -.Ar struct-name . -By default \*(Lqstream\*(Rq structure is used. -.It Ic sunique -Toggle storing of files on remote machine under unique file names. -Remote ftp server must support ftp protocol -.Dv STOU -command for -successful completion. -The remote server will report unique name. -Default value is off. -.It Ic system -Show the type of operating system running on the remote machine. -.It Ic tenex -Set the file transfer type to that needed to -talk to -.Tn TENEX -machines. -.It Ic trace -Toggle packet tracing. -.It Ic type Op Ar type-name -Set the file transfer -.Ic type -to -.Ar type-name . -If no type is specified, the current type -is printed. -The default type is network -.Tn ASCII . -.It Ic umask Op Ar newmask -Set the default umask on the remote server to -.Ar newmask . -If -.Ar newmask -is omitted, the current umask is printed. -.It Xo -.Ic user Ar user-name -.Op Ar password -.Op Ar account -.Xc -Identify yourself to the remote -.Tn FTP -server. -If the -.Ar password -is not specified and the server requires it, -.Nm ftp -will prompt the user for it (after disabling local echo). -If an -.Ar account -field is not specified, and the -.Tn FTP -server -requires it, the user will be prompted for it. -If an -.Ar account -field is specified, an account command will -be relayed to the remote server after the login sequence -is completed if the remote server did not require it -for logging in. -Unless -.Nm ftp -is invoked with \*(Lqauto-login\*(Rq disabled, this -process is done automatically on initial connection to -the -.Tn FTP -server. -.It Ic verbose -Toggle verbose mode. -In verbose mode, all responses from -the -.Tn FTP -server are displayed to the user. -In addition, -if verbose is on, when a file transfer completes, statistics -regarding the efficiency of the transfer are reported. -By default, -verbose is on. -.It Ic \&? Op Ar command -A synonym for help. -.El -.Pp -The following command can be used with ftpsec-aware servers. -.Bl -tag -width Fl -.It Xo -.Ic prot -.Ar clear | -.Ar safe | -.Ar confidential | -.Ar private -.Xc -Set the data protection level to the requested level. -.El -.Pp -The following command can be used with ftp servers that has -implemented the KAUTH site command. -.Bl -tag -width Fl -.It Ic kauth Op Ar principal -Obtain remote tickets. -.El -.Pp -Command arguments which have embedded spaces may be quoted with -quote `"' marks. -.Sh ABORTING A FILE TRANSFER -To abort a file transfer, use the terminal interrupt key -(usually Ctrl-C). -Sending transfers will be immediately halted. -Receiving transfers will be halted by sending a ftp protocol -.Dv ABOR -command to the remote server, and discarding any further data received. -The speed at which this is accomplished depends upon the remote -server's support for -.Dv ABOR -processing. -If the remote server does not support the -.Dv ABOR -command, an -.Ql ftp\*[Gt] -prompt will not appear until the remote server has completed -sending the requested file. -.Pp -The terminal interrupt key sequence will be ignored when -.Nm ftp -has completed any local processing and is awaiting a reply -from the remote server. -A long delay in this mode may result from the ABOR processing described -above, or from unexpected behavior by the remote server, including -violations of the ftp protocol. -If the delay results from unexpected remote server behavior, the local -.Nm ftp -program must be killed by hand. -.Sh FILE NAMING CONVENTIONS -Files specified as arguments to -.Nm ftp -commands are processed according to the following rules. -.Bl -enum -.It -If the file name -.Sq Fl -is specified, the -.Ar stdin -(for reading) or -.Ar stdout -(for writing) is used. -.It -If the first character of the file name is -.Sq \&| , -the -remainder of the argument is interpreted as a shell command. -.Nm Ftp -then forks a shell, using -.Xr popen 3 -with the argument supplied, and reads (writes) from the stdout -(stdin). -If the shell command includes spaces, the argument -must be quoted; e.g. -\*(Lq" ls -lt"\*(Rq. -A particularly -useful example of this mechanism is: \*(Lqdir more\*(Rq. -.It -Failing the above checks, if ``globbing'' is enabled, -local file names are expanded -according to the rules used in the -.Xr csh 1 ; -c.f. the -.Ic glob -command. -If the -.Nm ftp -command expects a single local file (.e.g. -.Ic put ) , -only the first filename generated by the "globbing" operation is used. -.It -For -.Ic mget -commands and -.Ic get -commands with unspecified local file names, the local filename is -the remote filename, which may be altered by a -.Ic case , -.Ic ntrans , -or -.Ic nmap -setting. -The resulting filename may then be altered if -.Ic runique -is on. -.It -For -.Ic mput -commands and -.Ic put -commands with unspecified remote file names, the remote filename is -the local filename, which may be altered by a -.Ic ntrans -or -.Ic nmap -setting. -The resulting filename may then be altered by the remote server if -.Ic sunique -is on. -.El -.Sh FILE TRANSFER PARAMETERS -The FTP specification specifies many parameters which may -affect a file transfer. -The -.Ic type -may be one of \*(Lqascii\*(Rq, \*(Lqimage\*(Rq (binary), -\*(Lqebcdic\*(Rq, and \*(Lqlocal byte size\*(Rq (for -.Tn PDP Ns -10's -and -.Tn PDP Ns -20's -mostly). -.Nm Ftp -supports the ascii and image types of file transfer, -plus local byte size 8 for -.Ic tenex -mode transfers. -.Pp -.Nm Ftp -supports only the default values for the remaining -file transfer parameters: -.Ic mode , -.Ic form , -and -.Ic struct . -.Sh THE .netrc FILE -The -.Pa .netrc -file contains login and initialization information -used by the auto-login process. -It resides in the user's home directory. -The following tokens are recognized; they may be separated by spaces, -tabs, or new-lines: -.Bl -tag -width password -.It Ic machine Ar name -Identify a remote machine -.Ar name . -The auto-login process searches the -.Pa .netrc -file for a -.Ic machine -token that matches the remote machine specified on the -.Nm ftp -command line or as an -.Ic open -command argument. -Once a match is made, the subsequent -.Pa .netrc -tokens are processed, -stopping when the end of file is reached or another -.Ic machine -or a -.Ic default -token is encountered. -.It Ic default -This is the same as -.Ic machine -.Ar name -except that -.Ic default -matches any name. -There can be only one -.Ic default -token, and it must be after all -.Ic machine -tokens. -This is normally used as: -.Pp -.Dl default login anonymous password user@site -.Pp -thereby giving the user -.Ar automatic -anonymous ftp login to -machines not specified in -.Pa .netrc . -This can be overridden -by using the -.Fl n -flag to disable auto-login. -.It Ic login Ar name -Identify a user on the remote machine. -If this token is present, the auto-login process will initiate -a login using the specified -.Ar name . -.It Ic password Ar string -Supply a password. -If this token is present, the auto-login process will supply the -specified string if the remote server requires a password as part -of the login process. -Note that if this token is present in the -.Pa .netrc -file for any user other -than -.Ar anonymous , -.Nm ftp -will abort the auto-login process if the -.Pa .netrc -is readable by -anyone besides the user. -.It Ic account Ar string -Supply an additional account password. -If this token is present, the auto-login process will supply the -specified string if the remote server requires an additional -account password, or the auto-login process will initiate an -.Dv ACCT -command if it does not. -.It Ic macdef Ar name -Define a macro. -This token functions like the -.Nm ftp -.Ic macdef -command functions. -A macro is defined with the specified name; its contents begin with the -next -.Pa .netrc -line and continue until a null line (consecutive new-line -characters) is encountered. -If a macro named -.Ic init -is defined, it is automatically executed as the last step in the -auto-login process. -.El -.Sh ENVIRONMENT -.Nm Ftp -uses the following environment variables. -.Bl -tag -width Fl -.It Ev HOME -For default location of a -.Pa .netrc -file, if one exists. -.It Ev SHELL -For default shell. -.El -.Sh SEE ALSO -.Xr ftpd 8 -.Rs -.%T RFC2228 -.Re -.Sh HISTORY -The -.Nm ftp -command appeared in -.Bx 4.2 . -.Sh BUGS -Correct execution of many commands depends upon proper behavior -by the remote server. -.Pp -An error in the treatment of carriage returns -in the -.Bx 4.2 -ascii-mode transfer code -has been corrected. -This correction may result in incorrect transfers of binary files -to and from -.Bx 4.2 -servers using the ascii type. -Avoid this problem by using the binary image type. diff --git a/appl/ftp/ftp/ftp.c b/appl/ftp/ftp/ftp.c deleted file mode 100644 index 0f77f1d68..000000000 --- a/appl/ftp/ftp/ftp.c +++ /dev/null @@ -1,1814 +0,0 @@ -/* - * Copyright (c) 1985, 1989, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "ftp_locl.h" -RCSID ("$Id$"); - -struct sockaddr_storage hisctladdr_ss; -struct sockaddr *hisctladdr = (struct sockaddr *)&hisctladdr_ss; -struct sockaddr_storage data_addr_ss; -struct sockaddr *data_addr = (struct sockaddr *)&data_addr_ss; -struct sockaddr_storage myctladdr_ss; -struct sockaddr *myctladdr = (struct sockaddr *)&myctladdr_ss; -int data = -1; -int abrtflag = 0; -jmp_buf ptabort; -int ptabflg; -int ptflag = 0; -off_t restart_point = 0; - - -FILE *cin, *cout; - -typedef void (*sighand) (int); - -char * -hookup (const char *host, int port) -{ - static char hostnamebuf[MaxHostNameLen]; - struct addrinfo *ai, *a; - struct addrinfo hints; - int error; - char portstr[NI_MAXSERV]; - socklen_t len; - int s; - - memset (&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - hints.ai_flags = AI_CANONNAME; - - snprintf (portstr, sizeof(portstr), "%u", ntohs(port)); - - error = getaddrinfo (host, portstr, &hints, &ai); - if (error) { - warnx ("%s: %s", host, gai_strerror(error)); - code = -1; - return NULL; - } - strlcpy (hostnamebuf, host, sizeof(hostnamebuf)); - hostname = hostnamebuf; - - s = -1; - for (a = ai; a != NULL; a = a->ai_next) { - s = socket (a->ai_family, a->ai_socktype, a->ai_protocol); - if (s < 0) - continue; - - if (a->ai_canonname != NULL) - strlcpy (hostnamebuf, a->ai_canonname, sizeof(hostnamebuf)); - - memcpy (hisctladdr, a->ai_addr, a->ai_addrlen); - - error = connect (s, a->ai_addr, a->ai_addrlen); - if (error < 0) { - char addrstr[256]; - - if (getnameinfo (a->ai_addr, a->ai_addrlen, - addrstr, sizeof(addrstr), - NULL, 0, NI_NUMERICHOST) != 0) - strlcpy (addrstr, "unknown address", sizeof(addrstr)); - - warn ("connect %s", addrstr); - close (s); - s = -1; - continue; - } - break; - } - freeaddrinfo (ai); - if (s < 0) { - warnx ("failed to contact %s", host); - code = -1; - return NULL; - } - - len = sizeof(myctladdr_ss); - if (getsockname (s, myctladdr, &len) < 0) { - warn ("getsockname"); - code = -1; - close (s); - return NULL; - } -#ifdef IPTOS_LOWDELAY - socket_set_tos (s, IPTOS_LOWDELAY); -#endif - cin = fdopen (s, "r"); - cout = fdopen (s, "w"); - if (cin == NULL || cout == NULL) { - warnx ("fdopen failed."); - if (cin) - fclose (cin); - if (cout) - fclose (cout); - code = -1; - goto bad; - } - if (verbose) - printf ("Connected to %s.\n", hostname); - if (getreply (0) > 2) { /* read startup message from server */ - if (cin) - fclose (cin); - if (cout) - fclose (cout); - code = -1; - goto bad; - } -#if defined(SO_OOBINLINE) && defined(HAVE_SETSOCKOPT) - { - int on = 1; - - if (setsockopt (s, SOL_SOCKET, SO_OOBINLINE, (char *) &on, sizeof (on)) - < 0 && debug) { - warn ("setsockopt"); - } - } -#endif /* SO_OOBINLINE */ - - return (hostname); -bad: - close (s); - return NULL; -} - -int -login (char *host) -{ - char tmp[80]; - char defaultpass[128]; - char *userstr, *pass, *acctstr; - char *ruserstr, *rpass, *racctstr; - int n, aflag = 0; - - char *myname = NULL; - struct passwd *pw = k_getpwuid(getuid()); - - if (pw != NULL) - myname = pw->pw_name; - - ruserstr = rpass = racctstr = NULL; - - if(sec_login(host)) - printf("\n*** Using plaintext user and password ***\n\n"); - else{ - printf("Authentication successful.\n\n"); - } - - if (ruserpassword (host, &ruserstr, &rpass, &racctstr) < 0) { - code = -1; - return (0); - } - userstr = ruserstr; - pass = rpass; - acctstr = racctstr; - - while (userstr == NULL) { - if (myname) - printf ("Name (%s:%s): ", host, myname); - else - printf ("Name (%s): ", host); - *tmp = '\0'; - if (fgets (tmp, sizeof (tmp) - 1, stdin) != NULL) - tmp[strlen (tmp) - 1] = '\0'; - if (*tmp == '\0') - userstr = myname; - else - userstr = tmp; - } - strlcpy(username, userstr, sizeof(username)); - if (ruserstr) - free(ruserstr); - - n = command("USER %s", userstr); - if (n == COMPLETE) - n = command("PASS dummy"); /* DK: Compatibility with gssftp daemon */ - else if(n == CONTINUE) { - if (pass == NULL) { - char prompt[128]; - if(myname && - (!strcmp(userstr, "ftp") || !strcmp(userstr, "anonymous"))) { - snprintf(defaultpass, sizeof(defaultpass), - "%s@%s", myname, mydomain); - snprintf(prompt, sizeof(prompt), - "Password (%s): ", defaultpass); - } else if (sec_complete) { - pass = myname; - } else { - *defaultpass = '\0'; - snprintf(prompt, sizeof(prompt), "Password: "); - } - if (pass == NULL) { - pass = defaultpass; - UI_UTIL_read_pw_string (tmp, sizeof (tmp), prompt, 0); - if (tmp[0]) - pass = tmp; - } - } - n = command ("PASS %s", pass); - if (rpass) - free(rpass); - } - if (n == CONTINUE) { - aflag++; - UI_UTIL_read_pw_string (tmp, sizeof(tmp), "Account:", 0); - acctstr = tmp; - n = command ("ACCT %s", acctstr); - } - if (n != COMPLETE) { - if (racctstr) - free(racctstr); - warnx ("Login failed."); - return (0); - } - if (!aflag && acctstr != NULL) - command ("ACCT %s", acctstr); - if (racctstr) - free(racctstr); - if (proxy) - return (1); - for (n = 0; n < macnum; ++n) { - if (!strcmp("init", macros[n].mac_name)) { - strlcpy (line, "$init", sizeof (line)); - makeargv(); - domacro(margc, margv); - break; - } - } - sec_set_protection_level (); - return (1); -} - -void -cmdabort (int sig) -{ - - printf ("\n"); - fflush (stdout); - abrtflag++; - if (ptflag) - longjmp (ptabort, 1); -} - -int -command (char *fmt,...) -{ - va_list ap; - int r; - sighand oldintr; - - abrtflag = 0; - if (cout == NULL) { - warn ("No control connection for command"); - code = -1; - return (0); - } - oldintr = signal(SIGINT, cmdabort); - if(debug){ - printf("---> "); - if (strncmp("PASS ", fmt, 5) == 0) - printf("PASS XXXX"); - else { - va_start(ap, fmt); - vfprintf(stdout, fmt, ap); - va_end(ap); - } - } - va_start(ap, fmt); - sec_vfprintf(cout, fmt, ap); - va_end(ap); - if(debug){ - printf("\n"); - fflush(stdout); - } - fprintf (cout, "\r\n"); - fflush (cout); - cpend = 1; - r = getreply (!strcmp (fmt, "QUIT")); - if (abrtflag && oldintr != SIG_IGN) - (*oldintr) (SIGINT); - signal (SIGINT, oldintr); - return (r); -} - -char reply_string[BUFSIZ]; /* last line of previous reply */ - -int -getreply (int expecteof) -{ - char *p; - char *lead_string; - int c; - struct sigaction sa, osa; - char buf[8192]; - int reply_code; - int long_warn = 0; - - sigemptyset (&sa.sa_mask); - sa.sa_flags = 0; - sa.sa_handler = cmdabort; - sigaction (SIGINT, &sa, &osa); - - p = buf; - - reply_code = 0; - while (1) { - c = getc (cin); - switch (c) { - case EOF: - if (expecteof) { - sigaction (SIGINT, &osa, NULL); - code = 221; - return 0; - } - lostpeer (0); - if (verbose) { - printf ("421 Service not available, " - "remote server has closed connection\n"); - fflush (stdout); - } - code = 421; - return (4); - case IAC: - c = getc (cin); - if (c == WILL || c == WONT) - fprintf (cout, "%c%c%c", IAC, DONT, getc (cin)); - if (c == DO || c == DONT) - fprintf (cout, "%c%c%c", IAC, WONT, getc (cin)); - continue; - case '\n': - *p++ = '\0'; - if(isdigit((unsigned char)buf[0])){ - sscanf(buf, "%d", &code); - if(code == 631){ - code = 0; - sec_read_msg(buf, prot_safe); - sscanf(buf, "%d", &code); - lead_string = "S:"; - } else if(code == 632){ - code = 0; - sec_read_msg(buf, prot_private); - sscanf(buf, "%d", &code); - lead_string = "P:"; - }else if(code == 633){ - code = 0; - sec_read_msg(buf, prot_confidential); - sscanf(buf, "%d", &code); - lead_string = "C:"; - }else if(sec_complete) - lead_string = "!!"; - else - lead_string = ""; - if(code != 0 && reply_code == 0) - reply_code = code; - if (verbose > 0 || (verbose > -1 && code > 499)) - fprintf (stdout, "%s%s\n", lead_string, buf); - if (code == reply_code && buf[3] == ' ') { - strlcpy (reply_string, buf, sizeof(reply_string)); - if (code >= 200) - cpend = 0; - sigaction (SIGINT, &osa, NULL); - if (code == 421) - lostpeer (0); -#if 1 - if (abrtflag && - osa.sa_handler != cmdabort && - osa.sa_handler != SIG_IGN) - osa.sa_handler (SIGINT); -#endif - if (code == 227 || code == 229) { - char *q; - - q = strchr (reply_string, '('); - if (q) { - q++; - strlcpy(pasv, q, sizeof(pasv)); - q = strrchr(pasv, ')'); - if (q) - *q = '\0'; - } - } - return code / 100; - } - }else{ - if(verbose > 0 || (verbose > -1 && code > 499)){ - if(sec_complete) - fprintf(stdout, "!!"); - fprintf(stdout, "%s\n", buf); - } - } - p = buf; - long_warn = 0; - continue; - default: - if(p < buf + sizeof(buf) - 1) - *p++ = c; - else if(long_warn == 0) { - fprintf(stderr, "WARNING: incredibly long line received\n"); - long_warn = 1; - } - } - } - -} - - -#if 0 -int -getreply (int expecteof) -{ - int c, n; - int dig; - int originalcode = 0, continuation = 0; - sighand oldintr; - int pflag = 0; - char *cp, *pt = pasv; - - oldintr = signal (SIGINT, cmdabort); - for (;;) { - dig = n = code = 0; - cp = reply_string; - while ((c = getc (cin)) != '\n') { - if (c == IAC) { /* handle telnet commands */ - switch (c = getc (cin)) { - case WILL: - case WONT: - c = getc (cin); - fprintf (cout, "%c%c%c", IAC, DONT, c); - fflush (cout); - break; - case DO: - case DONT: - c = getc (cin); - fprintf (cout, "%c%c%c", IAC, WONT, c); - fflush (cout); - break; - default: - break; - } - continue; - } - dig++; - if (c == EOF) { - if (expecteof) { - signal (SIGINT, oldintr); - code = 221; - return (0); - } - lostpeer (0); - if (verbose) { - printf ("421 Service not available, remote server has closed connection\n"); - fflush (stdout); - } - code = 421; - return (4); - } - if (c != '\r' && (verbose > 0 || - (verbose > -1 && n == '5' && dig > 4))) { - if (proxflag && - (dig == 1 || dig == 5 && verbose == 0)) - printf ("%s:", hostname); - putchar (c); - } - if (dig < 4 && isdigit (c)) - code = code * 10 + (c - '0'); - if (!pflag && code == 227) - pflag = 1; - if (dig > 4 && pflag == 1 && isdigit (c)) - pflag = 2; - if (pflag == 2) { - if (c != '\r' && c != ')') - *pt++ = c; - else { - *pt = '\0'; - pflag = 3; - } - } - if (dig == 4 && c == '-') { - if (continuation) - code = 0; - continuation++; - } - if (n == 0) - n = c; - if (cp < &reply_string[sizeof (reply_string) - 1]) - *cp++ = c; - } - if (verbose > 0 || verbose > -1 && n == '5') { - putchar (c); - fflush (stdout); - } - if (continuation && code != originalcode) { - if (originalcode == 0) - originalcode = code; - continue; - } - *cp = '\0'; - if(sec_complete){ - if(code == 631) - sec_read_msg(reply_string, prot_safe); - else if(code == 632) - sec_read_msg(reply_string, prot_private); - else if(code == 633) - sec_read_msg(reply_string, prot_confidential); - n = code / 100 + '0'; - } - if (n != '1') - cpend = 0; - signal (SIGINT, oldintr); - if (code == 421 || originalcode == 421) - lostpeer (0); - if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN) - (*oldintr) (SIGINT); - return (n - '0'); - } -} - -#endif - -int -empty (fd_set * mask, int sec) -{ - struct timeval t; - - t.tv_sec = sec; - t.tv_usec = 0; - return (select (FD_SETSIZE, mask, NULL, NULL, &t)); -} - -jmp_buf sendabort; - -static RETSIGTYPE -abortsend (int sig) -{ - - mflag = 0; - abrtflag = 0; - printf ("\nsend aborted\nwaiting for remote to finish abort\n"); - fflush (stdout); - longjmp (sendabort, 1); -} - -#define HASHBYTES 1024 - -static int -copy_stream (FILE * from, FILE * to) -{ - static size_t bufsize; - static char *buf; - int n; - int bytes = 0; - int werr = 0; - int hashbytes = HASHBYTES; - struct stat st; - -#if defined(HAVE_MMAP) && !defined(NO_MMAP) - void *chunk; - size_t off; - -#define BLOCKSIZE (1024 * 1024 * 10) - -#ifndef MAP_FAILED -#define MAP_FAILED (-1) -#endif - - if (fstat (fileno (from), &st) == 0 && S_ISREG (st.st_mode)) { - /* - * mmap zero bytes has potential of loosing, don't do it. - */ - if (st.st_size == 0) - return 0; - off = 0; - while (off != st.st_size) { - size_t len; - ssize_t res; - - len = st.st_size - off; - if (len > BLOCKSIZE) - len = BLOCKSIZE; - - chunk = mmap (0, len, PROT_READ, MAP_SHARED, fileno (from), off); - if (chunk == (void *) MAP_FAILED) { - if (off == 0) /* try read if mmap doesn't work */ - goto try_read; - break; - } - - res = sec_write (fileno (to), chunk, len); - if (msync (chunk, len, MS_ASYNC)) - warn ("msync"); - if (munmap (chunk, len) < 0) - warn ("munmap"); - sec_fflush (to); - if (res != len) - return off; - off += len; - } - return off; - } -try_read: -#endif - - buf = alloc_buffer (buf, &bufsize, - fstat (fileno (from), &st) >= 0 ? &st : NULL); - if (buf == NULL) - return -1; - - while ((n = read (fileno (from), buf, bufsize)) > 0) { - werr = sec_write (fileno (to), buf, n); - if (werr < 0) - break; - bytes += werr; - while (hash && bytes > hashbytes) { - putchar ('#'); - hashbytes += HASHBYTES; - } - } - sec_fflush (to); - if (n < 0) - warn ("local"); - - if (werr < 0) { - if (errno != EPIPE) - warn ("netout"); - bytes = -1; - } - return bytes; -} - -void -sendrequest (char *cmd, char *local, char *remote, char *lmode, int printnames) -{ - struct stat st; - struct timeval start, stop; - int c, d; - FILE *fin, *dout = 0; - int (*closefunc) (FILE *); - RETSIGTYPE (*oldintr)(int), (*oldintp)(int); - long bytes = 0, hashbytes = HASHBYTES; - char *rmode = "w"; - - if (verbose && printnames) { - if (strcmp (local, "-") != 0) - printf ("local: %s ", local); - if (remote) - printf ("remote: %s\n", remote); - } - if (proxy) { - proxtrans (cmd, local, remote); - return; - } - if (curtype != type) - changetype (type, 0); - closefunc = NULL; - oldintr = NULL; - oldintp = NULL; - - if (setjmp (sendabort)) { - while (cpend) { - getreply (0); - } - if (data >= 0) { - close (data); - data = -1; - } - if (oldintr) - signal (SIGINT, oldintr); - if (oldintp) - signal (SIGPIPE, oldintp); - code = -1; - return; - } - oldintr = signal (SIGINT, abortsend); - if (strcmp (local, "-") == 0) - fin = stdin; - else if (*local == '|') { - oldintp = signal (SIGPIPE, SIG_IGN); - fin = popen (local + 1, lmode); - if (fin == NULL) { - warn ("%s", local + 1); - signal (SIGINT, oldintr); - signal (SIGPIPE, oldintp); - code = -1; - return; - } - closefunc = pclose; - } else { - fin = fopen (local, lmode); - if (fin == NULL) { - warn ("local: %s", local); - signal (SIGINT, oldintr); - code = -1; - return; - } - closefunc = fclose; - if (fstat (fileno (fin), &st) < 0 || !S_ISREG(st.st_mode)) { - fprintf (stdout, "%s: not a plain file.\n", local); - signal (SIGINT, oldintr); - fclose (fin); - code = -1; - return; - } - } - if (initconn ()) { - signal (SIGINT, oldintr); - if (oldintp) - signal (SIGPIPE, oldintp); - code = -1; - if (closefunc != NULL) - (*closefunc) (fin); - return; - } - if (setjmp (sendabort)) - goto abort; - - if (restart_point && - (strcmp (cmd, "STOR") == 0 || strcmp (cmd, "APPE") == 0)) { - int rc; - - switch (curtype) { - case TYPE_A: - rc = fseek (fin, (long) restart_point, SEEK_SET); - break; - case TYPE_I: - case TYPE_L: - rc = lseek (fileno (fin), restart_point, SEEK_SET); - break; - default: - abort(); - } - if (rc < 0) { - warn ("local: %s", local); - restart_point = 0; - if (closefunc != NULL) - (*closefunc) (fin); - return; - } - if (command ("REST %ld", (long) restart_point) - != CONTINUE) { - restart_point = 0; - if (closefunc != NULL) - (*closefunc) (fin); - return; - } - restart_point = 0; - rmode = "r+w"; - } - if (remote) { - if (command ("%s %s", cmd, remote) != PRELIM) { - signal (SIGINT, oldintr); - if (oldintp) - signal (SIGPIPE, oldintp); - if (closefunc != NULL) - (*closefunc) (fin); - return; - } - } else if (command ("%s", cmd) != PRELIM) { - signal(SIGINT, oldintr); - if (oldintp) - signal(SIGPIPE, oldintp); - if (closefunc != NULL) - (*closefunc)(fin); - return; - } - dout = dataconn(rmode); - if (dout == NULL) - goto abort; - set_buffer_size (fileno (dout), 0); - gettimeofday (&start, (struct timezone *) 0); - oldintp = signal (SIGPIPE, SIG_IGN); - switch (curtype) { - - case TYPE_I: - case TYPE_L: - errno = d = c = 0; - bytes = copy_stream (fin, dout); - break; - - case TYPE_A: - while ((c = getc (fin)) != EOF) { - if (c == '\n') { - while (hash && (bytes >= hashbytes)) { - putchar ('#'); - fflush (stdout); - hashbytes += HASHBYTES; - } - if (ferror (dout)) - break; - sec_putc ('\r', dout); - bytes++; - } - sec_putc (c, dout); - bytes++; - } - sec_fflush (dout); - if (hash) { - if (bytes < hashbytes) - putchar ('#'); - putchar ('\n'); - fflush (stdout); - } - if (ferror (fin)) - warn ("local: %s", local); - if (ferror (dout)) { - if (errno != EPIPE) - warn ("netout"); - bytes = -1; - } - break; - } - if (closefunc != NULL) - (*closefunc) (fin); - fclose (dout); - gettimeofday (&stop, (struct timezone *) 0); - getreply (0); - signal (SIGINT, oldintr); - if (oldintp) - signal (SIGPIPE, oldintp); - if (bytes > 0) - ptransfer ("sent", bytes, &start, &stop); - return; -abort: - signal (SIGINT, oldintr); - if (oldintp) - signal (SIGPIPE, oldintp); - if (!cpend) { - code = -1; - return; - } - if (data >= 0) { - close (data); - data = -1; - } - if (dout) - fclose (dout); - getreply (0); - code = -1; - if (closefunc != NULL && fin != NULL) - (*closefunc) (fin); - gettimeofday (&stop, (struct timezone *) 0); - if (bytes > 0) - ptransfer ("sent", bytes, &start, &stop); -} - -jmp_buf recvabort; - -void -abortrecv (int sig) -{ - - mflag = 0; - abrtflag = 0; - printf ("\nreceive aborted\nwaiting for remote to finish abort\n"); - fflush (stdout); - longjmp (recvabort, 1); -} - -void -recvrequest (char *cmd, char *local, char *remote, - char *lmode, int printnames, int local_given) -{ - FILE *fout = NULL, *din = NULL; - int (*closefunc) (FILE *); - sighand oldintr, oldintp; - int c, d, is_retr, tcrflag, bare_lfs = 0; - static size_t bufsize; - static char *buf; - long bytes = 0, hashbytes = HASHBYTES; - struct timeval start, stop; - struct stat st; - - is_retr = strcmp (cmd, "RETR") == 0; - if (is_retr && verbose && printnames) { - if (strcmp (local, "-") != 0) - printf ("local: %s ", local); - if (remote) - printf ("remote: %s\n", remote); - } - if (proxy && is_retr) { - proxtrans (cmd, local, remote); - return; - } - closefunc = NULL; - oldintr = NULL; - oldintp = NULL; - tcrflag = !crflag && is_retr; - if (setjmp (recvabort)) { - while (cpend) { - getreply (0); - } - if (data >= 0) { - close (data); - data = -1; - } - if (oldintr) - signal (SIGINT, oldintr); - code = -1; - return; - } - oldintr = signal (SIGINT, abortrecv); - if (!local_given || (strcmp(local, "-") && *local != '|')) { - if (access (local, 2) < 0) { - char *dir = strrchr (local, '/'); - - if (errno != ENOENT && errno != EACCES) { - warn ("local: %s", local); - signal (SIGINT, oldintr); - code = -1; - return; - } - if (dir != NULL) - *dir = 0; - d = access (dir ? local : ".", 2); - if (dir != NULL) - *dir = '/'; - if (d < 0) { - warn ("local: %s", local); - signal (SIGINT, oldintr); - code = -1; - return; - } - if (!runique && errno == EACCES && - chmod (local, 0600) < 0) { - warn ("local: %s", local); - signal (SIGINT, oldintr); - signal (SIGINT, oldintr); - code = -1; - return; - } - if (runique && errno == EACCES && - (local = gunique (local)) == NULL) { - signal (SIGINT, oldintr); - code = -1; - return; - } - } else if (runique && (local = gunique (local)) == NULL) { - signal(SIGINT, oldintr); - code = -1; - return; - } - } - if (!is_retr) { - if (curtype != TYPE_A) - changetype (TYPE_A, 0); - } else if (curtype != type) - changetype (type, 0); - if (initconn ()) { - signal (SIGINT, oldintr); - code = -1; - return; - } - if (setjmp (recvabort)) - goto abort; - if (is_retr && restart_point && - command ("REST %ld", (long) restart_point) != CONTINUE) - return; - if (remote) { - if (command ("%s %s", cmd, remote) != PRELIM) { - signal (SIGINT, oldintr); - return; - } - } else { - if (command ("%s", cmd) != PRELIM) { - signal (SIGINT, oldintr); - return; - } - } - din = dataconn ("r"); - if (din == NULL) - goto abort; - set_buffer_size (fileno (din), 1); - if (local_given && strcmp (local, "-") == 0) - fout = stdout; - else if (local_given && *local == '|') { - oldintp = signal (SIGPIPE, SIG_IGN); - fout = popen (local + 1, "w"); - if (fout == NULL) { - warn ("%s", local + 1); - goto abort; - } - closefunc = pclose; - } else { - fout = fopen (local, lmode); - if (fout == NULL) { - warn ("local: %s", local); - goto abort; - } - closefunc = fclose; - } - buf = alloc_buffer (buf, &bufsize, - fstat (fileno (fout), &st) >= 0 ? &st : NULL); - if (buf == NULL) - goto abort; - - gettimeofday (&start, (struct timezone *) 0); - switch (curtype) { - - case TYPE_I: - case TYPE_L: - if (restart_point && - lseek (fileno (fout), restart_point, SEEK_SET) < 0) { - warn ("local: %s", local); - if (closefunc != NULL) - (*closefunc) (fout); - return; - } - errno = d = 0; - while ((c = sec_read (fileno (din), buf, bufsize)) > 0) { - if ((d = write (fileno (fout), buf, c)) != c) - break; - bytes += c; - if (hash) { - while (bytes >= hashbytes) { - putchar ('#'); - hashbytes += HASHBYTES; - } - fflush (stdout); - } - } - if (hash && bytes > 0) { - if (bytes < HASHBYTES) - putchar ('#'); - putchar ('\n'); - fflush (stdout); - } - if (c < 0) { - if (errno != EPIPE) - warn ("netin"); - bytes = -1; - } - if (d < c) { - if (d < 0) - warn ("local: %s", local); - else - warnx ("%s: short write", local); - } - break; - - case TYPE_A: - if (restart_point) { - int i, n, ch; - - if (fseek (fout, 0L, SEEK_SET) < 0) - goto done; - n = restart_point; - for (i = 0; i++ < n;) { - if ((ch = sec_getc (fout)) == EOF) - goto done; - if (ch == '\n') - i++; - } - if (fseek (fout, 0L, SEEK_CUR) < 0) { - done: - warn ("local: %s", local); - if (closefunc != NULL) - (*closefunc) (fout); - return; - } - } - while ((c = sec_getc(din)) != EOF) { - if (c == '\n') - bare_lfs++; - while (c == '\r') { - while (hash && (bytes >= hashbytes)) { - putchar ('#'); - fflush (stdout); - hashbytes += HASHBYTES; - } - bytes++; - if ((c = sec_getc (din)) != '\n' || tcrflag) { - if (ferror (fout)) - goto break2; - putc ('\r', fout); - if (c == '\0') { - bytes++; - goto contin2; - } - if (c == EOF) - goto contin2; - } - } - putc (c, fout); - bytes++; - contin2:; - } -break2: - if (bare_lfs) { - printf ("WARNING! %d bare linefeeds received in ASCII mode\n", - bare_lfs); - printf ("File may not have transferred correctly.\n"); - } - if (hash) { - if (bytes < hashbytes) - putchar ('#'); - putchar ('\n'); - fflush (stdout); - } - if (ferror (din)) { - if (errno != EPIPE) - warn ("netin"); - bytes = -1; - } - if (ferror (fout)) - warn ("local: %s", local); - break; - } - if (closefunc != NULL) - (*closefunc) (fout); - signal (SIGINT, oldintr); - if (oldintp) - signal (SIGPIPE, oldintp); - fclose (din); - gettimeofday (&stop, (struct timezone *) 0); - getreply (0); - if (bytes > 0 && is_retr) - ptransfer ("received", bytes, &start, &stop); - return; -abort: - - /* abort using RFC959 recommended IP,SYNC sequence */ - - if (oldintp) - signal (SIGPIPE, oldintr); - signal (SIGINT, SIG_IGN); - if (!cpend) { - code = -1; - signal (SIGINT, oldintr); - return; - } - abort_remote(din); - code = -1; - if (data >= 0) { - close (data); - data = -1; - } - if (closefunc != NULL && fout != NULL) - (*closefunc) (fout); - if (din) - fclose (din); - gettimeofday (&stop, (struct timezone *) 0); - if (bytes > 0) - ptransfer ("received", bytes, &start, &stop); - signal (SIGINT, oldintr); -} - -static int -parse_epsv (const char *str) -{ - char sep; - char *end; - int port; - - if (*str == '\0') - return -1; - sep = *str++; - if (sep != *str++) - return -1; - if (sep != *str++) - return -1; - port = strtol (str, &end, 0); - if (str == end) - return -1; - if (end[0] != sep || end[1] != '\0') - return -1; - return htons(port); -} - -static int -parse_pasv (struct sockaddr_in *sin4, const char *str) -{ - int a0, a1, a2, a3, p0, p1; - - /* - * What we've got at this point is a string of comma separated - * one-byte unsigned integer values. The first four are the an IP - * address. The fifth is the MSB of the port number, the sixth is the - * LSB. From that we'll prepare a sockaddr_in. - */ - - if (sscanf (str, "%d,%d,%d,%d,%d,%d", - &a0, &a1, &a2, &a3, &p0, &p1) != 6) { - printf ("Passive mode address scan failure. " - "Shouldn't happen!\n"); - return -1; - } - if (a0 < 0 || a0 > 255 || - a1 < 0 || a1 > 255 || - a2 < 0 || a2 > 255 || - a3 < 0 || a3 > 255 || - p0 < 0 || p0 > 255 || - p1 < 0 || p1 > 255) { - printf ("Can't parse passive mode string.\n"); - return -1; - } - memset (sin4, 0, sizeof(*sin4)); - sin4->sin_family = AF_INET; - sin4->sin_addr.s_addr = htonl ((a0 << 24) | (a1 << 16) | - (a2 << 8) | a3); - sin4->sin_port = htons ((p0 << 8) | p1); - return 0; -} - -static int -passive_mode (void) -{ - int port; - - data = socket (myctladdr->sa_family, SOCK_STREAM, 0); - if (data < 0) { - warn ("socket"); - return (1); - } - if (options & SO_DEBUG) - socket_set_debug (data); - if (command ("EPSV") != COMPLETE) { - if (command ("PASV") != COMPLETE) { - printf ("Passive mode refused.\n"); - goto bad; - } - } - - /* - * Parse the reply to EPSV or PASV - */ - - port = parse_epsv (pasv); - if (port > 0) { - data_addr->sa_family = myctladdr->sa_family; - socket_set_address_and_port (data_addr, - socket_get_address (hisctladdr), - port); - } else { - if (parse_pasv ((struct sockaddr_in *)data_addr, pasv) < 0) - goto bad; - } - - if (connect (data, data_addr, socket_sockaddr_size (data_addr)) < 0) { - warn ("connect"); - goto bad; - } -#ifdef IPTOS_THROUGHPUT - socket_set_tos (data, IPTOS_THROUGHPUT); -#endif - return (0); -bad: - close (data); - data = -1; - sendport = 1; - return (1); -} - - -static int -active_mode (void) -{ - int tmpno = 0; - socklen_t len; - int result; - -noport: - data_addr->sa_family = myctladdr->sa_family; - socket_set_address_and_port (data_addr, socket_get_address (myctladdr), - sendport ? 0 : socket_get_port (myctladdr)); - - if (data != -1) - close (data); - data = socket (data_addr->sa_family, SOCK_STREAM, 0); - if (data < 0) { - warn ("socket"); - if (tmpno) - sendport = 1; - return (1); - } - if (!sendport) - socket_set_reuseaddr (data, 1); - if (bind (data, data_addr, socket_sockaddr_size (data_addr)) < 0) { - warn ("bind"); - goto bad; - } - if (options & SO_DEBUG) - socket_set_debug (data); - len = sizeof (data_addr_ss); - if (getsockname (data, data_addr, &len) < 0) { - warn ("getsockname"); - goto bad; - } - if (listen (data, 1) < 0) - warn ("listen"); - if (sendport) { - char addr_str[256]; - int inet_af; - int overbose; - - if (inet_ntop (data_addr->sa_family, socket_get_address (data_addr), - addr_str, sizeof(addr_str)) == NULL) - errx (1, "inet_ntop failed"); - switch (data_addr->sa_family) { - case AF_INET : - inet_af = 1; - break; -#ifdef HAVE_IPV6 - case AF_INET6 : - inet_af = 2; - break; -#endif - default : - errx (1, "bad address family %d", data_addr->sa_family); - } - - - overbose = verbose; - if (debug == 0) - verbose = -1; - - result = command ("EPRT |%d|%s|%d|", - inet_af, addr_str, - ntohs(socket_get_port (data_addr))); - verbose = overbose; - - if (result == ERROR) { - struct sockaddr_in *sin4 = (struct sockaddr_in *)data_addr; - - unsigned int a = ntohl(sin4->sin_addr.s_addr); - unsigned int p = ntohs(sin4->sin_port); - - if (data_addr->sa_family != AF_INET) { - warnx ("remote server doesn't support EPRT"); - goto bad; - } - - result = command("PORT %d,%d,%d,%d,%d,%d", - (a >> 24) & 0xff, - (a >> 16) & 0xff, - (a >> 8) & 0xff, - a & 0xff, - (p >> 8) & 0xff, - p & 0xff); - if (result == ERROR && sendport == -1) { - sendport = 0; - tmpno = 1; - goto noport; - } - return (result != COMPLETE); - } - return result != COMPLETE; - } - if (tmpno) - sendport = 1; - - -#ifdef IPTOS_THROUGHPUT - socket_set_tos (data, IPTOS_THROUGHPUT); -#endif - return (0); -bad: - close (data); - data = -1; - if (tmpno) - sendport = 1; - return (1); -} - -/* - * Need to start a listen on the data channel before we send the command, - * otherwise the server's connect may fail. - */ -int -initconn (void) -{ - if (passivemode) - return passive_mode (); - else - return active_mode (); -} - -FILE * -dataconn (const char *lmode) -{ - struct sockaddr_storage from_ss; - struct sockaddr *from = (struct sockaddr *)&from_ss; - socklen_t fromlen = sizeof(from_ss); - int s; - - if (passivemode) - return (fdopen (data, lmode)); - - s = accept (data, from, &fromlen); - if (s < 0) { - warn ("accept"); - close (data), data = -1; - return (NULL); - } - close (data); - data = s; -#ifdef IPTOS_THROUGHPUT - socket_set_tos (s, IPTOS_THROUGHPUT); -#endif - return (fdopen (data, lmode)); -} - -void -ptransfer (char *direction, long int bytes, - struct timeval * t0, struct timeval * t1) -{ - struct timeval td; - float s; - float bs; - int prec; - char *unit; - - if (verbose) { - td.tv_sec = t1->tv_sec - t0->tv_sec; - td.tv_usec = t1->tv_usec - t0->tv_usec; - if (td.tv_usec < 0) { - td.tv_sec--; - td.tv_usec += 1000000; - } - s = td.tv_sec + (td.tv_usec / 1000000.); - bs = bytes / (s ? s : 1); - if (bs >= 1048576) { - bs /= 1048576; - unit = "M"; - prec = 2; - } else if (bs >= 1024) { - bs /= 1024; - unit = "k"; - prec = 1; - } else { - unit = ""; - prec = 0; - } - - printf ("%ld bytes %s in %.3g seconds (%.*f %sbyte/s)\n", - bytes, direction, s, prec, bs, unit); - } -} - -void -psabort (int sig) -{ - - abrtflag++; -} - -void -pswitch (int flag) -{ - sighand oldintr; - static struct comvars { - int connect; - char name[MaxHostNameLen]; - struct sockaddr_storage mctl; - struct sockaddr_storage hctl; - FILE *in; - FILE *out; - int tpe; - int curtpe; - int cpnd; - int sunqe; - int runqe; - int mcse; - int ntflg; - char nti[17]; - char nto[17]; - int mapflg; - char mi[MaxPathLen]; - char mo[MaxPathLen]; - } proxstruct, tmpstruct; - struct comvars *ip, *op; - - abrtflag = 0; - oldintr = signal (SIGINT, psabort); - if (flag) { - if (proxy) - return; - ip = &tmpstruct; - op = &proxstruct; - proxy++; - } else { - if (!proxy) - return; - ip = &proxstruct; - op = &tmpstruct; - proxy = 0; - } - ip->connect = connected; - connected = op->connect; - if (hostname) { - strlcpy (ip->name, hostname, sizeof (ip->name)); - } else - ip->name[0] = 0; - hostname = op->name; - ip->hctl = hisctladdr_ss; - hisctladdr_ss = op->hctl; - ip->mctl = myctladdr_ss; - myctladdr_ss = op->mctl; - ip->in = cin; - cin = op->in; - ip->out = cout; - cout = op->out; - ip->tpe = type; - type = op->tpe; - ip->curtpe = curtype; - curtype = op->curtpe; - ip->cpnd = cpend; - cpend = op->cpnd; - ip->sunqe = sunique; - sunique = op->sunqe; - ip->runqe = runique; - runique = op->runqe; - ip->mcse = mcase; - mcase = op->mcse; - ip->ntflg = ntflag; - ntflag = op->ntflg; - strlcpy (ip->nti, ntin, sizeof (ip->nti)); - strlcpy (ntin, op->nti, 17); - strlcpy (ip->nto, ntout, sizeof (ip->nto)); - strlcpy (ntout, op->nto, 17); - ip->mapflg = mapflag; - mapflag = op->mapflg; - strlcpy (ip->mi, mapin, MaxPathLen); - strlcpy (mapin, op->mi, MaxPathLen); - strlcpy (ip->mo, mapout, MaxPathLen); - strlcpy (mapout, op->mo, MaxPathLen); - signal(SIGINT, oldintr); - if (abrtflag) { - abrtflag = 0; - (*oldintr) (SIGINT); - } -} - -void -abortpt (int sig) -{ - - printf ("\n"); - fflush (stdout); - ptabflg++; - mflag = 0; - abrtflag = 0; - longjmp (ptabort, 1); -} - -void -proxtrans (char *cmd, char *local, char *remote) -{ - sighand oldintr = NULL; - int secndflag = 0, prox_type, nfnd; - char *cmd2; - fd_set mask; - - if (strcmp (cmd, "RETR")) - cmd2 = "RETR"; - else - cmd2 = runique ? "STOU" : "STOR"; - if ((prox_type = type) == 0) { - if (unix_server && unix_proxy) - prox_type = TYPE_I; - else - prox_type = TYPE_A; - } - if (curtype != prox_type) - changetype (prox_type, 1); - if (command ("PASV") != COMPLETE) { - printf ("proxy server does not support third party transfers.\n"); - return; - } - pswitch (0); - if (!connected) { - printf ("No primary connection\n"); - pswitch (1); - code = -1; - return; - } - if (curtype != prox_type) - changetype (prox_type, 1); - if (command ("PORT %s", pasv) != COMPLETE) { - pswitch (1); - return; - } - if (setjmp (ptabort)) - goto abort; - oldintr = signal (SIGINT, abortpt); - if (command ("%s %s", cmd, remote) != PRELIM) { - signal (SIGINT, oldintr); - pswitch (1); - return; - } - sleep (2); - pswitch (1); - secndflag++; - if (command ("%s %s", cmd2, local) != PRELIM) - goto abort; - ptflag++; - getreply (0); - pswitch (0); - getreply (0); - signal (SIGINT, oldintr); - pswitch (1); - ptflag = 0; - printf ("local: %s remote: %s\n", local, remote); - return; -abort: - signal (SIGINT, SIG_IGN); - ptflag = 0; - if (strcmp (cmd, "RETR") && !proxy) - pswitch (1); - else if (!strcmp (cmd, "RETR") && proxy) - pswitch (0); - if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */ - if (command ("%s %s", cmd2, local) != PRELIM) { - pswitch (0); - if (cpend) - abort_remote ((FILE *) NULL); - } - pswitch (1); - if (ptabflg) - code = -1; - if (oldintr) - signal (SIGINT, oldintr); - return; - } - if (cpend) - abort_remote ((FILE *) NULL); - pswitch (!proxy); - if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */ - if (command ("%s %s", cmd2, local) != PRELIM) { - pswitch (0); - if (cpend) - abort_remote ((FILE *) NULL); - pswitch (1); - if (ptabflg) - code = -1; - signal (SIGINT, oldintr); - return; - } - } - if (cpend) - abort_remote ((FILE *) NULL); - pswitch (!proxy); - if (cpend) { - FD_ZERO (&mask); - if (fileno(cin) >= FD_SETSIZE) - errx (1, "fd too large"); - FD_SET (fileno (cin), &mask); - if ((nfnd = empty (&mask, 10)) <= 0) { - if (nfnd < 0) { - warn ("abort"); - } - if (ptabflg) - code = -1; - lostpeer (0); - } - getreply (0); - getreply (0); - } - if (proxy) - pswitch (0); - pswitch (1); - if (ptabflg) - code = -1; - signal (SIGINT, oldintr); -} - -void -reset (int argc, char **argv) -{ - fd_set mask; - int nfnd = 1; - - FD_ZERO (&mask); - while (nfnd > 0) { - if (fileno (cin) >= FD_SETSIZE) - errx (1, "fd too large"); - FD_SET (fileno (cin), &mask); - if ((nfnd = empty (&mask, 0)) < 0) { - warn ("reset"); - code = -1; - lostpeer(0); - } else if (nfnd) { - getreply(0); - } - } -} - -char * -gunique (char *local) -{ - static char new[MaxPathLen]; - char *cp = strrchr (local, '/'); - int d, count = 0; - char ext = '1'; - - if (cp) - *cp = '\0'; - d = access (cp ? local : ".", 2); - if (cp) - *cp = '/'; - if (d < 0) { - warn ("local: %s", local); - return NULL; - } - strlcpy (new, local, sizeof(new)); - cp = new + strlen(new); - *cp++ = '.'; - while (!d) { - if (++count == 100) { - printf ("runique: can't find unique file name.\n"); - return NULL; - } - *cp++ = ext; - *cp = '\0'; - if (ext == '9') - ext = '0'; - else - ext++; - if ((d = access (new, 0)) < 0) - break; - if (ext != '0') - cp--; - else if (*(cp - 2) == '.') - *(cp - 1) = '1'; - else { - *(cp - 2) = *(cp - 2) + 1; - cp--; - } - } - return (new); -} - -void -abort_remote (FILE * din) -{ - char buf[BUFSIZ]; - int nfnd; - fd_set mask; - - /* - * send IAC in urgent mode instead of DM because 4.3BSD places oob mark - * after urgent byte rather than before as is protocol now - */ - snprintf (buf, sizeof (buf), "%c%c%c", IAC, IP, IAC); - if (send (fileno (cout), buf, 3, MSG_OOB) != 3) - warn ("abort"); - fprintf (cout, "%c", DM); - sec_fprintf(cout, "ABOR"); - sec_fflush (cout); - fprintf (cout, "\r\n"); - fflush(cout); - FD_ZERO (&mask); - if (fileno (cin) >= FD_SETSIZE) - errx (1, "fd too large"); - FD_SET (fileno (cin), &mask); - if (din) { - if (fileno (din) >= FD_SETSIZE) - errx (1, "fd too large"); - FD_SET (fileno (din), &mask); - } - if ((nfnd = empty (&mask, 10)) <= 0) { - if (nfnd < 0) { - warn ("abort"); - } - if (ptabflg) - code = -1; - lostpeer (0); - } - if (din && FD_ISSET (fileno (din), &mask)) { - while (read (fileno (din), buf, BUFSIZ) > 0) - /* LOOP */ ; - } - if (getreply (0) == ERROR && code == 552) { - /* 552 needed for nic style abort */ - getreply (0); - } - getreply (0); -} diff --git a/appl/ftp/ftp/ftp_locl.h b/appl/ftp/ftp/ftp_locl.h deleted file mode 100644 index cae845a93..000000000 --- a/appl/ftp/ftp/ftp_locl.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* $Id$ */ - -#ifndef __FTP_LOCL_H__ -#define __FTP_LOCL_H__ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifdef HAVE_PWD_H -#include -#endif -#include -#include -#include -#include -#include -#ifdef TIME_WITH_SYS_TIME -#include -#include -#elif defined(HAVE_SYS_TIME_H) -#include -#else -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_PARAM_H -#include -#endif -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif -#ifdef HAVE_SYS_WAIT_H -#include -#endif -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETINET_IN_SYSTM_H -#include -#endif -#ifdef HAVE_NETINET_IP_H -#include -#endif - -#ifdef HAVE_ARPA_FTP_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_ARPA_TELNET_H -#include -#endif - -#include -#include -#include -#ifdef HAVE_NETDB_H -#include -#endif - -#ifdef HAVE_SYS_MMAN_H -#include -#endif - -#include - -#ifdef SOCKS -#include -extern int LIBPREFIX(fclose) (FILE *); - -/* This doesn't belong here. */ -struct tm *localtime(const time_t *); -struct hostent *gethostbyname(const char *); - -#endif - -#include "ftp_var.h" -#include "extern.h" -#include "common.h" -#include "pathnames.h" - -#include "roken.h" -#include "security.h" - -/* des_read_pw_string */ -#include "crypto-headers.h" - -#if defined(__sun__) && !defined(__svr4) -int fclose(FILE*); -int pclose(FILE*); -#endif - -#endif /* __FTP_LOCL_H__ */ diff --git a/appl/ftp/ftp/ftp_var.h b/appl/ftp/ftp/ftp_var.h deleted file mode 100644 index 75ec495b7..000000000 --- a/appl/ftp/ftp/ftp_var.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 1985, 1989, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)ftp_var.h 8.4 (Berkeley) 10/9/94 - */ - -/* - * FTP global variables. - */ - -#ifdef HAVE_SYS_PARAM_H -#include -#endif -#include - -/* - * Options and other state info. - */ -extern int trace; /* trace packets exchanged */ -extern int hash; /* print # for each buffer transferred */ -extern int sendport; /* use PORT cmd for each data connection */ -extern int verbose; /* print messages coming back from server */ -extern int connected; /* connected to server */ -extern int fromatty; /* input is from a terminal */ -extern int interactive; /* interactively prompt on m* cmds */ -extern int lineedit; /* use line-editing */ -extern int debug; /* debugging level */ -extern int bell; /* ring bell on cmd completion */ -extern int doglob; /* glob local file names */ -extern int autologin; /* establish user account on connection */ -extern int doencrypt; -extern int proxy; /* proxy server connection active */ -extern int proxflag; /* proxy connection exists */ -extern int sunique; /* store files on server with unique name */ -extern int runique; /* store local files with unique name */ -extern int mcase; /* map upper to lower case for mget names */ -extern int ntflag; /* use ntin ntout tables for name translation */ -extern int mapflag; /* use mapin mapout templates on file names */ -extern int code; /* return/reply code for ftp command */ -extern int crflag; /* if 1, strip car. rets. on ascii gets */ -extern char pasv[64]; /* passive port for proxy data connection */ -extern int passivemode; /* passive mode enabled */ -extern char *altarg; /* argv[1] with no shell-like preprocessing */ -extern char ntin[17]; /* input translation table */ -extern char ntout[17]; /* output translation table */ -extern char mapin[MaxPathLen]; /* input map template */ -extern char mapout[MaxPathLen]; /* output map template */ -extern char typename[32]; /* name of file transfer type */ -extern int type; /* requested file transfer type */ -extern int curtype; /* current file transfer type */ -extern char structname[32]; /* name of file transfer structure */ -extern int stru; /* file transfer structure */ -extern char formname[32]; /* name of file transfer format */ -extern int form; /* file transfer format */ -extern char modename[32]; /* name of file transfer mode */ -extern int mode; /* file transfer mode */ -extern char bytename[32]; /* local byte size in ascii */ -extern int bytesize; /* local byte size in binary */ - -extern char *hostname; /* name of host connected to */ -extern int unix_server; /* server is unix, can use binary for ascii */ -extern int unix_proxy; /* proxy is unix, can use binary for ascii */ - -extern jmp_buf toplevel; /* non-local goto stuff for cmd scanner */ - -extern char line[200]; /* input line buffer */ -extern char *stringbase; /* current scan point in line buffer */ -extern char argbuf[200]; /* argument storage buffer */ -extern char *argbase; /* current storage point in arg buffer */ -extern int margc; /* count of arguments on input line */ -extern char **margv; /* args parsed from input line */ -extern int margvlen; /* how large margv is currently */ -extern int cpend; /* flag: if != 0, then pending server reply */ -extern int mflag; /* flag: if != 0, then active multi command */ - -extern int options; /* used during socket creation */ -extern int use_kerberos; /* use Kerberos authentication */ - -/* - * Format of command table. - */ -struct cmd { - char *c_name; /* name of command */ - char *c_help; /* help string */ - char c_bell; /* give bell when command completes */ - char c_conn; /* must be connected to use command */ - char c_proxy; /* proxy server may execute */ - void (*c_handler) (int, char **); /* function to call */ -}; - -struct macel { - char mac_name[9]; /* macro name */ - char *mac_start; /* start of macro in macbuf */ - char *mac_end; /* end of macro in macbuf */ -}; - -extern int macnum; /* number of defined macros */ -extern struct macel macros[16]; -extern char macbuf[4096]; - - diff --git a/appl/ftp/ftp/globals.c b/appl/ftp/ftp/globals.c deleted file mode 100644 index 4c195f6e9..000000000 --- a/appl/ftp/ftp/globals.c +++ /dev/null @@ -1,79 +0,0 @@ -#include "ftp_locl.h" -RCSID("$Id$"); - -/* - * Options and other state info. - */ -int trace; /* trace packets exchanged */ -int hash; /* print # for each buffer transferred */ -int sendport; /* use PORT cmd for each data connection */ -int verbose; /* print messages coming back from server */ -int connected; /* connected to server */ -int fromatty; /* input is from a terminal */ -int interactive; /* interactively prompt on m* cmds */ -int lineedit; /* use line-editing */ -int debug; /* debugging level */ -int bell; /* ring bell on cmd completion */ -int doglob; /* glob local file names */ -int doencrypt; /* try to use encryption */ -int autologin; /* establish user account on connection */ -int proxy; /* proxy server connection active */ -int proxflag; /* proxy connection exists */ -int sunique; /* store files on server with unique name */ -int runique; /* store local files with unique name */ -int mcase; /* map upper to lower case for mget names */ -int ntflag; /* use ntin ntout tables for name translation */ -int mapflag; /* use mapin mapout templates on file names */ -int code; /* return/reply code for ftp command */ -int crflag; /* if 1, strip car. rets. on ascii gets */ -char pasv[64]; /* passive port for proxy data connection */ -int passivemode; /* passive mode enabled */ -char *altarg; /* argv[1] with no shell-like preprocessing */ -char ntin[17]; /* input translation table */ -char ntout[17]; /* output translation table */ -char mapin[MaxPathLen]; /* input map template */ -char mapout[MaxPathLen]; /* output map template */ -char typename[32]; /* name of file transfer type */ -int type; /* requested file transfer type */ -int curtype; /* current file transfer type */ -char structname[32]; /* name of file transfer structure */ -int stru; /* file transfer structure */ -char formname[32]; /* name of file transfer format */ -int form; /* file transfer format */ -char modename[32]; /* name of file transfer mode */ -int mode; /* file transfer mode */ -char bytename[32]; /* local byte size in ascii */ -int bytesize; /* local byte size in binary */ - -char *hostname; /* name of host connected to */ -int unix_server; /* server is unix, can use binary for ascii */ -int unix_proxy; /* proxy is unix, can use binary for ascii */ - -jmp_buf toplevel; /* non-local goto stuff for cmd scanner */ - -char line[200]; /* input line buffer */ -char *stringbase; /* current scan point in line buffer */ -char argbuf[200]; /* argument storage buffer */ -char *argbase; /* current storage point in arg buffer */ -int margc; /* count of arguments on input line */ -char **margv; /* args parsed from input line */ -int margvlen; /* how large margv is currently */ -int cpend; /* flag: if != 0, then pending server reply */ -int mflag; /* flag: if != 0, then active multi command */ - -int options; /* used during socket creation */ -int use_kerberos; /* use Kerberos authentication */ - -/* - * Format of command table. - */ - -int macnum; /* number of defined macros */ -struct macel macros[16]; -char macbuf[4096]; - -char username[32]; - -/* these are set in ruserpassword */ -char myhostname[MaxHostNameLen]; -char *mydomain; diff --git a/appl/ftp/ftp/gssapi.c b/appl/ftp/ftp/gssapi.c deleted file mode 100644 index 4d1669d8e..000000000 --- a/appl/ftp/ftp/gssapi.c +++ /dev/null @@ -1,535 +0,0 @@ -/* - * Copyright (c) 1998 - 2005 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifdef FTP_SERVER -#include "ftpd_locl.h" -#else -#include "ftp_locl.h" -#endif -#include -#include -#include - -RCSID("$Id$"); - -int ftp_do_gss_bindings = 0; -int ftp_do_gss_delegate = 1; - -struct gss_data { - gss_ctx_id_t context_hdl; - char *client_name; - gss_cred_id_t delegated_cred_handle; - void *mech_data; -}; - -static int -gss_init(void *app_data) -{ - struct gss_data *d = app_data; - d->context_hdl = GSS_C_NO_CONTEXT; - d->delegated_cred_handle = GSS_C_NO_CREDENTIAL; -#if defined(FTP_SERVER) - return 0; -#else - /* XXX Check the gss mechanism; with gss_indicate_mechs() ? */ -#ifdef KRB5 - return !use_kerberos; -#else - return 0; -#endif /* KRB5 */ -#endif /* FTP_SERVER */ -} - -static int -gss_check_prot(void *app_data, int level) -{ - if(level == prot_confidential) - return -1; - return 0; -} - -static int -gss_decode(void *app_data, void *buf, int len, int level) -{ - OM_uint32 maj_stat, min_stat; - gss_buffer_desc input, output; - gss_qop_t qop_state; - int conf_state; - struct gss_data *d = app_data; - size_t ret_len; - - input.length = len; - input.value = buf; - maj_stat = gss_unwrap (&min_stat, - d->context_hdl, - &input, - &output, - &conf_state, - &qop_state); - if(GSS_ERROR(maj_stat)) - return -1; - memmove(buf, output.value, output.length); - ret_len = output.length; - gss_release_buffer(&min_stat, &output); - return ret_len; -} - -static int -gss_overhead(void *app_data, int level, int len) -{ - return 100; /* dunno? */ -} - - -static int -gss_encode(void *app_data, void *from, int length, int level, void **to) -{ - OM_uint32 maj_stat, min_stat; - gss_buffer_desc input, output; - int conf_state; - struct gss_data *d = app_data; - - input.length = length; - input.value = from; - maj_stat = gss_wrap (&min_stat, - d->context_hdl, - level == prot_private, - GSS_C_QOP_DEFAULT, - &input, - &conf_state, - &output); - *to = output.value; - return output.length; -} - -static void -sockaddr_to_gss_address (struct sockaddr *sa, - OM_uint32 *addr_type, - gss_buffer_desc *gss_addr) -{ - switch (sa->sa_family) { -#ifdef HAVE_IPV6 - case AF_INET6 : { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; - - gss_addr->length = 16; - gss_addr->value = &sin6->sin6_addr; - *addr_type = GSS_C_AF_INET6; - break; - } -#endif - case AF_INET : { - struct sockaddr_in *sin4 = (struct sockaddr_in *)sa; - - gss_addr->length = 4; - gss_addr->value = &sin4->sin_addr; - *addr_type = GSS_C_AF_INET; - break; - } - default : - errx (1, "unknown address family %d", sa->sa_family); - - } -} - -/* end common stuff */ - -#ifdef FTP_SERVER - -static int -gss_adat(void *app_data, void *buf, size_t len) -{ - char *p = NULL; - gss_buffer_desc input_token, output_token; - OM_uint32 maj_stat, min_stat; - gss_name_t client_name; - struct gss_data *d = app_data; - gss_channel_bindings_t bindings; - - if (ftp_do_gss_bindings) { - bindings = malloc(sizeof(*bindings)); - if (bindings == NULL) - errx(1, "out of memory"); - - sockaddr_to_gss_address (his_addr, - &bindings->initiator_addrtype, - &bindings->initiator_address); - sockaddr_to_gss_address (ctrl_addr, - &bindings->acceptor_addrtype, - &bindings->acceptor_address); - - bindings->application_data.length = 0; - bindings->application_data.value = NULL; - } else - bindings = GSS_C_NO_CHANNEL_BINDINGS; - - input_token.value = buf; - input_token.length = len; - - maj_stat = gss_accept_sec_context (&min_stat, - &d->context_hdl, - GSS_C_NO_CREDENTIAL, - &input_token, - bindings, - &client_name, - NULL, - &output_token, - NULL, - NULL, - &d->delegated_cred_handle); - - if (bindings != GSS_C_NO_CHANNEL_BINDINGS) - free(bindings); - - if(output_token.length) { - if(base64_encode(output_token.value, output_token.length, &p) < 0) { - reply(535, "Out of memory base64-encoding."); - return -1; - } - gss_release_buffer(&min_stat, &output_token); - } - if(maj_stat == GSS_S_COMPLETE){ - char *name; - gss_buffer_desc export_name; - gss_OID oid; - - maj_stat = gss_display_name(&min_stat, client_name, - &export_name, &oid); - if(maj_stat != 0) { - reply(500, "Error displaying name"); - goto out; - } - /* XXX kerberos */ - if(oid != GSS_KRB5_NT_PRINCIPAL_NAME) { - reply(500, "OID not kerberos principal name"); - gss_release_buffer(&min_stat, &export_name); - goto out; - } - name = malloc(export_name.length + 1); - if(name == NULL) { - reply(500, "Out of memory"); - gss_release_buffer(&min_stat, &export_name); - goto out; - } - memcpy(name, export_name.value, export_name.length); - name[export_name.length] = '\0'; - gss_release_buffer(&min_stat, &export_name); - d->client_name = name; - if(p) - reply(235, "ADAT=%s", p); - else - reply(235, "ADAT Complete"); - sec_complete = 1; - - } else if(maj_stat == GSS_S_CONTINUE_NEEDED) { - if(p) - reply(335, "ADAT=%s", p); - else - reply(335, "OK, need more data"); - } else { - OM_uint32 new_stat; - OM_uint32 msg_ctx = 0; - gss_buffer_desc status_string; - gss_display_status(&new_stat, - min_stat, - GSS_C_MECH_CODE, - GSS_C_NO_OID, - &msg_ctx, - &status_string); - syslog(LOG_ERR, "gss_accept_sec_context: %.*s", - (int)status_string.length, - (char*)status_string.value); - gss_release_buffer(&new_stat, &status_string); - reply(431, "Security resource unavailable"); - } - out: - if (client_name) - gss_release_name(&min_stat, &client_name); - free(p); - return 0; -} - -int gss_userok(void*, char*); -int gss_session(void*, char*); - -struct sec_server_mech gss_server_mech = { - "GSSAPI", - sizeof(struct gss_data), - gss_init, /* init */ - NULL, /* end */ - gss_check_prot, - gss_overhead, - gss_encode, - gss_decode, - /* */ - NULL, - gss_adat, - NULL, /* pbsz */ - NULL, /* ccc */ - gss_userok, - gss_session -}; - -#else /* FTP_SERVER */ - -extern struct sockaddr *hisctladdr, *myctladdr; - -static int -import_name(const char *kname, const char *host, gss_name_t *target_name) -{ - OM_uint32 maj_stat, min_stat; - gss_buffer_desc name; - char *str; - - name.length = asprintf(&str, "%s@%s", kname, host); - if (str == NULL) { - printf("Out of memory\n"); - return AUTH_ERROR; - } - name.value = str; - - maj_stat = gss_import_name(&min_stat, - &name, - GSS_C_NT_HOSTBASED_SERVICE, - target_name); - if (GSS_ERROR(maj_stat)) { - OM_uint32 new_stat; - OM_uint32 msg_ctx = 0; - gss_buffer_desc status_string; - - gss_display_status(&new_stat, - min_stat, - GSS_C_MECH_CODE, - GSS_C_NO_OID, - &msg_ctx, - &status_string); - printf("Error importing name %.*s: %.*s\n", - (int)name.length, - (char *)name.value, - (int)status_string.length, - (char *)status_string.value); - free(name.value); - gss_release_buffer(&new_stat, &status_string); - return AUTH_ERROR; - } - free(name.value); - return 0; -} - -static int -gss_auth(void *app_data, char *host) -{ - - OM_uint32 maj_stat, min_stat; - gss_name_t target_name; - gss_buffer_desc input, output_token; - int context_established = 0; - char *p; - int n; - gss_channel_bindings_t bindings; - struct gss_data *d = app_data; - OM_uint32 mech_flags = GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG; - - const char *knames[] = { "ftp", "host", NULL }, **kname = knames; - - - if(import_name(*kname++, host, &target_name)) - return AUTH_ERROR; - - input.length = 0; - input.value = NULL; - - if (ftp_do_gss_bindings) { - bindings = malloc(sizeof(*bindings)); - if (bindings == NULL) - errx(1, "out of memory"); - - sockaddr_to_gss_address (myctladdr, - &bindings->initiator_addrtype, - &bindings->initiator_address); - sockaddr_to_gss_address (hisctladdr, - &bindings->acceptor_addrtype, - &bindings->acceptor_address); - - bindings->application_data.length = 0; - bindings->application_data.value = NULL; - } else - bindings = GSS_C_NO_CHANNEL_BINDINGS; - - if (ftp_do_gss_delegate) - mech_flags |= GSS_C_DELEG_FLAG; - - while(!context_established) { - maj_stat = gss_init_sec_context(&min_stat, - GSS_C_NO_CREDENTIAL, - &d->context_hdl, - target_name, - GSS_C_NO_OID, - mech_flags, - 0, - bindings, - &input, - NULL, - &output_token, - NULL, - NULL); - if (GSS_ERROR(maj_stat)) { - OM_uint32 new_stat; - OM_uint32 msg_ctx = 0; - gss_buffer_desc status_string; - - d->context_hdl = GSS_C_NO_CONTEXT; - - gss_release_name(&min_stat, &target_name); - - if(*kname != NULL) { - - if(import_name(*kname++, host, &target_name)) { - if (bindings != GSS_C_NO_CHANNEL_BINDINGS) - free(bindings); - return AUTH_ERROR; - } - continue; - } - - if (bindings != GSS_C_NO_CHANNEL_BINDINGS) - free(bindings); - - gss_display_status(&new_stat, - min_stat, - GSS_C_MECH_CODE, - GSS_C_NO_OID, - &msg_ctx, - &status_string); - printf("Error initializing security context: %.*s\n", - (int)status_string.length, - (char*)status_string.value); - gss_release_buffer(&new_stat, &status_string); - return AUTH_CONTINUE; - } - - if (input.value) { - free(input.value); - input.value = NULL; - input.length = 0; - } - if (output_token.length != 0) { - base64_encode(output_token.value, output_token.length, &p); - gss_release_buffer(&min_stat, &output_token); - n = command("ADAT %s", p); - free(p); - } - if (GSS_ERROR(maj_stat)) { - if (d->context_hdl != GSS_C_NO_CONTEXT) - gss_delete_sec_context (&min_stat, - &d->context_hdl, - GSS_C_NO_BUFFER); - break; - } - if (maj_stat & GSS_S_CONTINUE_NEEDED) { - p = strstr(reply_string, "ADAT="); - if(p == NULL){ - printf("Error: expected ADAT in reply. got: %s\n", - reply_string); - if (bindings != GSS_C_NO_CHANNEL_BINDINGS) - free(bindings); - return AUTH_ERROR; - } else { - p+=5; - input.value = malloc(strlen(p)); - input.length = base64_decode(p, input.value); - } - } else { - if(code != 235) { - printf("Unrecognized response code: %d\n", code); - if (bindings != GSS_C_NO_CHANNEL_BINDINGS) - free(bindings); - return AUTH_ERROR; - } - context_established = 1; - } - } - - gss_release_name(&min_stat, &target_name); - - if (bindings != GSS_C_NO_CHANNEL_BINDINGS) - free(bindings); - if (input.value) - free(input.value); - - { - gss_name_t targ_name; - - maj_stat = gss_inquire_context(&min_stat, - d->context_hdl, - NULL, - &targ_name, - NULL, - NULL, - NULL, - NULL, - NULL); - if (GSS_ERROR(maj_stat) == 0) { - gss_buffer_desc name; - maj_stat = gss_display_name (&min_stat, - targ_name, - &name, - NULL); - if (GSS_ERROR(maj_stat) == 0) { - printf("Authenticated to <%.*s>\n", - (int)name.length, - (char *)name.value); - gss_release_buffer(&min_stat, &name); - } - gss_release_name(&min_stat, &targ_name); - } else - printf("Failed to get gss name of peer.\n"); - } - - - return AUTH_OK; -} - -struct sec_client_mech gss_client_mech = { - "GSSAPI", - sizeof(struct gss_data), - gss_init, - gss_auth, - NULL, /* end */ - gss_check_prot, - gss_overhead, - gss_encode, - gss_decode, -}; - -#endif /* FTP_SERVER */ diff --git a/appl/ftp/ftp/main.c b/appl/ftp/ftp/main.c deleted file mode 100644 index 8a45d10c9..000000000 --- a/appl/ftp/ftp/main.c +++ /dev/null @@ -1,590 +0,0 @@ -/* - * Copyright (c) 1985, 1989, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * FTP User Program -- Command Interface. - */ - -#include "ftp_locl.h" -#include - -RCSID("$Id$"); - -static int help_flag; -static int version_flag; -static int debug_flag; - -struct getargs getargs[] = { - { NULL, 'd', arg_flag, &debug_flag, - "debug", NULL }, - { NULL, 'g', arg_negative_flag, &doglob, - "disables globbing", NULL}, - { NULL, 'i', arg_negative_flag, &interactive, - "Turn off interactive prompting", NULL}, - { NULL, 'l', arg_negative_flag, &lineedit, - "Turn off line editing", NULL}, - { NULL, 'n', arg_negative_flag, &autologin, - "Turn off auto-login", NULL}, - { NULL, 'p', arg_flag, &passivemode, - "passive mode", NULL}, - { NULL, 't', arg_counter, &trace, - "Packet tracing", NULL}, -#ifdef KRB5 - { "gss-bindings", 0, arg_negative_flag, &ftp_do_gss_bindings, - "Don't use GSS-API bindings", NULL}, - { "gss-delegate", 0, arg_negative_flag, &ftp_do_gss_delegate, - "Disable delegation of GSS-API credentials", NULL}, -#endif - { NULL, 'v', arg_counter, &verbose, - "verbosity", NULL}, - { NULL, 'K', arg_negative_flag, &use_kerberos, - "Disable kerberos authentication", NULL}, - { "encrypt", 'x', arg_flag, &doencrypt, - "Encrypt command and data channel if possible" }, - { "version", 0, arg_flag, &version_flag }, - { "help", 'h', arg_flag, &help_flag }, -}; - -static int num_args = sizeof(getargs) / sizeof(getargs[0]); - -static void -usage(int ecode) -{ - arg_printusage(getargs, num_args, NULL, "[host [port]]"); - exit(ecode); -} - -int -main(int argc, char **argv) -{ - int top; - struct passwd *pw = NULL; - char homedir[MaxPathLen]; - struct servent *sp; - int optind = 0; - - setprogname(argv[0]); - - sp = getservbyname("ftp", "tcp"); - if (sp == 0) - errx(1, "ftp/tcp: unknown service"); - doglob = 1; - interactive = 1; - autologin = 1; - lineedit = 1; - passivemode = 0; /* passive mode not active */ - use_kerberos = 1; -#ifdef KRB5 - ftp_do_gss_bindings = 1; -#endif - - if(getarg(getargs, num_args, argc, argv, &optind)) - usage(1); - if(help_flag) - usage(0); - if(version_flag) { - print_version(NULL); - exit(0); - } - - if (debug_flag) { - options |= SO_DEBUG; - debug++; - } - - argc -= optind; - argv += optind; - - fromatty = isatty(fileno(stdin)); - if (fromatty) - verbose++; - cpend = 0; /* no pending replies */ - proxy = 0; /* proxy not active */ - crflag = 1; /* strip c.r. on ascii gets */ - sendport = -1; /* not using ports */ - /* - * Set up the home directory in case we're globbing. - */ - pw = k_getpwuid(getuid()); - if (pw != NULL) { - strlcpy(homedir, pw->pw_dir, sizeof(homedir)); - home = homedir; - } - if (argc > 0) { - char *xargv[5]; - - if (setjmp(toplevel)) - exit(0); - signal(SIGINT, intr); - signal(SIGPIPE, lostpeer); - xargv[0] = (char*)getprogname(); - xargv[1] = argv[0]; - xargv[2] = argv[1]; - xargv[3] = argv[2]; - xargv[4] = NULL; - setpeer(argc+1, xargv); - } - if(setjmp(toplevel) == 0) - top = 1; - else - top = 0; - if (top) { - signal(SIGINT, intr); - signal(SIGPIPE, lostpeer); - } - for (;;) { - cmdscanner(top); - top = 1; - } -} - -void -intr(int sig) -{ - - longjmp(toplevel, 1); -} - -#ifndef SHUT_RDWR -#define SHUT_RDWR 2 -#endif - -RETSIGTYPE -lostpeer(int sig) -{ - - if (connected) { - if (cout != NULL) { - shutdown(fileno(cout), SHUT_RDWR); - fclose(cout); - cout = NULL; - } - if (data >= 0) { - shutdown(data, SHUT_RDWR); - close(data); - data = -1; - } - connected = 0; - } - pswitch(1); - if (connected) { - if (cout != NULL) { - shutdown(fileno(cout), SHUT_RDWR); - fclose(cout); - cout = NULL; - } - connected = 0; - } - proxflag = 0; - pswitch(0); - sec_end(); - SIGRETURN(0); -} - -/* -char * -tail(filename) - char *filename; -{ - char *s; - - while (*filename) { - s = strrchr(filename, '/'); - if (s == NULL) - break; - if (s[1]) - return (s + 1); - *s = '\0'; - } - return (filename); -} -*/ - -static char * -simple_readline(char *prompt) -{ - char buf[BUFSIZ]; - printf ("%s", prompt); - fflush (stdout); - if(fgets(buf, sizeof(buf), stdin) == NULL) - return NULL; - if (buf[strlen(buf) - 1] == '\n') - buf[strlen(buf) - 1] = '\0'; - return strdup(buf); -} - -#ifndef HAVE_READLINE - -static char * -readline(char *prompt) -{ - return simple_readline (prompt); -} - -static void -add_history(char *p) -{ -} - -#else - -/* These should not really be here */ - -char *readline(char *); -void add_history(char *); - -#endif - -/* - * Command parser. - */ -void -cmdscanner(int top) -{ - struct cmd *c; - int l; - - if (!top) - putchar('\n'); - for (;;) { - if (fromatty) { - char *p; - if (lineedit) - p = readline("ftp> "); - else - p = simple_readline("ftp> "); - if(p == NULL) { - printf("\n"); - quit(0, 0); - } - strlcpy(line, p, sizeof(line)); - if (lineedit) - add_history(p); - free(p); - } else{ - if (fgets(line, sizeof line, stdin) == NULL) - quit(0, 0); - } - /* XXX will break on long lines */ - l = strlen(line); - if (l == 0) - break; - if (line[--l] == '\n') { - if (l == 0) - break; - line[l] = '\0'; - } else if (l == sizeof(line) - 2) { - printf("sorry, input line too long\n"); - while ((l = getchar()) != '\n' && l != EOF) - /* void */; - break; - } /* else it was a line without a newline */ - makeargv(); - if (margc == 0) { - continue; - } - c = getcmd(margv[0]); - if (c == (struct cmd *)-1) { - printf("?Ambiguous command\n"); - continue; - } - if (c == 0) { - printf("?Invalid command\n"); - continue; - } - if (c->c_conn && !connected) { - printf("Not connected.\n"); - continue; - } - (*c->c_handler)(margc, margv); - if (bell && c->c_bell) - putchar('\007'); - if (c->c_handler != help) - break; - } - signal(SIGINT, intr); - signal(SIGPIPE, lostpeer); -} - -struct cmd * -getcmd(char *name) -{ - char *p, *q; - struct cmd *c, *found; - int nmatches, longest; - - longest = 0; - nmatches = 0; - found = 0; - for (c = cmdtab; (p = c->c_name); c++) { - for (q = name; *q == *p++; q++) - if (*q == 0) /* exact match? */ - return (c); - if (!*q) { /* the name was a prefix */ - if (q - name > longest) { - longest = q - name; - nmatches = 1; - found = c; - } else if (q - name == longest) - nmatches++; - } - } - if (nmatches > 1) - return ((struct cmd *)-1); - return (found); -} - -/* - * Slice a string up into argc/argv. - */ - -int slrflag; - -void -makeargv(void) -{ - char **argp; - - argp = margv; - stringbase = line; /* scan from first of buffer */ - argbase = argbuf; /* store from first of buffer */ - slrflag = 0; - for (margc = 0; ; margc++) { - /* Expand array if necessary */ - if (margc == margvlen) { - int i; - - margv = (margvlen == 0) - ? (char **)malloc(20 * sizeof(char *)) - : (char **)realloc(margv, - (margvlen + 20)*sizeof(char *)); - if (margv == NULL) - errx(1, "cannot realloc argv array"); - for(i = margvlen; i < margvlen + 20; ++i) - margv[i] = NULL; - margvlen += 20; - argp = margv + margc; - } - - if ((*argp++ = slurpstring()) == NULL) - break; - } - -} - -/* - * Parse string into argbuf; - * implemented with FSM to - * handle quoting and strings - */ -char * -slurpstring(void) -{ - int got_one = 0; - char *sb = stringbase; - char *ap = argbase; - char *tmp = argbase; /* will return this if token found */ - - if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */ - switch (slrflag) { /* and $ as token for macro invoke */ - case 0: - slrflag++; - stringbase++; - return ((*sb == '!') ? "!" : "$"); - /* NOTREACHED */ - case 1: - slrflag++; - altarg = stringbase; - break; - default: - break; - } - } - -S0: - switch (*sb) { - - case '\0': - goto OUT; - - case ' ': - case '\t': - sb++; goto S0; - - default: - switch (slrflag) { - case 0: - slrflag++; - break; - case 1: - slrflag++; - altarg = sb; - break; - default: - break; - } - goto S1; - } - -S1: - switch (*sb) { - - case ' ': - case '\t': - case '\0': - goto OUT; /* end of token */ - - case '\\': - sb++; goto S2; /* slurp next character */ - - case '"': - sb++; goto S3; /* slurp quoted string */ - - default: - *ap++ = *sb++; /* add character to token */ - got_one = 1; - goto S1; - } - -S2: - switch (*sb) { - - case '\0': - goto OUT; - - default: - *ap++ = *sb++; - got_one = 1; - goto S1; - } - -S3: - switch (*sb) { - - case '\0': - goto OUT; - - case '"': - sb++; goto S1; - - default: - *ap++ = *sb++; - got_one = 1; - goto S3; - } - -OUT: - if (got_one) - *ap++ = '\0'; - argbase = ap; /* update storage pointer */ - stringbase = sb; /* update scan pointer */ - if (got_one) { - return (tmp); - } - switch (slrflag) { - case 0: - slrflag++; - break; - case 1: - slrflag++; - altarg = (char *) 0; - break; - default: - break; - } - return NULL; -} - -#define HELPINDENT ((int) sizeof ("directory")) - -/* - * Help command. - * Call each command handler with argc == 0 and argv[0] == name. - */ -void -help(int argc, char **argv) -{ - struct cmd *c; - - if (argc == 1) { - int i, j, w, k; - int columns, width = 0, lines; - - printf("Commands may be abbreviated. Commands are:\n\n"); - for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { - int len = strlen(c->c_name); - - if (len > width) - width = len; - } - width = (width + 8) &~ 7; - columns = 80 / width; - if (columns == 0) - columns = 1; - lines = (NCMDS + columns - 1) / columns; - for (i = 0; i < lines; i++) { - for (j = 0; j < columns; j++) { - c = cmdtab + j * lines + i; - if ((!proxy || c->c_proxy)) { - printf("%s", c->c_name); - } else { - for (k=0; k < strlen(c->c_name); k++) { - putchar(' '); - } - } - if (c + lines >= &cmdtab[NCMDS]) { - printf("\n"); - break; - } - w = strlen(c->c_name); - while (w < width) { - w = (w + 8) &~ 7; - putchar('\t'); - } - } - } - return; - } - while (--argc > 0) { - char *arg; - arg = *++argv; - c = getcmd(arg); - if (c == (struct cmd *)-1) - printf("?Ambiguous help command %s\n", arg); - else if (c == (struct cmd *)0) - printf("?Invalid help command %s\n", arg); - else - printf("%-*s\t%s\n", HELPINDENT, - c->c_name, c->c_help); - } -} diff --git a/appl/ftp/ftp/pathnames.h b/appl/ftp/ftp/pathnames.h deleted file mode 100644 index f7c1fb391..000000000 --- a/appl/ftp/ftp/pathnames.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 - */ - -#ifdef HAVE_PATHS_H -#include -#endif - -#define _PATH_TMP_XXX "/tmp/ftpXXXXXX" - -#ifndef _PATH_BSHELL -#define _PATH_BSHELL "/bin/sh" -#endif diff --git a/appl/ftp/ftp/ruserpass.c b/appl/ftp/ftp/ruserpass.c deleted file mode 100644 index a8665b643..000000000 --- a/appl/ftp/ftp/ruserpass.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (c) 1985, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "ftp_locl.h" -RCSID("$Id$"); - -static int token (void); -static FILE *cfile; - -#define DEFAULT 1 -#define LOGIN 2 -#define PASSWD 3 -#define ACCOUNT 4 -#define MACDEF 5 -#define PROT 6 -#define ID 10 -#define MACH 11 - -static char tokval[100]; - -static struct toktab { - char *tokstr; - int tval; -} toktab[]= { - { "default", DEFAULT }, - { "login", LOGIN }, - { "password", PASSWD }, - { "passwd", PASSWD }, - { "account", ACCOUNT }, - { "machine", MACH }, - { "macdef", MACDEF }, - { "prot", PROT }, - { NULL, 0 } -}; - -/* - * Write a copy of the hostname into `hostname, sz' and return a guess - * as to the `domain' of that hostname. - */ - -static char * -guess_domain (char *hostname_str, size_t sz) -{ - struct addrinfo *ai, *a; - struct addrinfo hints; - int error; - char *dot; - - if (gethostname (hostname_str, sz) < 0) { - strlcpy (hostname_str, "", sz); - return ""; - } - dot = strchr (hostname_str, '.'); - if (dot != NULL) - return dot + 1; - - memset (&hints, 0, sizeof(hints)); - hints.ai_flags = AI_CANONNAME; - - error = getaddrinfo (hostname_str, NULL, &hints, &ai); - if (error) - return hostname_str; - - for (a = ai; a != NULL; a = a->ai_next) - if (a->ai_canonname != NULL) { - strlcpy (hostname_str, ai->ai_canonname, sz); - break; - } - freeaddrinfo (ai); - dot = strchr (hostname_str, '.'); - if (dot != NULL) - return dot + 1; - else - return hostname_str; -} - -int -ruserpassword(char *host, char **aname, char **apass, char **aacct) -{ - char *hdir, buf[BUFSIZ], *tmp; - int t, i, c, usedefault = 0; - struct stat stb; - - mydomain = guess_domain (myhostname, MaxHostNameLen); - - hdir = getenv("HOME"); - if (hdir == NULL) - hdir = "."; - snprintf(buf, sizeof(buf), "%s/.netrc", hdir); - cfile = fopen(buf, "r"); - if (cfile == NULL) { - if (errno != ENOENT) - warn("%s", buf); - return (0); - } - -next: - while ((t = token())) switch(t) { - - case DEFAULT: - usedefault = 1; - /* FALL THROUGH */ - - case MACH: - if (!usedefault) { - if (token() != ID) - continue; - /* - * Allow match either for user's input host name - * or official hostname. Also allow match of - * incompletely-specified host in local domain. - */ - if (strcasecmp(host, tokval) == 0) - goto match; - if (strcasecmp(hostname, tokval) == 0) - goto match; - if ((tmp = strchr(hostname, '.')) != NULL && - tmp++ && - strcasecmp(tmp, mydomain) == 0 && - strncasecmp(hostname, tokval, tmp-hostname) == 0 && - tokval[tmp - hostname] == '\0') - goto match; - if ((tmp = strchr(host, '.')) != NULL && - tmp++ && - strcasecmp(tmp, mydomain) == 0 && - strncasecmp(host, tokval, tmp - host) == 0 && - tokval[tmp - host] == '\0') - goto match; - continue; - } - match: - while ((t = token()) && t != MACH && t != DEFAULT) switch(t) { - - case LOGIN: - if (token()) { - if (*aname == 0) { - *aname = strdup(tokval); - } else { - if (strcmp(*aname, tokval)) - goto next; - } - } - break; - case PASSWD: - if ((*aname == NULL || strcmp(*aname, "anonymous")) && - fstat(fileno(cfile), &stb) >= 0 && - (stb.st_mode & 077) != 0) { - warnx("Error: .netrc file is readable by others."); - warnx("Remove password or make file unreadable by others."); - goto bad; - } - if (token() && *apass == 0) { - *apass = strdup(tokval); - } - break; - case ACCOUNT: - if (fstat(fileno(cfile), &stb) >= 0 - && (stb.st_mode & 077) != 0) { - warnx("Error: .netrc file is readable by others."); - warnx("Remove account or make file unreadable by others."); - goto bad; - } - if (token() && *aacct == 0) { - *aacct = strdup(tokval); - } - break; - case MACDEF: - if (proxy) { - fclose(cfile); - return (0); - } - while ((c=getc(cfile)) != EOF && - (c == ' ' || c == '\t')); - if (c == EOF || c == '\n') { - printf("Missing macdef name argument.\n"); - goto bad; - } - if (macnum == 16) { - printf("Limit of 16 macros have already been defined\n"); - goto bad; - } - tmp = macros[macnum].mac_name; - *tmp++ = c; - for (i=0; i < 8 && (c=getc(cfile)) != EOF && - !isspace(c); ++i) { - *tmp++ = c; - } - if (c == EOF) { - printf("Macro definition missing null line terminator.\n"); - goto bad; - } - *tmp = '\0'; - if (c != '\n') { - while ((c=getc(cfile)) != EOF && c != '\n'); - } - if (c == EOF) { - printf("Macro definition missing null line terminator.\n"); - goto bad; - } - if (macnum == 0) { - macros[macnum].mac_start = macbuf; - } - else { - macros[macnum].mac_start = macros[macnum-1].mac_end + 1; - } - tmp = macros[macnum].mac_start; - while (tmp != macbuf + 4096) { - if ((c=getc(cfile)) == EOF) { - printf("Macro definition missing null line terminator.\n"); - goto bad; - } - *tmp = c; - if (*tmp == '\n') { - if (*(tmp-1) == '\0') { - macros[macnum++].mac_end = tmp - 1; - break; - } - *tmp = '\0'; - } - tmp++; - } - if (tmp == macbuf + 4096) { - printf("4K macro buffer exceeded\n"); - goto bad; - } - break; - case PROT: - token(); - if(doencrypt == 0 && sec_request_prot(tokval) < 0) - warnx("Unknown protection level \"%s\"", tokval); - break; - default: - warnx("Unknown .netrc keyword %s", tokval); - break; - } - goto done; - } -done: - fclose(cfile); - return (0); -bad: - fclose(cfile); - return (-1); -} - -static int -token(void) -{ - char *cp; - int c; - struct toktab *t; - - if (feof(cfile) || ferror(cfile)) - return (0); - while ((c = getc(cfile)) != EOF && - (c == '\n' || c == '\t' || c == ' ' || c == ',')) - continue; - if (c == EOF) - return (0); - cp = tokval; - if (c == '"') { - while ((c = getc(cfile)) != EOF && c != '"') { - if (c == '\\') - c = getc(cfile); - *cp++ = c; - } - } else { - *cp++ = c; - while ((c = getc(cfile)) != EOF - && c != '\n' && c != '\t' && c != ' ' && c != ',') { - if (c == '\\') - c = getc(cfile); - *cp++ = c; - } - } - *cp = 0; - if (tokval[0] == 0) - return (0); - for (t = toktab; t->tokstr; t++) - if (!strcmp(t->tokstr, tokval)) - return (t->tval); - return (ID); -} diff --git a/appl/ftp/ftp/security.c b/appl/ftp/ftp/security.c deleted file mode 100644 index f186ab818..000000000 --- a/appl/ftp/ftp/security.c +++ /dev/null @@ -1,883 +0,0 @@ -/* - * Copyright (c) 1998-2002, 2005 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifdef FTP_SERVER -#include "ftpd_locl.h" -#else -#include "ftp_locl.h" -#endif - -RCSID("$Id$"); - -static enum protection_level command_prot; -static enum protection_level data_prot; -static size_t buffer_size; - -struct buffer { - void *data; - size_t size; - size_t index; - int eof_flag; -}; - -static struct buffer in_buffer, out_buffer; -int sec_complete; - -static struct { - enum protection_level level; - const char *name; -} level_names[] = { - { prot_clear, "clear" }, - { prot_safe, "safe" }, - { prot_confidential, "confidential" }, - { prot_private, "private" } -}; - -static const char * -level_to_name(enum protection_level level) -{ - int i; - for(i = 0; i < sizeof(level_names) / sizeof(level_names[0]); i++) - if(level_names[i].level == level) - return level_names[i].name; - return "unknown"; -} - -#ifndef FTP_SERVER /* not used in server */ -static enum protection_level -name_to_level(const char *name) -{ - int i; - for(i = 0; i < sizeof(level_names) / sizeof(level_names[0]); i++) - if(!strncasecmp(level_names[i].name, name, strlen(name))) - return level_names[i].level; - return (enum protection_level)-1; -} -#endif - -#ifdef FTP_SERVER - -static struct sec_server_mech *mechs[] = { -#ifdef KRB5 - &gss_server_mech, -#endif - NULL -}; - -static struct sec_server_mech *mech; - -#else - -static struct sec_client_mech *mechs[] = { -#ifdef KRB5 - &gss_client_mech, -#endif - NULL -}; - -static struct sec_client_mech *mech; - -#endif - -static void *app_data; - -int -sec_getc(FILE *F) -{ - if(sec_complete && data_prot) { - char c; - if(sec_read(fileno(F), &c, 1) <= 0) - return EOF; - return c; - } else - return getc(F); -} - -static int -block_read(int fd, void *buf, size_t len) -{ - unsigned char *p = buf; - int b; - while(len) { - b = read(fd, p, len); - if (b == 0) - return 0; - else if (b < 0) - return -1; - len -= b; - p += b; - } - return p - (unsigned char*)buf; -} - -static int -block_write(int fd, void *buf, size_t len) -{ - unsigned char *p = buf; - int b; - while(len) { - b = write(fd, p, len); - if(b < 0) - return -1; - len -= b; - p += b; - } - return p - (unsigned char*)buf; -} - -static int -sec_get_data(int fd, struct buffer *buf, int level) -{ - int len; - int b; - void *tmp; - - b = block_read(fd, &len, sizeof(len)); - if (b == 0) - return 0; - else if (b < 0) - return -1; - len = ntohl(len); - tmp = realloc(buf->data, len); - if (tmp == NULL) - return -1; - buf->data = tmp; - b = block_read(fd, buf->data, len); - if (b == 0) - return 0; - else if (b < 0) - return -1; - buf->size = (*mech->decode)(app_data, buf->data, len, data_prot); - buf->index = 0; - return 0; -} - -static size_t -buffer_read(struct buffer *buf, void *dataptr, size_t len) -{ - len = min(len, buf->size - buf->index); - memcpy(dataptr, (char*)buf->data + buf->index, len); - buf->index += len; - return len; -} - -static size_t -buffer_write(struct buffer *buf, void *dataptr, size_t len) -{ - if(buf->index + len > buf->size) { - void *tmp; - if(buf->data == NULL) - tmp = malloc(1024); - else - tmp = realloc(buf->data, buf->index + len); - if(tmp == NULL) - return -1; - buf->data = tmp; - buf->size = buf->index + len; - } - memcpy((char*)buf->data + buf->index, dataptr, len); - buf->index += len; - return len; -} - -int -sec_read(int fd, void *dataptr, int length) -{ - size_t len; - int rx = 0; - - if(sec_complete == 0 || data_prot == 0) - return read(fd, dataptr, length); - - if(in_buffer.eof_flag){ - in_buffer.eof_flag = 0; - return 0; - } - - len = buffer_read(&in_buffer, dataptr, length); - length -= len; - rx += len; - dataptr = (char*)dataptr + len; - - while(length){ - int ret; - - ret = sec_get_data(fd, &in_buffer, data_prot); - if (ret < 0) - return -1; - if(ret == 0 && in_buffer.size == 0) { - if(rx) - in_buffer.eof_flag = 1; - return rx; - } - len = buffer_read(&in_buffer, dataptr, length); - length -= len; - rx += len; - dataptr = (char*)dataptr + len; - } - return rx; -} - -static int -sec_send(int fd, char *from, int length) -{ - int bytes; - void *buf; - bytes = (*mech->encode)(app_data, from, length, data_prot, &buf); - bytes = htonl(bytes); - block_write(fd, &bytes, sizeof(bytes)); - block_write(fd, buf, ntohl(bytes)); - free(buf); - return length; -} - -int -sec_fflush(FILE *F) -{ - if(data_prot != prot_clear) { - if(out_buffer.index > 0){ - sec_write(fileno(F), out_buffer.data, out_buffer.index); - out_buffer.index = 0; - } - sec_send(fileno(F), NULL, 0); - } - fflush(F); - return 0; -} - -int -sec_write(int fd, char *dataptr, int length) -{ - int len = buffer_size; - int tx = 0; - - if(data_prot == prot_clear) - return write(fd, dataptr, length); - - len -= (*mech->overhead)(app_data, data_prot, len); - while(length){ - if(length < len) - len = length; - sec_send(fd, dataptr, len); - length -= len; - dataptr += len; - tx += len; - } - return tx; -} - -int -sec_vfprintf2(FILE *f, const char *fmt, va_list ap) -{ - char *buf; - int ret; - if(data_prot == prot_clear) - return vfprintf(f, fmt, ap); - else { - int len; - len = vasprintf(&buf, fmt, ap); - if (len == -1) - return len; - ret = buffer_write(&out_buffer, buf, len); - free(buf); - return ret; - } -} - -int -sec_fprintf2(FILE *f, const char *fmt, ...) -{ - int ret; - va_list ap; - va_start(ap, fmt); - ret = sec_vfprintf2(f, fmt, ap); - va_end(ap); - return ret; -} - -int -sec_putc(int c, FILE *F) -{ - char ch = c; - if(data_prot == prot_clear) - return putc(c, F); - - buffer_write(&out_buffer, &ch, 1); - if(c == '\n' || out_buffer.index >= 1024 /* XXX */) { - sec_write(fileno(F), out_buffer.data, out_buffer.index); - out_buffer.index = 0; - } - return c; -} - -int -sec_read_msg(char *s, int level) -{ - int len; - char *buf; - int return_code; - - buf = malloc(strlen(s)); - len = base64_decode(s + 4, buf); /* XXX */ - - len = (*mech->decode)(app_data, buf, len, level); - if(len < 0) - return -1; - - buf[len] = '\0'; - - if(buf[3] == '-') - return_code = 0; - else - sscanf(buf, "%d", &return_code); - if(buf[len-1] == '\n') - buf[len-1] = '\0'; - strcpy(s, buf); - free(buf); - return return_code; -} - -int -sec_vfprintf(FILE *f, const char *fmt, va_list ap) -{ - char *buf; - void *enc; - int len; - if(!sec_complete) - return vfprintf(f, fmt, ap); - - if (vasprintf(&buf, fmt, ap) == -1) { - printf("Failed to allocate command.\n"); - return -1; - } - len = (*mech->encode)(app_data, buf, strlen(buf), command_prot, &enc); - free(buf); - if(len < 0) { - printf("Failed to encode command.\n"); - return -1; - } - if(base64_encode(enc, len, &buf) < 0){ - free(enc); - printf("Out of memory base64-encoding.\n"); - return -1; - } - free(enc); -#ifdef FTP_SERVER - if(command_prot == prot_safe) - fprintf(f, "631 %s\r\n", buf); - else if(command_prot == prot_private) - fprintf(f, "632 %s\r\n", buf); - else if(command_prot == prot_confidential) - fprintf(f, "633 %s\r\n", buf); -#else - if(command_prot == prot_safe) - fprintf(f, "MIC %s", buf); - else if(command_prot == prot_private) - fprintf(f, "ENC %s", buf); - else if(command_prot == prot_confidential) - fprintf(f, "CONF %s", buf); -#endif - free(buf); - return 0; -} - -int -sec_fprintf(FILE *f, const char *fmt, ...) -{ - va_list ap; - int ret; - va_start(ap, fmt); - ret = sec_vfprintf(f, fmt, ap); - va_end(ap); - return ret; -} - -/* end common stuff */ - -#ifdef FTP_SERVER - -int ccc_passed; - -void -auth(char *auth_name) -{ - int i; - void *tmp; - - for(i = 0; (mech = mechs[i]) != NULL; i++){ - if(!strcasecmp(auth_name, mech->name)){ - tmp = realloc(app_data, mech->size); - if (tmp == NULL) { - reply(431, "Unable to accept %s at this time", mech->name); - return; - } - app_data = tmp; - - if(mech->init && (*mech->init)(app_data) != 0) { - reply(431, "Unable to accept %s at this time", mech->name); - return; - } - if(mech->auth) { - (*mech->auth)(app_data); - return; - } - if(mech->adat) - reply(334, "Send authorization data."); - else - reply(234, "Authorization complete."); - return; - } - } - free (app_data); - app_data = NULL; - reply(504, "%s is unknown to me", auth_name); -} - -void -adat(char *auth_data) -{ - if(mech && !sec_complete) { - void *buf = malloc(strlen(auth_data)); - size_t len; - len = base64_decode(auth_data, buf); - (*mech->adat)(app_data, buf, len); - free(buf); - } else - reply(503, "You must %sissue an AUTH first.", mech ? "re-" : ""); -} - -void pbsz(int size) -{ - size_t new = size; - if(!sec_complete) - reply(503, "Incomplete security data exchange."); - if(mech->pbsz) - new = (*mech->pbsz)(app_data, size); - if(buffer_size != new){ - buffer_size = size; - } - if(new != size) - reply(200, "PBSZ=%lu", (unsigned long)new); - else - reply(200, "OK"); -} - -void -prot(char *pl) -{ - int p = -1; - - if(buffer_size == 0){ - reply(503, "No protection buffer size negotiated."); - return; - } - - if(!strcasecmp(pl, "C")) - p = prot_clear; - else if(!strcasecmp(pl, "S")) - p = prot_safe; - else if(!strcasecmp(pl, "E")) - p = prot_confidential; - else if(!strcasecmp(pl, "P")) - p = prot_private; - else { - reply(504, "Unrecognized protection level."); - return; - } - - if(sec_complete){ - if((*mech->check_prot)(app_data, p)){ - reply(536, "%s does not support %s protection.", - mech->name, level_to_name(p)); - }else{ - data_prot = (enum protection_level)p; - reply(200, "Data protection is %s.", level_to_name(p)); - } - }else{ - reply(503, "Incomplete security data exchange."); - } -} - -void ccc(void) -{ - if(sec_complete){ - if(mech->ccc && (*mech->ccc)(app_data) == 0) { - command_prot = data_prot = prot_clear; - ccc_passed = 1; - } else - reply(534, "You must be joking."); - }else - reply(503, "Incomplete security data exchange."); -} - -void mec(char *msg, enum protection_level level) -{ - void *buf; - size_t len, buf_size; - if(!sec_complete) { - reply(503, "Incomplete security data exchange."); - return; - } - buf_size = strlen(msg) + 2; - buf = malloc(buf_size); - if (buf == NULL) { - reply(501, "Failed to allocate %lu", (unsigned long)buf_size); - return; - } - len = base64_decode(msg, buf); - command_prot = level; - if(len == (size_t)-1) { - free(buf); - reply(501, "Failed to base64-decode command"); - return; - } - len = (*mech->decode)(app_data, buf, len, level); - if(len == (size_t)-1) { - free(buf); - reply(535, "Failed to decode command"); - return; - } - ((char*)buf)[len] = '\0'; - if(strstr((char*)buf, "\r\n") == NULL) - strlcat((char*)buf, "\r\n", buf_size); - new_ftp_command(buf); -} - -/* ------------------------------------------------------------ */ - -int -sec_userok(char *userstr) -{ - if(sec_complete) - return (*mech->userok)(app_data, userstr); - return 0; -} - -int -sec_session(char *user) -{ - if(sec_complete && mech->session) - return (*mech->session)(app_data, user); - return 0; -} - -char *ftp_command; - -void -new_ftp_command(char *command) -{ - ftp_command = command; -} - -void -delete_ftp_command(void) -{ - free(ftp_command); - ftp_command = NULL; -} - -int -secure_command(void) -{ - return ftp_command != NULL; -} - -enum protection_level -get_command_prot(void) -{ - return command_prot; -} - -#else /* FTP_SERVER */ - -void -sec_status(void) -{ - if(sec_complete){ - printf("Using %s for authentication.\n", mech->name); - printf("Using %s command channel.\n", level_to_name(command_prot)); - printf("Using %s data channel.\n", level_to_name(data_prot)); - if(buffer_size > 0) - printf("Protection buffer size: %lu.\n", - (unsigned long)buffer_size); - }else{ - printf("Not using any security mechanism.\n"); - } -} - -static int -sec_prot_internal(int level) -{ - int ret; - char *p; - unsigned int s = 1048576; - - int old_verbose = verbose; - verbose = 0; - - if(!sec_complete){ - printf("No security data exchange has taken place.\n"); - return -1; - } - - if(level){ - ret = command("PBSZ %u", s); - if(ret != COMPLETE){ - printf("Failed to set protection buffer size.\n"); - return -1; - } - buffer_size = s; - p = strstr(reply_string, "PBSZ="); - if(p) - sscanf(p, "PBSZ=%u", &s); - if(s < buffer_size) - buffer_size = s; - } - verbose = old_verbose; - ret = command("PROT %c", level["CSEP"]); /* XXX :-) */ - if(ret != COMPLETE){ - printf("Failed to set protection level.\n"); - return -1; - } - - data_prot = (enum protection_level)level; - return 0; -} - -enum protection_level -set_command_prot(enum protection_level level) -{ - int ret; - enum protection_level old = command_prot; - if(level != command_prot && level == prot_clear) { - ret = command("CCC"); - if(ret != COMPLETE) { - printf("Failed to clear command channel.\n"); - return -1; - } - } - command_prot = level; - return old; -} - -void -sec_prot(int argc, char **argv) -{ - int level = -1; - - if(argc > 3) - goto usage; - - if(argc == 1) { - sec_status(); - return; - } - if(!sec_complete) { - printf("No security data exchange has taken place.\n"); - code = -1; - return; - } - level = name_to_level(argv[argc - 1]); - - if(level == -1) - goto usage; - - if((*mech->check_prot)(app_data, level)) { - printf("%s does not implement %s protection.\n", - mech->name, level_to_name(level)); - code = -1; - return; - } - - if(argc == 2 || strncasecmp(argv[1], "data", strlen(argv[1])) == 0) { - if(sec_prot_internal(level) < 0){ - code = -1; - return; - } - } else if(strncasecmp(argv[1], "command", strlen(argv[1])) == 0) { - if(set_command_prot(level) < 0) { - code = -1; - return; - } - } else - goto usage; - code = 0; - return; - usage: - printf("usage: %s [command|data] [clear|safe|confidential|private]\n", - argv[0]); - code = -1; -} - -void -sec_prot_command(int argc, char **argv) -{ - int level; - - if(argc > 2) - goto usage; - - if(!sec_complete) { - printf("No security data exchange has taken place.\n"); - code = -1; - return; - } - - if(argc == 1) { - sec_status(); - } else { - level = name_to_level(argv[1]); - if(level == -1) - goto usage; - - if((*mech->check_prot)(app_data, level)) { - printf("%s does not implement %s protection.\n", - mech->name, level_to_name(level)); - code = -1; - return; - } - if(set_command_prot(level) < 0) { - code = -1; - return; - } - } - code = 0; - return; - usage: - printf("usage: %s [clear|safe|confidential|private]\n", - argv[0]); - code = -1; -} - -static enum protection_level request_data_prot; - -void -sec_set_protection_level(void) -{ - if(sec_complete && data_prot != request_data_prot) - sec_prot_internal(request_data_prot); -} - - -int -sec_request_prot(char *level) -{ - int l = name_to_level(level); - if(l == -1) - return -1; - request_data_prot = (enum protection_level)l; - return 0; -} - -int -sec_login(char *host) -{ - int ret; - struct sec_client_mech **m; - int old_verbose = verbose; - - verbose = -1; /* shut up all messages this will produce (they - are usually not very user friendly) */ - - for(m = mechs; *m && (*m)->name; m++) { - void *tmp; - - tmp = realloc(app_data, (*m)->size); - if (tmp == NULL) { - warnx ("realloc %lu failed", (unsigned long)(*m)->size); - return -1; - } - app_data = tmp; - - if((*m)->init && (*(*m)->init)(app_data) != 0) { - printf("Skipping %s...\n", (*m)->name); - continue; - } - printf("Trying %s...\n", (*m)->name); - ret = command("AUTH %s", (*m)->name); - if(ret != CONTINUE){ - if(code == 504){ - printf("%s is not supported by the server.\n", (*m)->name); - }else if(code == 534){ - printf("%s rejected as security mechanism.\n", (*m)->name); - }else if(ret == ERROR) { - printf("The server doesn't support the FTP " - "security extensions.\n"); - verbose = old_verbose; - return -1; - } - continue; - } - - ret = (*(*m)->auth)(app_data, host); - - if(ret == AUTH_CONTINUE) - continue; - else if(ret != AUTH_OK){ - /* mechanism is supposed to output error string */ - verbose = old_verbose; - return -1; - } - mech = *m; - sec_complete = 1; - if(doencrypt) { - command_prot = prot_private; - request_data_prot = prot_private; - } else { - command_prot = prot_safe; - } - break; - } - - verbose = old_verbose; - return *m == NULL; -} - -void -sec_end(void) -{ - if (mech != NULL) { - if(mech->end) - (*mech->end)(app_data); - if (app_data != NULL) { - memset(app_data, 0, mech->size); - free(app_data); - app_data = NULL; - } - } - sec_complete = 0; - data_prot = (enum protection_level)0; -} - -#endif /* FTP_SERVER */ - diff --git a/appl/ftp/ftp/security.h b/appl/ftp/ftp/security.h deleted file mode 100644 index 6567a6e45..000000000 --- a/appl/ftp/ftp/security.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 1998 - 2005 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* $Id$ */ - -#ifndef __security_h__ -#define __security_h__ - -enum protection_level { - prot_clear, - prot_safe, - prot_confidential, - prot_private -}; - -struct sec_client_mech { - char *name; - size_t size; - int (*init)(void *); - int (*auth)(void *, char*); - void (*end)(void *); - int (*check_prot)(void *, int); - int (*overhead)(void *, int, int); - int (*encode)(void *, void*, int, int, void**); - int (*decode)(void *, void*, int, int); -}; - -struct sec_server_mech { - char *name; - size_t size; - int (*init)(void *); - void (*end)(void *); - int (*check_prot)(void *, int); - int (*overhead)(void *, int, int); - int (*encode)(void *, void*, int, int, void**); - int (*decode)(void *, void*, int, int); - - int (*auth)(void *); - int (*adat)(void *, void*, size_t); - size_t (*pbsz)(void *, size_t); - int (*ccc)(void*); - int (*userok)(void*, char*); - int (*session)(void*, char*); -}; - -#define AUTH_OK 0 -#define AUTH_CONTINUE 1 -#define AUTH_ERROR 2 - -extern int ftp_do_gss_bindings; -extern int ftp_do_gss_delegate; -#ifdef FTP_SERVER -extern struct sec_server_mech krb4_server_mech, gss_server_mech; -#else -extern struct sec_client_mech krb4_client_mech, gss_client_mech; -#endif - -extern int sec_complete; - -#ifdef FTP_SERVER -extern char *ftp_command; -void new_ftp_command(char*); -void delete_ftp_command(void); -#endif - -/* ---- */ - - -int sec_fflush (FILE *); -int sec_fprintf (FILE *, const char *, ...) - __attribute__ ((format (printf, 2,3))); -int sec_getc (FILE *); -int sec_putc (int, FILE *); -int sec_read (int, void *, int); -int sec_read_msg (char *, int); -int sec_vfprintf (FILE *, const char *, va_list) - __attribute__ ((format (printf, 2,0))); -int sec_fprintf2(FILE *f, const char *fmt, ...) - __attribute__ ((format (printf, 2,3))); -int sec_vfprintf2(FILE *, const char *, va_list) - __attribute__ ((format (printf, 2,0))); -int sec_write (int, char *, int); - -#ifdef FTP_SERVER -void adat (char *); -void auth (char *); -void ccc (void); -void mec (char *, enum protection_level); -void pbsz (int); -void prot (char *); -void delete_ftp_command (void); -void new_ftp_command (char *); -int sec_userok (char *); -int sec_session(char *); -int secure_command (void); -enum protection_level get_command_prot(void); -#else -void sec_end (void); -int sec_login (char *); -void sec_prot (int, char **); -void sec_prot_command (int, char **); -int sec_request_prot (char *); -void sec_set_protection_level (void); -void sec_status (void); - -enum protection_level set_command_prot(enum protection_level); - -#endif - -#endif /* __security_h__ */ diff --git a/appl/ftp/ftpd/Makefile.am b/appl/ftp/ftpd/Makefile.am deleted file mode 100644 index cc0ad840f..000000000 --- a/appl/ftp/ftpd/Makefile.am +++ /dev/null @@ -1,54 +0,0 @@ -# $Id$ - -include $(top_srcdir)/Makefile.am.common - -AM_CPPFLAGS += -I$(srcdir)/../common $(INCLUDE_krb4) -DFTP_SERVER - -libexec_PROGRAMS = ftpd - -CHECK_LOCAL = - -if KRB5 -krb5_sources = gssapi.c gss_userok.c -endif - -ftpd_SOURCES = \ - extern.h \ - ftpcmd.y \ - ftpd.c \ - ftpd_locl.h \ - logwtmp.c \ - ls.c \ - pathnames.h \ - popen.c \ - security.c \ - kauth.c \ - klist.c \ - $(krb4_sources) \ - $(krb5_sources) - -EXTRA_ftpd_SOURCES = kauth.c gssapi.c gss_userok.c - -$(ftpd_OBJECTS): security.h - -security.c: - @test -f security.c || $(LN_S) $(srcdir)/../ftp/security.c . -security.h: - @test -f security.h || $(LN_S) $(srcdir)/../ftp/security.h . -gssapi.c: - @test -f gssapi.c || $(LN_S) $(srcdir)/../ftp/gssapi.c . - -CLEANFILES = security.c security.h gssapi.c - -man_MANS = ftpd.8 ftpusers.5 - -LDADD = ../common/libcommon.a \ - $(LIB_otp) \ - $(LIB_gssapi) \ - $(LIB_krb5) \ - $(LIB_kafs) \ - $(LIB_krb4) \ - $(LIB_hcrypto) \ - $(LIB_roken) - -EXTRA_DIST = $(man_MANS) diff --git a/appl/ftp/ftpd/extern.h b/appl/ftp/ftpd/extern.h deleted file mode 100644 index 3f48ec66e..000000000 --- a/appl/ftp/ftpd/extern.h +++ /dev/null @@ -1,150 +0,0 @@ -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)extern.h 8.2 (Berkeley) 4/4/94 - */ - -#ifndef _EXTERN_H_ -#define _EXTERN_H_ - -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif - -#include -#include -#ifdef HAVE_PWD_H -#include -#endif - -#ifdef HAVE_LIMITS_H -#include -#endif - -#ifndef NBBY -#define NBBY CHAR_BIT -#endif - -void abor(void); -void blkfree(char **); -char **copyblk(char **); -void cwd(const char *); -void do_delete(char *); -void dologout(int); -void eprt(char *); -void epsv(char *); -void fatal(char *); -int filename_check(char *); -int ftpd_pclose(FILE *); -FILE *ftpd_popen(char *, char *, int, int); -char *ftpd_getline(char *, int); -void ftpd_logwtmp(char *, char *, char *); -void lreply(int, const char *, ...) - __attribute__ ((format (printf, 2, 3))); -void makedir(char *); -void nack(char *); -void nreply(const char *, ...) - __attribute__ ((format (printf, 1, 2))); -void pass(char *); -void pasv(void); -void perror_reply(int, const char *); -void pwd(void); -void removedir(char *); -void renamecmd(char *, char *); -char *renamefrom(char *); -void reply(int, const char *, ...) - __attribute__ ((format (printf, 2, 3))); -void retrieve(const char *, char *); -void send_file_list(char *); -void setproctitle(const char *, ...) - __attribute__ ((format (printf, 1, 2))); -void statcmd(void); -void statfilecmd(char *); -void do_store(char *, char *, int); -void upper(char *); -void user(char *); -void yyerror(char *); - -void list_file(char*); - -void kauth(char *, char*); -void klist(void); -void cond_kdestroy(void); -void kdestroy(void); -void krbtkfile(const char *tkfile); -void afslog(const char *, int); -void afsunlog(void); - -extern int do_destroy_tickets; -extern char *k5ccname; - -int find(char *); - -int builtin_ls(FILE*, const char*); - -int do_login(int code, char *passwd); -int klogin(char *name, char *password); - -const char *ftp_rooted(const char *path); - -extern struct sockaddr *ctrl_addr, *his_addr; -extern char hostname[]; - -extern struct sockaddr *data_dest; -extern int logged_in; -extern struct passwd *pw; -extern int guest; -extern int dochroot; -extern int logging; -extern int type; -extern off_t file_size; -extern off_t byte_count; -extern int ccc_passed; - -extern int form; -extern int debug; -extern int ftpd_timeout; -extern int maxtimeout; -extern int pdata; -extern char hostname[], remotehost[]; -extern char proctitle[]; -extern int usedefault; -extern char tmpline[]; -extern int paranoid; - -#endif /* _EXTERN_H_ */ diff --git a/appl/ftp/ftpd/ftpcmd.y b/appl/ftp/ftpd/ftpcmd.y deleted file mode 100644 index 5fb8e8e2e..000000000 --- a/appl/ftp/ftpd/ftpcmd.y +++ /dev/null @@ -1,1478 +0,0 @@ -/* $NetBSD: ftpcmd.y,v 1.6 1995/06/03 22:46:45 mycroft Exp $ */ - -/* - * Copyright (c) 1985, 1988, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)ftpcmd.y 8.3 (Berkeley) 4/6/94 - */ - -/* - * Grammar for FTP commands. - * See RFC 959. - */ - -%{ - -#include "ftpd_locl.h" -RCSID("$Id$"); - -off_t restart_point; - -static int hasyyerrored; - - -static int cmd_type; -static int cmd_form; -static int cmd_bytesz; -char cbuf[64*1024]; -char *fromname; - -struct tab { - char *name; - short token; - short state; - short implemented; /* 1 if command is implemented */ - char *help; -}; - -extern struct tab cmdtab[]; -extern struct tab sitetab[]; - -static char *copy (char *); -static void help (struct tab *, char *); -static struct tab * - lookup (struct tab *, char *); -static void sizecmd (char *); -static RETSIGTYPE toolong (int); -static int yylex (void); - -/* This is for bison */ - -#if !defined(alloca) && !defined(HAVE_ALLOCA) -#define alloca(x) malloc(x) -#endif - -%} - -%union { - int i; - char *s; -} - -%token - A B C E F I - L N P R S T - - SP CRLF COMMA - - USER PASS ACCT REIN QUIT PORT - PASV TYPE STRU MODE RETR STOR - APPE MLFL MAIL MSND MSOM MSAM - MRSQ MRCP ALLO REST RNFR RNTO - ABOR DELE CWD LIST NLST SITE - sTAT HELP NOOP MKD RMD PWD - CDUP STOU SMNT SYST SIZE MDTM - EPRT EPSV - - UMASK IDLE CHMOD - - AUTH ADAT PROT PBSZ CCC MIC - CONF ENC - - KAUTH KLIST KDESTROY KRBTKFILE AFSLOG - LOCATE URL - - FEAT OPTS - - LEXERR - -%token STRING -%token NUMBER - -%type check_login check_login_no_guest check_secure octal_number byte_size -%type struct_code mode_code type_code form_code -%type pathstring pathname password username - -%start cmd_list - -%% - -cmd_list - : /* empty */ - | cmd_list cmd - { - fromname = (char *) 0; - restart_point = (off_t) 0; - } - | cmd_list rcmd - ; - -cmd - : USER SP username CRLF check_secure - { - if ($5) - user($3); - free($3); - } - | PASS SP password CRLF check_secure - { - if ($5) - pass($3); - memset ($3, 0, strlen($3)); - free($3); - } - - | PORT SP host_port CRLF check_secure - { - if ($5) { - if (paranoid && - (data_dest->sa_family != his_addr->sa_family || - (socket_get_port(data_dest) < IPPORT_RESERVED) || - memcmp(socket_get_address(data_dest), - socket_get_address(his_addr), - socket_addr_size(his_addr)) != 0)) { - usedefault = 1; - reply(500, "Illegal PORT range rejected."); - } else { - usedefault = 0; - if (pdata >= 0) { - close(pdata); - pdata = -1; - } - reply(200, "PORT command successful."); - } - } - } - | EPRT SP STRING CRLF check_secure - { - if ($5) - eprt ($3); - free ($3); - } - | PASV CRLF check_login - { - if($3) - pasv (); - } - | EPSV CRLF check_login - { - if($3) - epsv (NULL); - } - | EPSV SP STRING CRLF check_login - { - if($5) - epsv ($3); - free ($3); - } - | TYPE SP type_code CRLF check_secure - { - if ($5) { - switch (cmd_type) { - - case TYPE_A: - if (cmd_form == FORM_N) { - reply(200, "Type set to A."); - type = cmd_type; - form = cmd_form; - } else - reply(504, "Form must be N."); - break; - - case TYPE_E: - reply(504, "Type E not implemented."); - break; - - case TYPE_I: - reply(200, "Type set to I."); - type = cmd_type; - break; - - case TYPE_L: -#if NBBY == 8 - if (cmd_bytesz == 8) { - reply(200, - "Type set to L (byte size 8)."); - type = cmd_type; - } else - reply(504, "Byte size must be 8."); -#else /* NBBY == 8 */ - UNIMPLEMENTED for NBBY != 8 -#endif /* NBBY == 8 */ - } - } - } - | STRU SP struct_code CRLF check_secure - { - if ($5) { - switch ($3) { - - case STRU_F: - reply(200, "STRU F ok."); - break; - - default: - reply(504, "Unimplemented STRU type."); - } - } - } - | MODE SP mode_code CRLF check_secure - { - if ($5) { - switch ($3) { - - case MODE_S: - reply(200, "MODE S ok."); - break; - - default: - reply(502, "Unimplemented MODE type."); - } - } - } - | ALLO SP NUMBER CRLF check_secure - { - if ($5) { - reply(202, "ALLO command ignored."); - } - } - | ALLO SP NUMBER SP R SP NUMBER CRLF check_secure - { - if ($9) { - reply(202, "ALLO command ignored."); - } - } - | RETR SP pathname CRLF check_login - { - char *name = $3; - - if ($5 && name != NULL) - retrieve(0, name); - if (name != NULL) - free(name); - } - | STOR SP pathname CRLF check_login - { - char *name = $3; - - if ($5 && name != NULL) - do_store(name, "w", 0); - if (name != NULL) - free(name); - } - | APPE SP pathname CRLF check_login - { - char *name = $3; - - if ($5 && name != NULL) - do_store(name, "a", 0); - if (name != NULL) - free(name); - } - | NLST CRLF check_login - { - if ($3) - send_file_list("."); - } - | NLST SP STRING CRLF check_login - { - char *name = $3; - - if ($5 && name != NULL) - send_file_list(name); - if (name != NULL) - free(name); - } - | LIST CRLF check_login - { - if($3) - list_file("."); - } - | LIST SP pathname CRLF check_login - { - if($5) - list_file($3); - free($3); - } - | sTAT SP pathname CRLF check_login - { - if ($5 && $3 != NULL) - statfilecmd($3); - if ($3 != NULL) - free($3); - } - | sTAT CRLF check_secure - { - if ($3) - statcmd(); - } - | DELE SP pathname CRLF check_login_no_guest - { - if ($5 && $3 != NULL) - do_delete($3); - if ($3 != NULL) - free($3); - } - | RNTO SP pathname CRLF check_login_no_guest - { - if($5){ - if (fromname) { - renamecmd(fromname, $3); - free(fromname); - fromname = (char *) 0; - } else { - reply(503, "Bad sequence of commands."); - } - } - if ($3 != NULL) - free($3); - } - | ABOR CRLF check_secure - { - if ($3) - reply(225, "ABOR command successful."); - } - | CWD CRLF check_login - { - if ($3) { - const char *path = pw->pw_dir; - if (dochroot || guest) - path = "/"; - cwd(path); - } - } - | CWD SP pathname CRLF check_login - { - if ($5 && $3 != NULL) - cwd($3); - if ($3 != NULL) - free($3); - } - | HELP CRLF check_secure - { - if ($3) - help(cmdtab, (char *) 0); - } - | HELP SP STRING CRLF check_secure - { - if ($5) { - char *cp = $3; - - if (strncasecmp(cp, "SITE", 4) == 0) { - cp = $3 + 4; - if (*cp == ' ') - cp++; - if (*cp) - help(sitetab, cp); - else - help(sitetab, (char *) 0); - } else - help(cmdtab, $3); - } - } - | NOOP CRLF check_secure - { - if ($3) - reply(200, "NOOP command successful."); - } - | MKD SP pathname CRLF check_login - { - if ($5 && $3 != NULL) - makedir($3); - if ($3 != NULL) - free($3); - } - | RMD SP pathname CRLF check_login_no_guest - { - if ($5 && $3 != NULL) - removedir($3); - if ($3 != NULL) - free($3); - } - | PWD CRLF check_login - { - if ($3) - pwd(); - } - | CDUP CRLF check_login - { - if ($3) - cwd(".."); - } - | FEAT CRLF check_secure - { - if ($3) { - lreply(211, "Supported features:"); - lreply(0, " MDTM"); - lreply(0, " REST STREAM"); - lreply(0, " SIZE"); - reply(211, "End"); - } - } - | OPTS SP STRING CRLF check_secure - { - if ($5) - reply(501, "Bad options"); - free ($3); - } - - | SITE SP HELP CRLF check_secure - { - if ($5) - help(sitetab, (char *) 0); - } - | SITE SP HELP SP STRING CRLF check_secure - { - if ($7) - help(sitetab, $5); - } - | SITE SP UMASK CRLF check_login - { - if ($5) { - int oldmask = umask(0); - umask(oldmask); - reply(200, "Current UMASK is %03o", oldmask); - } - } - | SITE SP UMASK SP octal_number CRLF check_login_no_guest - { - if ($7) { - if (($5 == -1) || ($5 > 0777)) { - reply(501, "Bad UMASK value"); - } else { - int oldmask = umask($5); - reply(200, - "UMASK set to %03o (was %03o)", - $5, oldmask); - } - } - } - | SITE SP CHMOD SP octal_number SP pathname CRLF check_login_no_guest - { - if ($9 && $7 != NULL) { - if ($5 > 0777) - reply(501, - "CHMOD: Mode value must be between 0 and 0777"); - else if (chmod($7, $5) < 0) - perror_reply(550, $7); - else - reply(200, "CHMOD command successful."); - } - if ($7 != NULL) - free($7); - } - | SITE SP IDLE CRLF check_secure - { - if ($5) - reply(200, - "Current IDLE time limit is %d seconds; max %d", - ftpd_timeout, maxtimeout); - } - | SITE SP IDLE SP NUMBER CRLF check_secure - { - if ($7) { - if ($5 < 30 || $5 > maxtimeout) { - reply(501, - "Maximum IDLE time must be between 30 and %d seconds", - maxtimeout); - } else { - ftpd_timeout = $5; - alarm((unsigned) ftpd_timeout); - reply(200, - "Maximum IDLE time set to %d seconds", - ftpd_timeout); - } - } - } - - | SITE SP KAUTH SP STRING CRLF check_login - { - reply(500, "Command not implemented."); - } - | SITE SP KLIST CRLF check_login - { - if($5) - klist(); - } - | SITE SP KDESTROY CRLF check_login - { - reply(500, "Command not implemented."); - } - | SITE SP KRBTKFILE SP STRING CRLF check_login - { - reply(500, "Command not implemented."); - } - | SITE SP AFSLOG CRLF check_login - { -#if defined(KRB5) - if(guest) - reply(500, "Can't be done as guest."); - else if($5) - afslog(NULL, 0); -#else - reply(500, "Command not implemented."); -#endif - } - | SITE SP AFSLOG SP STRING CRLF check_login - { -#if defined(KRB5) - if(guest) - reply(500, "Can't be done as guest."); - else if($7) - afslog($5, 0); - if($5) - free($5); -#else - reply(500, "Command not implemented."); -#endif - } - | SITE SP LOCATE SP STRING CRLF check_login - { - if($7 && $5 != NULL) - find($5); - if($5 != NULL) - free($5); - } - | SITE SP URL CRLF check_secure - { - if ($5) - reply(200, "http://www.pdc.kth.se/heimdal/"); - } - | STOU SP pathname CRLF check_login - { - if ($5 && $3 != NULL) - do_store($3, "w", 1); - if ($3 != NULL) - free($3); - } - | SYST CRLF check_secure - { - if ($3) { -#if !defined(WIN32) && !defined(__EMX__) && !defined(__OS2__) && !defined(__CYGWIN32__) - reply(215, "UNIX Type: L%d", NBBY); -#else - reply(215, "UNKNOWN Type: L%d", NBBY); -#endif - } - } - - /* - * SIZE is not in RFC959, but Postel has blessed it and - * it will be in the updated RFC. - * - * Return size of file in a format suitable for - * using with RESTART (we just count bytes). - */ - | SIZE SP pathname CRLF check_login - { - if ($5 && $3 != NULL) - sizecmd($3); - if ($3 != NULL) - free($3); - } - - /* - * MDTM is not in RFC959, but Postel has blessed it and - * it will be in the updated RFC. - * - * Return modification time of file as an ISO 3307 - * style time. E.g. YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx - * where xxx is the fractional second (of any precision, - * not necessarily 3 digits) - */ - | MDTM SP pathname CRLF check_login - { - if ($5 && $3 != NULL) { - struct stat stbuf; - if (stat($3, &stbuf) < 0) - reply(550, "%s: %s", - $3, strerror(errno)); - else if (!S_ISREG(stbuf.st_mode)) { - reply(550, - "%s: not a plain file.", $3); - } else { - struct tm *t; - time_t mtime = stbuf.st_mtime; - - t = gmtime(&mtime); - reply(213, - "%04d%02d%02d%02d%02d%02d", - t->tm_year + 1900, - t->tm_mon + 1, - t->tm_mday, - t->tm_hour, - t->tm_min, - t->tm_sec); - } - } - if ($3 != NULL) - free($3); - } - | QUIT CRLF check_secure - { - if ($3) { - reply(221, "Goodbye."); - dologout(0); - } - } - | error CRLF - { - yyerrok; - } - ; -rcmd - : RNFR SP pathname CRLF check_login_no_guest - { - restart_point = (off_t) 0; - if ($5 && $3) { - fromname = renamefrom($3); - if (fromname == (char *) 0 && $3) { - free($3); - } - } - } - | REST SP byte_size CRLF check_secure - { - if ($5) { - fromname = (char *) 0; - restart_point = $3; /* XXX $3 is only "int" */ - reply(350, "Restarting at %ld. %s", - (long)restart_point, - "Send STORE or RETRIEVE to initiate transfer."); - } - } - | AUTH SP STRING CRLF - { - auth($3); - free($3); - } - | ADAT SP STRING CRLF - { - adat($3); - free($3); - } - | PBSZ SP NUMBER CRLF check_secure - { - if ($5) - pbsz($3); - } - | PROT SP STRING CRLF check_secure - { - if ($5) - prot($3); - } - | CCC CRLF check_secure - { - if ($3) - ccc(); - } - | MIC SP STRING CRLF - { - mec($3, prot_safe); - free($3); - } - | CONF SP STRING CRLF - { - mec($3, prot_confidential); - free($3); - } - | ENC SP STRING CRLF - { - mec($3, prot_private); - free($3); - } - ; - -username - : STRING - ; - -password - : /* empty */ - { - $$ = (char *)calloc(1, sizeof(char)); - } - | STRING - ; - -byte_size - : NUMBER - ; - -host_port - : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA - NUMBER COMMA NUMBER - { - struct sockaddr_in *sin4 = (struct sockaddr_in *)data_dest; - - sin4->sin_family = AF_INET; - sin4->sin_port = htons($9 * 256 + $11); - sin4->sin_addr.s_addr = - htonl(($1 << 24) | ($3 << 16) | ($5 << 8) | $7); - } - ; - -form_code - : N - { - $$ = FORM_N; - } - | T - { - $$ = FORM_T; - } - | C - { - $$ = FORM_C; - } - ; - -type_code - : A - { - cmd_type = TYPE_A; - cmd_form = FORM_N; - } - | A SP form_code - { - cmd_type = TYPE_A; - cmd_form = $3; - } - | E - { - cmd_type = TYPE_E; - cmd_form = FORM_N; - } - | E SP form_code - { - cmd_type = TYPE_E; - cmd_form = $3; - } - | I - { - cmd_type = TYPE_I; - } - | L - { - cmd_type = TYPE_L; - cmd_bytesz = NBBY; - } - | L SP byte_size - { - cmd_type = TYPE_L; - cmd_bytesz = $3; - } - /* this is for a bug in the BBN ftp */ - | L byte_size - { - cmd_type = TYPE_L; - cmd_bytesz = $2; - } - ; - -struct_code - : F - { - $$ = STRU_F; - } - | R - { - $$ = STRU_R; - } - | P - { - $$ = STRU_P; - } - ; - -mode_code - : S - { - $$ = MODE_S; - } - | B - { - $$ = MODE_B; - } - | C - { - $$ = MODE_C; - } - ; - -pathname - : pathstring - { - /* - * Problem: this production is used for all pathname - * processing, but only gives a 550 error reply. - * This is a valid reply in some cases but not in others. - */ - if (logged_in && $1 && *$1 == '~') { - glob_t gl; - int flags = - GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE; - - memset(&gl, 0, sizeof(gl)); - if (glob($1, flags, NULL, &gl) || - gl.gl_pathc == 0) { - reply(550, "not found"); - $$ = NULL; - } else { - $$ = strdup(gl.gl_pathv[0]); - } - globfree(&gl); - free($1); - } else - $$ = $1; - } - ; - -pathstring - : STRING - ; - -octal_number - : NUMBER - { - int ret, dec, multby, digit; - - /* - * Convert a number that was read as decimal number - * to what it would be if it had been read as octal. - */ - dec = $1; - multby = 1; - ret = 0; - while (dec) { - digit = dec%10; - if (digit > 7) { - ret = -1; - break; - } - ret += digit * multby; - multby *= 8; - dec /= 10; - } - $$ = ret; - } - ; - - -check_login_no_guest : check_login - { - $$ = $1 && !guest; - if($1 && !$$) - reply(550, "Permission denied"); - } - ; - -check_login : check_secure - { - if($1) { - if(($$ = logged_in) == 0) - reply(530, "Please login with USER and PASS."); - } else - $$ = 0; - } - ; - -check_secure : /* empty */ - { - $$ = 1; - if(sec_complete && !ccc_passed && !secure_command()) { - $$ = 0; - reply(533, "Command protection level denied " - "for paranoid reasons."); - } - } - ; - -%% - -#define CMD 0 /* beginning of command */ -#define ARGS 1 /* expect miscellaneous arguments */ -#define STR1 2 /* expect SP followed by STRING */ -#define STR2 3 /* expect STRING */ -#define OSTR 4 /* optional SP then STRING */ -#define ZSTR1 5 /* SP then optional STRING */ -#define ZSTR2 6 /* optional STRING after SP */ -#define SITECMD 7 /* SITE command */ -#define NSTR 8 /* Number followed by a string */ - -struct tab cmdtab[] = { /* In order defined in RFC 765 */ - { "USER", USER, STR1, 1, " username" }, - { "PASS", PASS, ZSTR1, 1, " password" }, - { "ACCT", ACCT, STR1, 0, "(specify account)" }, - { "SMNT", SMNT, ARGS, 0, "(structure mount)" }, - { "REIN", REIN, ARGS, 0, "(reinitialize server state)" }, - { "QUIT", QUIT, ARGS, 1, "(terminate service)", }, - { "PORT", PORT, ARGS, 1, " b0, b1, b2, b3, b4" }, - { "EPRT", EPRT, STR1, 1, " string" }, - { "PASV", PASV, ARGS, 1, "(set server in passive mode)" }, - { "EPSV", EPSV, OSTR, 1, "[ foo]" }, - { "TYPE", TYPE, ARGS, 1, " [ A | E | I | L ]" }, - { "STRU", STRU, ARGS, 1, "(specify file structure)" }, - { "MODE", MODE, ARGS, 1, "(specify transfer mode)" }, - { "RETR", RETR, STR1, 1, " file-name" }, - { "STOR", STOR, STR1, 1, " file-name" }, - { "APPE", APPE, STR1, 1, " file-name" }, - { "MLFL", MLFL, OSTR, 0, "(mail file)" }, - { "MAIL", MAIL, OSTR, 0, "(mail to user)" }, - { "MSND", MSND, OSTR, 0, "(mail send to terminal)" }, - { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" }, - { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" }, - { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" }, - { "MRCP", MRCP, STR1, 0, "(mail recipient)" }, - { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" }, - { "REST", REST, ARGS, 1, " offset (restart command)" }, - { "RNFR", RNFR, STR1, 1, " file-name" }, - { "RNTO", RNTO, STR1, 1, " file-name" }, - { "ABOR", ABOR, ARGS, 1, "(abort operation)" }, - { "DELE", DELE, STR1, 1, " file-name" }, - { "CWD", CWD, OSTR, 1, "[ directory-name ]" }, - { "XCWD", CWD, OSTR, 1, "[ directory-name ]" }, - { "LIST", LIST, OSTR, 1, "[ path-name ]" }, - { "NLST", NLST, OSTR, 1, "[ path-name ]" }, - { "SITE", SITE, SITECMD, 1, "site-cmd [ arguments ]" }, - { "SYST", SYST, ARGS, 1, "(get type of operating system)" }, - { "STAT", sTAT, OSTR, 1, "[ path-name ]" }, - { "HELP", HELP, OSTR, 1, "[ ]" }, - { "NOOP", NOOP, ARGS, 1, "" }, - { "MKD", MKD, STR1, 1, " path-name" }, - { "XMKD", MKD, STR1, 1, " path-name" }, - { "RMD", RMD, STR1, 1, " path-name" }, - { "XRMD", RMD, STR1, 1, " path-name" }, - { "PWD", PWD, ARGS, 1, "(return current directory)" }, - { "XPWD", PWD, ARGS, 1, "(return current directory)" }, - { "CDUP", CDUP, ARGS, 1, "(change to parent directory)" }, - { "XCUP", CDUP, ARGS, 1, "(change to parent directory)" }, - { "STOU", STOU, STR1, 1, " file-name" }, - { "SIZE", SIZE, OSTR, 1, " path-name" }, - { "MDTM", MDTM, OSTR, 1, " path-name" }, - - /* extensions from RFC2228 */ - { "AUTH", AUTH, STR1, 1, " auth-type" }, - { "ADAT", ADAT, STR1, 1, " auth-data" }, - { "PBSZ", PBSZ, ARGS, 1, " buffer-size" }, - { "PROT", PROT, STR1, 1, " prot-level" }, - { "CCC", CCC, ARGS, 1, "" }, - { "MIC", MIC, STR1, 1, " integrity command" }, - { "CONF", CONF, STR1, 1, " confidentiality command" }, - { "ENC", ENC, STR1, 1, " privacy command" }, - - /* RFC2389 */ - { "FEAT", FEAT, ARGS, 1, "" }, - { "OPTS", OPTS, ARGS, 1, " command [ options]" }, - - { NULL, 0, 0, 0, 0 } -}; - -struct tab sitetab[] = { - { "UMASK", UMASK, ARGS, 1, "[ umask ]" }, - { "IDLE", IDLE, ARGS, 1, "[ maximum-idle-time ]" }, - { "CHMOD", CHMOD, NSTR, 1, " mode file-name" }, - { "HELP", HELP, OSTR, 1, "[ ]" }, - - { "KAUTH", KAUTH, STR1, 1, " principal [ ticket ]" }, - { "KLIST", KLIST, ARGS, 1, "(show ticket file)" }, - { "KDESTROY", KDESTROY, ARGS, 1, "(destroy tickets)" }, - { "KRBTKFILE", KRBTKFILE, STR1, 1, " ticket-file" }, - { "AFSLOG", AFSLOG, OSTR, 1, "[ cell]" }, - - { "LOCATE", LOCATE, STR1, 1, " globexpr" }, - { "FIND", LOCATE, STR1, 1, " globexpr" }, - - { "URL", URL, ARGS, 1, "?" }, - - { NULL, 0, 0, 0, 0 } -}; - -static struct tab * -lookup(struct tab *p, char *cmd) -{ - - for (; p->name != NULL; p++) - if (strcmp(cmd, p->name) == 0) - return (p); - return (0); -} - -/* - * ftpd_getline - a hacked up version of fgets to ignore TELNET escape codes. - */ -char * -ftpd_getline(char *s, int n) -{ - int c; - char *cs; - - cs = s; - - /* might still be data within the security MIC/CONF/ENC */ - if(ftp_command){ - strlcpy(s, ftp_command, n); - if (debug) - syslog(LOG_DEBUG, "command: %s", s); - return s; - } - while ((c = getc(stdin)) != EOF) { - c &= 0377; - if (c == IAC) { - if ((c = getc(stdin)) != EOF) { - c &= 0377; - switch (c) { - case WILL: - case WONT: - c = getc(stdin); - printf("%c%c%c", IAC, DONT, 0377&c); - fflush(stdout); - continue; - case DO: - case DONT: - c = getc(stdin); - printf("%c%c%c", IAC, WONT, 0377&c); - fflush(stdout); - continue; - case IAC: - break; - default: - continue; /* ignore command */ - } - } - } - *cs++ = c; - if (--n <= 0 || c == '\n') - break; - } - if (c == EOF && cs == s) - return (NULL); - *cs++ = '\0'; - if (debug) { - if (!guest && strncasecmp("pass ", s, 5) == 0) { - /* Don't syslog passwords */ - syslog(LOG_DEBUG, "command: %.5s ???", s); - } else { - char *cp; - int len; - - /* Don't syslog trailing CR-LF */ - len = strlen(s); - cp = s + len - 1; - while (cp >= s && (*cp == '\n' || *cp == '\r')) { - --cp; - --len; - } - syslog(LOG_DEBUG, "command: %.*s", len, s); - } - } -#ifdef XXX - fprintf(stderr, "%s\n", s); -#endif - return (s); -} - -static RETSIGTYPE -toolong(int signo) -{ - - reply(421, - "Timeout (%d seconds): closing control connection.", - ftpd_timeout); - if (logging) - syslog(LOG_INFO, "User %s timed out after %d seconds", - (pw ? pw -> pw_name : "unknown"), ftpd_timeout); - dologout(1); - SIGRETURN(0); -} - -static int -yylex(void) -{ - static int cpos, state; - char *cp, *cp2; - struct tab *p; - int n; - char c; - - for (;;) { - switch (state) { - - case CMD: - hasyyerrored = 0; - - signal(SIGALRM, toolong); - alarm((unsigned) ftpd_timeout); - if (ftpd_getline(cbuf, sizeof(cbuf)-1) == NULL) { - reply(221, "You could at least say goodbye."); - dologout(0); - } - alarm(0); -#ifdef HAVE_SETPROCTITLE - if (strncasecmp(cbuf, "PASS", 4) != 0) - setproctitle("%s: %s", proctitle, cbuf); -#endif /* HAVE_SETPROCTITLE */ - if ((cp = strchr(cbuf, '\r'))) { - *cp++ = '\n'; - *cp = '\0'; - } - if ((cp = strpbrk(cbuf, " \n"))) - cpos = cp - cbuf; - if (cpos == 0) - cpos = 4; - c = cbuf[cpos]; - cbuf[cpos] = '\0'; - strupr(cbuf); - p = lookup(cmdtab, cbuf); - cbuf[cpos] = c; - if (p != 0) { - if (p->implemented == 0) { - nack(p->name); - hasyyerrored = 1; - break; - } - state = p->state; - yylval.s = p->name; - return (p->token); - } - break; - - case SITECMD: - if (cbuf[cpos] == ' ') { - cpos++; - return (SP); - } - cp = &cbuf[cpos]; - if ((cp2 = strpbrk(cp, " \n"))) - cpos = cp2 - cbuf; - c = cbuf[cpos]; - cbuf[cpos] = '\0'; - strupr(cp); - p = lookup(sitetab, cp); - cbuf[cpos] = c; - if (p != 0) { - if (p->implemented == 0) { - state = CMD; - nack(p->name); - hasyyerrored = 1; - break; - } - state = p->state; - yylval.s = p->name; - return (p->token); - } - state = CMD; - break; - - case OSTR: - if (cbuf[cpos] == '\n') { - state = CMD; - return (CRLF); - } - /* FALLTHROUGH */ - - case STR1: - case ZSTR1: - dostr1: - if (cbuf[cpos] == ' ') { - cpos++; - if(state == OSTR) - state = STR2; - else - state++; - return (SP); - } - break; - - case ZSTR2: - if (cbuf[cpos] == '\n') { - state = CMD; - return (CRLF); - } - /* FALLTHROUGH */ - - case STR2: - cp = &cbuf[cpos]; - n = strlen(cp); - cpos += n - 1; - /* - * Make sure the string is nonempty and \n terminated. - */ - if (n > 1 && cbuf[cpos] == '\n') { - cbuf[cpos] = '\0'; - yylval.s = copy(cp); - cbuf[cpos] = '\n'; - state = ARGS; - return (STRING); - } - break; - - case NSTR: - if (cbuf[cpos] == ' ') { - cpos++; - return (SP); - } - if (isdigit((unsigned char)cbuf[cpos])) { - cp = &cbuf[cpos]; - while (isdigit((unsigned char)cbuf[++cpos])) - ; - c = cbuf[cpos]; - cbuf[cpos] = '\0'; - yylval.i = atoi(cp); - cbuf[cpos] = c; - state = STR1; - return (NUMBER); - } - state = STR1; - goto dostr1; - - case ARGS: - if (isdigit((unsigned char)cbuf[cpos])) { - cp = &cbuf[cpos]; - while (isdigit((unsigned char)cbuf[++cpos])) - ; - c = cbuf[cpos]; - cbuf[cpos] = '\0'; - yylval.i = atoi(cp); - cbuf[cpos] = c; - return (NUMBER); - } - switch (cbuf[cpos++]) { - - case '\n': - state = CMD; - return (CRLF); - - case ' ': - return (SP); - - case ',': - return (COMMA); - - case 'A': - case 'a': - return (A); - - case 'B': - case 'b': - return (B); - - case 'C': - case 'c': - return (C); - - case 'E': - case 'e': - return (E); - - case 'F': - case 'f': - return (F); - - case 'I': - case 'i': - return (I); - - case 'L': - case 'l': - return (L); - - case 'N': - case 'n': - return (N); - - case 'P': - case 'p': - return (P); - - case 'R': - case 'r': - return (R); - - case 'S': - case 's': - return (S); - - case 'T': - case 't': - return (T); - - } - break; - - default: - fatal("Unknown state in scanner."); - } - yyerror(NULL); - state = CMD; - return (0); - } -} - -/* ARGSUSED */ -void -yyerror(char *s) -{ - char *cp; - - if (hasyyerrored) - return; - - if ((cp = strchr(cbuf,'\n'))) - *cp = '\0'; - reply(500, "'%s': command not understood.", cbuf); - hasyyerrored = 1; -} - -static char * -copy(char *s) -{ - char *p; - - p = strdup(s); - if (p == NULL) - fatal("Ran out of memory."); - return p; -} - -static void -help(struct tab *ctab, char *s) -{ - struct tab *c; - int width, NCMDS; - char *t; - char buf[1024]; - - if (ctab == sitetab) - t = "SITE "; - else - t = ""; - width = 0, NCMDS = 0; - for (c = ctab; c->name != NULL; c++) { - int len = strlen(c->name); - - if (len > width) - width = len; - NCMDS++; - } - width = (width + 8) &~ 7; - if (s == 0) { - int i, j, w; - int columns, lines; - - lreply(214, "The following %scommands are recognized %s.", - t, "(* =>'s unimplemented)"); - columns = 76 / width; - if (columns == 0) - columns = 1; - lines = (NCMDS + columns - 1) / columns; - for (i = 0; i < lines; i++) { - strlcpy (buf, " ", sizeof(buf)); - for (j = 0; j < columns; j++) { - c = ctab + j * lines + i; - snprintf (buf + strlen(buf), - sizeof(buf) - strlen(buf), - "%s%c", - c->name, - c->implemented ? ' ' : '*'); - if (c + lines >= &ctab[NCMDS]) - break; - w = strlen(c->name) + 1; - while (w < width) { - strlcat (buf, - " ", - sizeof(buf)); - w++; - } - } - lreply(214, "%s", buf); - } - reply(214, "Direct comments to kth-krb-bugs@pdc.kth.se"); - return; - } - strupr(s); - c = lookup(ctab, s); - if (c == (struct tab *)0) { - reply(502, "Unknown command %s.", s); - return; - } - if (c->implemented) - reply(214, "Syntax: %s%s %s", t, c->name, c->help); - else - reply(214, "%s%-*s\t%s; unimplemented.", t, width, - c->name, c->help); -} - -static void -sizecmd(char *filename) -{ - switch (type) { - case TYPE_L: - case TYPE_I: { - struct stat stbuf; - if (stat(filename, &stbuf) < 0 || !S_ISREG(stbuf.st_mode)) - reply(550, "%s: not a plain file.", filename); - else - reply(213, "%lu", (unsigned long)stbuf.st_size); - break; - } - case TYPE_A: { - FILE *fin; - int c; - size_t count; - struct stat stbuf; - fin = fopen(filename, "r"); - if (fin == NULL) { - perror_reply(550, filename); - return; - } - if (fstat(fileno(fin), &stbuf) < 0 || !S_ISREG(stbuf.st_mode)) { - reply(550, "%s: not a plain file.", filename); - fclose(fin); - return; - } - - count = 0; - while((c=getc(fin)) != EOF) { - if (c == '\n') /* will get expanded to \r\n */ - count++; - count++; - } - fclose(fin); - - reply(213, "%lu", (unsigned long)count); - break; - } - default: - reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]); - } -} diff --git a/appl/ftp/ftpd/ftpd.8 b/appl/ftp/ftpd/ftpd.8 deleted file mode 100644 index 0dfed9f75..000000000 --- a/appl/ftp/ftpd/ftpd.8 +++ /dev/null @@ -1,503 +0,0 @@ -.\" $NetBSD: ftpd.8,v 1.7 1995/04/11 02:44:53 cgd Exp $ -.\" -.\" Copyright (c) 1985, 1988, 1991, 1993 -.\" The Regents of the University of California. All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. -.\" 4. Neither the name of the University nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" @(#)ftpd.8 8.2 (Berkeley) 4/19/94 -.\" -.Dd July 19, 2003 -.Dt FTPD 8 -.Os BSD 4.2 -.Sh NAME -.Nm ftpd -.Nd Internet File Transfer Protocol server -.Sh SYNOPSIS -.Nm -.Op Fl a Ar authmode -.Op Fl dilvU -.Op Fl g Ar umask -.Op Fl p Ar port -.Op Fl T Ar maxtimeout -.Op Fl t Ar timeout -.Op Fl -gss-bindings -.Op Fl I | Fl -no-insecure-oob -.Op Fl u Ar default umask -.Op Fl B | Fl -builtin-ls -.Op Fl -good-chars= Ns Ar string -.Sh DESCRIPTION -.Nm Ftpd -is the -Internet File Transfer Protocol -server process. The server uses the -.Tn TCP -protocol -and listens at the port specified in the -.Dq ftp -service specification; see -.Xr services 5 . -.Pp -Available options: -.Bl -tag -width Ds -.It Fl a -Select the level of authentication required. Kerberised login can not -be turned off. The default is to only allow kerberised login. Other -possibilities can be turned on by giving a string of comma separated -flags as argument to -.Fl a . -Recognised flags are: -.Bl -tag -width plain -.It Ar plain -Allow logging in with plaintext password. The password can be a(n) OTP -or an ordinary password. -.It Ar otp -Same as -.Ar plain , -but only OTP is allowed. -.It Ar ftp -Allow anonymous login. -.El -.Pp -The following combination modes exists for backwards compatibility: -.Bl -tag -width plain -.It Ar none -Same as -.Ar plain,ftp . -.It Ar safe -Same as -.Ar ftp . -.It Ar user -Ignored. -.El -.It Fl d -Debugging information is written to the syslog using LOG_FTP. -.It Fl g -Anonymous users will get a umask of -.Ar umask . -.It Fl -gss-bindings -require the peer to use GSS-API bindings (ie make sure IP addresses match). -.It Fl i -Open a socket and wait for a connection. This is mainly used for -debugging when ftpd isn't started by inetd. -.It Fl l -Each successful and failed -.Xr ftp 1 -session is logged using syslog with a facility of LOG_FTP. -If this option is specified twice, the retrieve (get), store (put), append, -delete, make directory, remove directory and rename operations and -their filename arguments are also logged. -.It Fl p -Use -.Ar port -(a service name or number) instead of the default -.Ar ftp/tcp . -.It Fl T -A client may also request a different timeout period; -the maximum period allowed may be set to -.Ar timeout -seconds with the -.Fl T -option. -The default limit is 2 hours. -.It Fl t -The inactivity timeout period is set to -.Ar timeout -seconds (the default is 15 minutes). -.It Fl u -Set the initial umask to something else than the default 027. -.It Fl U -In previous versions of -.Nm ftpd , -when a passive mode client requested a data connection to the server, the -server would use data ports in the range 1024..4999. Now, by default, -if the system supports the IP_PORTRANGE socket option, the server will -use data ports in the range 49152..65535. Specifying this option will -revert to the old behavior. -.It Fl v -Verbose mode. -.It Xo -.Fl B , -.Fl -builtin-ls -.Xc -use built-in ls to list files -.It Xo -.Fl -good-chars= Ns Ar string -.Xc -allowed anonymous upload filename chars -.It Xo -.Fl I -.Fl -no-insecure-oob -.Xc -don't allow insecure out of band. -Heimdal ftp clients before 0.6.3 doesn't support secure oob, so turning -on this option makes them no longer work. -.El -.Pp -The file -.Pa /etc/nologin -can be used to disable ftp access. -If the file exists, -.Nm -displays it and exits. -If the file -.Pa /etc/ftpwelcome -exists, -.Nm -prints it before issuing the -.Dq ready -message. -If the file -.Pa /etc/motd -exists, -.Nm -prints it after a successful login. -.Pp -The ftp server currently supports the following ftp requests. -The case of the requests is ignored. -.Bl -column "Request" -offset indent -.It Request Ta "Description" -.It ABOR Ta "abort previous command" -.It ACCT Ta "specify account (ignored)" -.It ALLO Ta "allocate storage (vacuously)" -.It APPE Ta "append to a file" -.It CDUP Ta "change to parent of current working directory" -.It CWD Ta "change working directory" -.It DELE Ta "delete a file" -.It HELP Ta "give help information" -.It LIST Ta "give list files in a directory" Pq Dq Li "ls -lgA" -.It MKD Ta "make a directory" -.It MDTM Ta "show last modification time of file" -.It MODE Ta "specify data transfer" Em mode -.It NLST Ta "give name list of files in directory" -.It NOOP Ta "do nothing" -.It PASS Ta "specify password" -.It PASV Ta "prepare for server-to-server transfer" -.It PORT Ta "specify data connection port" -.It PWD Ta "print the current working directory" -.It QUIT Ta "terminate session" -.It REST Ta "restart incomplete transfer" -.It RETR Ta "retrieve a file" -.It RMD Ta "remove a directory" -.It RNFR Ta "specify rename-from file name" -.It RNTO Ta "specify rename-to file name" -.It SITE Ta "non-standard commands (see next section)" -.It SIZE Ta "return size of file" -.It STAT Ta "return status of server" -.It STOR Ta "store a file" -.It STOU Ta "store a file with a unique name" -.It STRU Ta "specify data transfer" Em structure -.It SYST Ta "show operating system type of server system" -.It TYPE Ta "specify data transfer" Em type -.It USER Ta "specify user name" -.It XCUP Ta "change to parent of current working directory (deprecated)" -.It XCWD Ta "change working directory (deprecated)" -.It XMKD Ta "make a directory (deprecated)" -.It XPWD Ta "print the current working directory (deprecated)" -.It XRMD Ta "remove a directory (deprecated)" -.El -.Pp -The following commands are specified by RFC2228. -.Bl -column Request -offset indent -.It AUTH Ta "authentication/security mechanism" -.It ADAT Ta "authentication/security data" -.It PROT Ta "data channel protection level" -.It PBSZ Ta "protection buffer size" -.It MIC Ta "integrity protected command" -.It CONF Ta "confidentiality protected command" -.It ENC Ta "privacy protected command" -.It CCC Ta "clear command channel" -.El -.Pp -The following non-standard or -.Tn UNIX -specific commands are supported -by the -SITE request. -.Pp -.Bl -column Request -offset indent -.It UMASK Ta change umask, (e.g. -.Ic "SITE UMASK 002" ) -.It IDLE Ta set idle-timer, (e.g. -.Ic "SITE IDLE 60" ) -.It CHMOD Ta change mode of a file (e.g. -.Ic "SITE CHMOD 755 filename" ) -.It FIND Ta quickly find a specific file with GNU -.Xr locate 1 . -.It HELP Ta give help information. -.El -.Pp -The following Kerberos related site commands are understood. -.Bl -column Request -offset indent -.It KAUTH Ta obtain remote tickets. -.It KLIST Ta show remote tickets -.El -.Pp -The remaining ftp requests specified in Internet RFC 959 -are -recognized, but not implemented. -MDTM and SIZE are not specified in RFC 959, but will appear in the -next updated FTP RFC. -.Pp -The ftp server will abort an active file transfer only when the -ABOR -command is preceded by a Telnet "Interrupt Process" (IP) -signal and a Telnet "Synch" signal in the command Telnet stream, -as described in Internet RFC 959. -If a -STAT -command is received during a data transfer, preceded by a Telnet IP -and Synch, transfer status will be returned. -.Pp -.Nm Ftpd -interprets file names according to the -.Dq globbing -conventions used by -.Xr csh 1 . -This allows users to use the metacharacters -.Dq Li \&*?[]{}~ . -.Pp -.Nm Ftpd -authenticates users according to these rules. -.Pp -.Bl -enum -offset indent -.It -If Kerberos authentication is used, the user must pass valid tickets -and the principal must be allowed to login as the remote user. -.It -The login name must be in the password data base, and not have a null -password (if Kerberos is used the password field is not checked). In -this case a password must be provided by the client before any file -operations may be performed. If the user has an OTP key, the response -from a successful USER command will include an OTP challenge. The -client may choose to respond with a PASS command giving either a -standard password or an OTP one-time password. The server will -automatically determine which type of password it has been given and -attempt to authenticate accordingly. See -.Xr otp 1 -for more information on OTP authentication. -.It -The login name must not appear in the file -.Pa /etc/ftpusers . -.It -The user must have a standard shell returned by -.Xr getusershell 3 . -.It -If the user name appears in the file -.Pa /etc/ftpchroot -the session's root will be changed to the user's login directory by -.Xr chroot 2 -as for an -.Dq anonymous -or -.Dq ftp -account (see next item). However, the user must still supply a password. -This feature is intended as a compromise between a fully anonymous account -and a fully privileged account. The account should also be set up as for an -anonymous account. -.It -If the user name is -.Dq anonymous -or -.Dq ftp , -an -anonymous ftp account must be present in the password -file (user -.Dq ftp ) . -In this case the user is allowed -to log in by specifying any password (by convention an email address for -the user should be used as the password). -.El -.Pp -In the last case, -.Nm ftpd -takes special measures to restrict the client's access privileges. -The server performs a -.Xr chroot 2 -to the home directory of the -.Dq ftp -user. -In order that system security is not breached, it is recommended -that the -.Dq ftp -subtree be constructed with care, consider following these guidelines -for anonymous ftp. -.Pp -In general all files should be owned by -.Dq root , -and have non-write permissions (644 or 755 depending on the kind of -file). No files should be owned or writable by -.Dq ftp -(possibly with exception for the -.Pa ~ftp/incoming , -as specified below). -.Bl -tag -width "~ftp/pub" -offset indent -.It Pa ~ftp -The -.Dq ftp -homedirectory should be owned by root. -.It Pa ~ftp/bin -The directory for external programs (such as -.Xr ls 1 ) . -These programs must either be statically linked, or you must setup an -environment for dynamic linking when running chrooted. -These programs will be used if present: -.Bl -tag -width "locate" -offset indent -.It ls -Used when listing files. -.It compress -When retrieving a filename that ends in -.Pa .Z , -and that file isn't present, -.Nm -will try to find the filename without -.Pa .Z -and compress it on the fly. -.It gzip -Same as compress, just with files ending in -.Pa .gz . -.It gtar -Enables retrieval of whole directories as files ending in -.Pa .tar . -Can also be combined with compression. You must use GNU Tar (or some -other that supports the -.Fl z -and -.Fl Z -flags). -.It locate -Will enable ``fast find'' with the -.Ic SITE FIND -command. You must also create a -.Pa locatedb -file in -.Pa ~ftp/etc . -.El -.It Pa ~ftp/etc -If you put copies of the -.Xr passwd 5 -and -.Xr group 5 -files here, ls will be able to produce owner names rather than -numbers. Remember to remove any passwords from these files. -.Pp -The file -.Pa motd , -if present, will be printed after a successful login. -.It Pa ~ftp/dev -Put a copy of -.Xr /dev/null 7 -here. -.It Pa ~ftp/pub -Traditional place to put whatever you want to make public. -.El -.Pp -If you want guests to be able to upload files, create a -.Pa ~ftp/incoming -directory owned by -.Dq root , -and group -.Dq ftp -with mode 730 (make sure -.Dq ftp -is member of group -.Dq ftp ) . -The following restrictions apply to anonymous users: -.Bl -bullet -.It -Directories created will have mode 700. -.It -Uploaded files will be created with an umask of 777, if not changed -with the -.Fl g -option. -.It -These command are not accessible: -.Ic DELE , RMD , RNTO , RNFR , -.Ic SITE UMASK , -and -.Ic SITE CHMOD . -.It -Filenames must start with an alpha-numeric character, and consist of -alpha-numeric characters or any of the following: -.Li \&+ -(plus), -.Li \&- -(minus), -.Li \&= -(equal), -.Li \&_ -(underscore), -.Li \&. -(period), and -.Li \&, -(comma). -.El -.Sh FILES -.Bl -tag -width /etc/ftpwelcome -compact -.It Pa /etc/ftpusers -Access list for users. -.It Pa /etc/ftpchroot -List of normal users who should be chroot'd. -.It Pa /etc/ftpwelcome -Welcome notice. -.It Pa /etc/motd -Welcome notice after login. -.It Pa /etc/nologin -Displayed and access refused. -.It Pa ~/.klogin -Login access for Kerberos. -.El -.Sh SEE ALSO -.Xr ftp 1 , -.Xr otp 1 , -.Xr getusershell 3 , -.Xr ftpusers 5 , -.Xr syslogd 8 -.Sh STANDARDS -.Bl -tag -compact -width "RFC 1938" -.It Cm RFC 959 -FTP PROTOCOL SPECIFICATION -.It Cm RFC 1938 -OTP Specification -.It Cm RFC 2228 -FTP Security Extensions. -.El -.Sh BUGS -The server must run as the super-user -to create sockets with privileged port numbers. It maintains -an effective user id of the logged in user, reverting to -the super-user only when binding addresses to sockets. The -possible security holes have been extensively -scrutinized, but are possibly incomplete. -.Sh HISTORY -The -.Nm -command appeared in -.Bx 4.2 . diff --git a/appl/ftp/ftpd/ftpd.c b/appl/ftp/ftpd/ftpd.c deleted file mode 100644 index 138f9b55e..000000000 --- a/appl/ftp/ftpd/ftpd.c +++ /dev/null @@ -1,2376 +0,0 @@ -/* - * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#define FTP_NAMES -#include "ftpd_locl.h" -#ifdef KRB5 -#include -#endif -#include "getarg.h" - -RCSID("$Id$"); - -static char version[] = "Version 6.00"; - -extern off_t restart_point; -extern char cbuf[]; - -struct sockaddr_storage ctrl_addr_ss; -struct sockaddr *ctrl_addr = (struct sockaddr *)&ctrl_addr_ss; - -struct sockaddr_storage data_source_ss; -struct sockaddr *data_source = (struct sockaddr *)&data_source_ss; - -struct sockaddr_storage data_dest_ss; -struct sockaddr *data_dest = (struct sockaddr *)&data_dest_ss; - -struct sockaddr_storage his_addr_ss; -struct sockaddr *his_addr = (struct sockaddr *)&his_addr_ss; - -struct sockaddr_storage pasv_addr_ss; -struct sockaddr *pasv_addr = (struct sockaddr *)&pasv_addr_ss; - -int data; -int logged_in; -struct passwd *pw; -int debug = 0; -int ftpd_timeout = 900; /* timeout after 15 minutes of inactivity */ -int maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */ -int restricted_data_ports = 1; -int logging; -int guest; -int dochroot; -int type; -int form; -int stru; /* avoid C keyword */ -int mode; -int usedefault = 1; /* for data transfers */ -int pdata = -1; /* for passive mode */ -int allow_insecure_oob = 1; -static int transflag; -static int urgflag; -off_t file_size; -off_t byte_count; -#if !defined(CMASK) || CMASK == 0 -#undef CMASK -#define CMASK 027 -#endif -int defumask = CMASK; /* default umask value */ -int guest_umask = 0777; /* Paranoia for anonymous users */ -char tmpline[10240]; -char hostname[MaxHostNameLen]; -char remotehost[MaxHostNameLen]; -static char ttyline[20]; -int paranoid = 1; - -#define AUTH_PLAIN (1 << 0) /* allow sending passwords */ -#define AUTH_OTP (1 << 1) /* passwords are one-time */ -#define AUTH_FTP (1 << 2) /* allow anonymous login */ - -static int auth_level = 0; /* Only allow kerberos login by default */ - -/* - * Timeout intervals for retrying connections - * to hosts that don't accept PORT cmds. This - * is a kludge, but given the problems with TCP... - */ -#define SWAITMAX 90 /* wait at most 90 seconds */ -#define SWAITINT 5 /* interval between retries */ - -int swaitmax = SWAITMAX; -int swaitint = SWAITINT; - -#ifdef HAVE_SETPROCTITLE -char proctitle[BUFSIZ]; /* initial part of title */ -#endif /* HAVE_SETPROCTITLE */ - -#define LOGCMD(cmd, file) \ - if (logging > 1) \ - syslog(LOG_INFO,"%s %s%s", cmd, \ - *(file) == '/' ? "" : curdir(), file); -#define LOGCMD2(cmd, file1, file2) \ - if (logging > 1) \ - syslog(LOG_INFO,"%s %s%s %s%s", cmd, \ - *(file1) == '/' ? "" : curdir(), file1, \ - *(file2) == '/' ? "" : curdir(), file2); -#define LOGBYTES(cmd, file, cnt) \ - if (logging > 1) { \ - if (cnt == (off_t)-1) \ - syslog(LOG_INFO,"%s %s%s", cmd, \ - *(file) == '/' ? "" : curdir(), file); \ - else \ - syslog(LOG_INFO, "%s %s%s = %ld bytes", \ - cmd, (*(file) == '/') ? "" : curdir(), file, (long)cnt); \ - } - -static void ack (char *); -static void myoob (int); -static int handleoobcmd(void); -static int checkuser (char *, char *); -static int checkaccess (char *); -static FILE *dataconn (const char *, off_t, const char *); -static void dolog (struct sockaddr *, int); -static void end_login (void); -static FILE *getdatasock (const char *, int); -static char *gunique (char *); -static RETSIGTYPE lostconn (int); -static int receive_data (FILE *, FILE *); -static void send_data (FILE *, FILE *); -static struct passwd * sgetpwnam (char *); - -static char * -curdir(void) -{ - static char path[MaxPathLen+1]; /* path + '/' + '\0' */ - - if (getcwd(path, sizeof(path)-1) == NULL) - return (""); - if (path[1] != '\0') /* special case for root dir. */ - strlcat(path, "/", sizeof(path)); - /* For guest account, skip / since it's chrooted */ - return (guest ? path+1 : path); -} - -#ifndef LINE_MAX -#define LINE_MAX 1024 -#endif - -static int -parse_auth_level(char *str) -{ - char *p; - int ret = 0; - char *foo = NULL; - - for(p = strtok_r(str, ",", &foo); - p; - p = strtok_r(NULL, ",", &foo)) { - if(strcmp(p, "user") == 0) - ; -#ifdef OTP - else if(strcmp(p, "otp") == 0) - ret |= AUTH_PLAIN|AUTH_OTP; -#endif - else if(strcmp(p, "ftp") == 0 || - strcmp(p, "safe") == 0) - ret |= AUTH_FTP; - else if(strcmp(p, "plain") == 0) - ret |= AUTH_PLAIN; - else if(strcmp(p, "none") == 0) - ret |= AUTH_PLAIN|AUTH_FTP; - else - warnx("bad value for -a: `%s'", p); - } - return ret; -} - -/* - * Print usage and die. - */ - -static int interactive_flag; -static char *guest_umask_string; -static char *port_string; -static char *umask_string; -static char *auth_string; - -int use_builtin_ls = -1; - -static int help_flag; -static int version_flag; - -static const char *good_chars = "+-=_,."; - -struct getargs args[] = { - { NULL, 'a', arg_string, &auth_string, "required authentication" }, - { NULL, 'i', arg_flag, &interactive_flag, "don't assume stdin is a socket" }, - { NULL, 'p', arg_string, &port_string, "what port to listen to" }, - { NULL, 'g', arg_string, &guest_umask_string, "umask for guest logins" }, - { NULL, 'l', arg_counter, &logging, "log more stuff", "" }, - { NULL, 't', arg_integer, &ftpd_timeout, "initial timeout" }, - { NULL, 'T', arg_integer, &maxtimeout, "max timeout" }, - { NULL, 'u', arg_string, &umask_string, "umask for user logins" }, - { NULL, 'U', arg_negative_flag, &restricted_data_ports, "don't use high data ports" }, - { NULL, 'd', arg_flag, &debug, "enable debugging" }, - { NULL, 'v', arg_flag, &debug, "enable debugging" }, - { "builtin-ls", 'B', arg_flag, &use_builtin_ls, "use built-in ls to list files" }, - { "good-chars", 0, arg_string, &good_chars, "allowed anonymous upload filename chars" }, - { "insecure-oob", 'I', arg_negative_flag, &allow_insecure_oob, "don't allow insecure OOB ABOR/STAT" }, -#ifdef KRB5 - { "gss-bindings", 0, arg_flag, &ftp_do_gss_bindings, "Require GSS-API bindings", NULL}, -#endif - { "version", 0, arg_flag, &version_flag }, - { "help", 'h', arg_flag, &help_flag } -}; - -static int num_args = sizeof(args) / sizeof(args[0]); - -static void -usage (int code) -{ - arg_printusage(args, num_args, NULL, ""); - exit (code); -} - -/* output contents of a file */ -static int -show_file(const char *file, int code) -{ - FILE *f; - char buf[128]; - - f = fopen(file, "r"); - if(f == NULL) - return -1; - while(fgets(buf, sizeof(buf), f)){ - buf[strcspn(buf, "\r\n")] = '\0'; - lreply(code, "%s", buf); - } - fclose(f); - return 0; -} - -int -main(int argc, char **argv) -{ - socklen_t his_addr_len, ctrl_addr_len; - int on = 1; - int port; - struct servent *sp; - - int optind = 0; - - setprogname (argv[0]); - - if(getarg(args, num_args, argc, argv, &optind)) - usage(1); - - if(help_flag) - usage(0); - - if(version_flag) { - print_version(NULL); - exit(0); - } - - if(auth_string) - auth_level = parse_auth_level(auth_string); - { - char *p; - long val = 0; - - if(guest_umask_string) { - val = strtol(guest_umask_string, &p, 8); - if (*p != '\0' || val < 0) - warnx("bad value for -g"); - else - guest_umask = val; - } - if(umask_string) { - val = strtol(umask_string, &p, 8); - if (*p != '\0' || val < 0) - warnx("bad value for -u"); - else - defumask = val; - } - } - sp = getservbyname("ftp", "tcp"); - if(sp) - port = sp->s_port; - else - port = htons(21); - if(port_string) { - sp = getservbyname(port_string, "tcp"); - if(sp) - port = sp->s_port; - else - if(isdigit((unsigned char)port_string[0])) - port = htons(atoi(port_string)); - else - warnx("bad value for -p"); - } - - if (maxtimeout < ftpd_timeout) - maxtimeout = ftpd_timeout; - -#if 0 - if (ftpd_timeout > maxtimeout) - ftpd_timeout = maxtimeout; -#endif - - if(interactive_flag) - mini_inetd (port); - - /* - * LOG_NDELAY sets up the logging connection immediately, - * necessary for anonymous ftp's that chroot and can't do it later. - */ - openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP); - his_addr_len = sizeof(his_addr_ss); - if (getpeername(STDIN_FILENO, his_addr, &his_addr_len) < 0) { - syslog(LOG_ERR, "getpeername (%s): %m",argv[0]); - exit(1); - } - ctrl_addr_len = sizeof(ctrl_addr_ss); - if (getsockname(STDIN_FILENO, ctrl_addr, &ctrl_addr_len) < 0) { - syslog(LOG_ERR, "getsockname (%s): %m",argv[0]); - exit(1); - } -#if defined(IP_TOS) && defined(HAVE_SETSOCKOPT) - { - int tos = IPTOS_LOWDELAY; - - if (setsockopt(STDIN_FILENO, IPPROTO_IP, IP_TOS, - (void *)&tos, sizeof(int)) < 0) - syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); - } -#endif - data_source->sa_family = ctrl_addr->sa_family; - socket_set_port (data_source, - htons(ntohs(socket_get_port(ctrl_addr)) - 1)); - - /* set this here so it can be put in wtmp */ - snprintf(ttyline, sizeof(ttyline), "ftp%u", (unsigned)getpid()); - - - /* freopen(_PATH_DEVNULL, "w", stderr); */ - signal(SIGPIPE, lostconn); - signal(SIGCHLD, SIG_IGN); -#ifdef SIGURG - if (signal(SIGURG, myoob) == SIG_ERR) - syslog(LOG_ERR, "signal: %m"); -#endif - - /* Try to handle urgent data inline */ -#if defined(SO_OOBINLINE) && defined(HAVE_SETSOCKOPT) - if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (void *)&on, - sizeof(on)) < 0) - syslog(LOG_ERR, "setsockopt: %m"); -#endif - -#ifdef F_SETOWN - if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1) - syslog(LOG_ERR, "fcntl F_SETOWN: %m"); -#endif - dolog(his_addr, his_addr_len); - /* - * Set up default state - */ - data = -1; - type = TYPE_A; - form = FORM_N; - stru = STRU_F; - mode = MODE_S; - tmpline[0] = '\0'; - - /* If logins are disabled, print out the message. */ - if(show_file(_PATH_NOLOGIN, 530) == 0) { - reply(530, "System not available."); - exit(0); - } - show_file(_PATH_FTPWELCOME, 220); - /* reply(220,) must follow */ - gethostname(hostname, sizeof(hostname)); - - reply(220, "%s FTP server (%s" -#ifdef KRB5 - "+%s" -#endif - ") ready.", hostname, version -#ifdef KRB5 - ,heimdal_version -#endif - ); - - for (;;) - yyparse(); - /* NOTREACHED */ -} - -static RETSIGTYPE -lostconn(int signo) -{ - - if (debug) - syslog(LOG_DEBUG, "lost connection"); - dologout(-1); -} - -/* - * Helper function for sgetpwnam(). - */ -static char * -sgetsave(char *s) -{ - char *new = strdup(s); - - if (new == NULL) { - perror_reply(421, "Local resource failure: malloc"); - dologout(1); - /* NOTREACHED */ - } - return new; -} - -/* - * Save the result of a getpwnam. Used for USER command, since - * the data returned must not be clobbered by any other command - * (e.g., globbing). - */ -static struct passwd * -sgetpwnam(char *name) -{ - static struct passwd save; - struct passwd *p; - - if ((p = k_getpwnam(name)) == NULL) - return (p); - if (save.pw_name) { - free(save.pw_name); - free(save.pw_passwd); - free(save.pw_gecos); - free(save.pw_dir); - free(save.pw_shell); - } - save = *p; - save.pw_name = sgetsave(p->pw_name); - save.pw_passwd = sgetsave(p->pw_passwd); - save.pw_gecos = sgetsave(p->pw_gecos); - save.pw_dir = sgetsave(p->pw_dir); - save.pw_shell = sgetsave(p->pw_shell); - return (&save); -} - -static int login_attempts; /* number of failed login attempts */ -static int askpasswd; /* had user command, ask for passwd */ -static char curname[10]; /* current USER name */ -#ifdef OTP -OtpContext otp_ctx; -#endif - -/* - * USER command. - * Sets global passwd pointer pw if named account exists and is acceptable; - * sets askpasswd if a PASS command is expected. If logged in previously, - * need to reset state. If name is "ftp" or "anonymous", the name is not in - * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return. - * If account doesn't exist, ask for passwd anyway. Otherwise, check user - * requesting login privileges. Disallow anyone who does not have a standard - * shell as returned by getusershell(). Disallow anyone mentioned in the file - * _PATH_FTPUSERS to allow people such as root and uucp to be avoided. - */ -void -user(char *name) -{ - char *cp, *shell; - - if(auth_level == 0 && !sec_complete){ - reply(530, "No login allowed without authorization."); - return; - } - - if (logged_in) { - if (guest) { - reply(530, "Can't change user from guest login."); - return; - } else if (dochroot) { - reply(530, "Can't change user from chroot user."); - return; - } - end_login(); - } - - guest = 0; - if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) { - if ((auth_level & AUTH_FTP) == 0 || - checkaccess("ftp") || - checkaccess("anonymous")) - reply(530, "User %s access denied.", name); - else if ((pw = sgetpwnam("ftp")) != NULL) { - guest = 1; - defumask = guest_umask; /* paranoia for incoming */ - askpasswd = 1; - reply(331, "Guest login ok, type your name as password."); - } else - reply(530, "User %s unknown.", name); - if (!askpasswd && logging) { - char data_addr[256]; - - if (inet_ntop (his_addr->sa_family, - socket_get_address(his_addr), - data_addr, sizeof(data_addr)) == NULL) - strlcpy (data_addr, "unknown address", - sizeof(data_addr)); - - syslog(LOG_NOTICE, - "ANONYMOUS FTP LOGIN REFUSED FROM %s(%s)", - remotehost, data_addr); - } - return; - } - if((auth_level & AUTH_PLAIN) == 0 && !sec_complete){ - reply(530, "Only authorized and anonymous login allowed."); - return; - } - if ((pw = sgetpwnam(name))) { - if ((shell = pw->pw_shell) == NULL || *shell == 0) - shell = _PATH_BSHELL; - while ((cp = getusershell()) != NULL) - if (strcmp(cp, shell) == 0) - break; - endusershell(); - - if (cp == NULL || checkaccess(name)) { - reply(530, "User %s access denied.", name); - if (logging) { - char data_addr[256]; - - if (inet_ntop (his_addr->sa_family, - socket_get_address(his_addr), - data_addr, - sizeof(data_addr)) == NULL) - strlcpy (data_addr, - "unknown address", - sizeof(data_addr)); - - syslog(LOG_NOTICE, - "FTP LOGIN REFUSED FROM %s(%s), %s", - remotehost, - data_addr, - name); - } - pw = (struct passwd *) NULL; - return; - } - } - if (logging) - strlcpy(curname, name, sizeof(curname)); - if(sec_complete) { - if(sec_userok(name) == 0) { - do_login(232, name); - sec_session(name); - } else - reply(530, "User %s access denied.", name); - } else { -#ifdef OTP - char ss[256]; - - if (otp_challenge(&otp_ctx, name, ss, sizeof(ss)) == 0) { - reply(331, "Password %s for %s required.", - ss, name); - askpasswd = 1; - } else -#endif - if ((auth_level & AUTH_OTP) == 0) { - reply(331, "Password required for %s.", name); - askpasswd = 1; - } else { -#ifdef OTP - char *s; - - if ((s = otp_error (&otp_ctx)) != NULL) - lreply(530, "OTP: %s", s); -#endif - reply(530, - "Only authorized, anonymous" -#ifdef OTP - " and OTP " -#endif - "login allowed."); - } - - } - /* - * Delay before reading passwd after first failed - * attempt to slow down passwd-guessing programs. - */ - if (login_attempts) - sleep(login_attempts); -} - -/* - * Check if a user is in the file "fname" - */ -static int -checkuser(char *fname, char *name) -{ - FILE *fd; - int found = 0; - char *p, line[BUFSIZ]; - - if ((fd = fopen(fname, "r")) != NULL) { - while (fgets(line, sizeof(line), fd) != NULL) - if ((p = strchr(line, '\n')) != NULL) { - *p = '\0'; - if (line[0] == '#') - continue; - if (strcmp(line, name) == 0) { - found = 1; - break; - } - } - fclose(fd); - } - return (found); -} - - -/* - * Determine whether a user has access, based on information in - * _PATH_FTPUSERS. The users are listed one per line, with `allow' - * or `deny' after the username. If anything other than `allow', or - * just nothing, is given after the username, `deny' is assumed. - * - * If the user is not found in the file, but the pseudo-user `*' is, - * the permission is taken from that line. - * - * This preserves the old semantics where if a user was listed in the - * file he was denied, otherwise he was allowed. - * - * Return 1 if the user is denied, or 0 if he is allowed. */ - -static int -match(const char *pattern, const char *string) -{ - return fnmatch(pattern, string, FNM_NOESCAPE); -} - -static int -checkaccess(char *name) -{ -#define ALLOWED 0 -#define NOT_ALLOWED 1 - FILE *fd; - int allowed = ALLOWED; - char *user, *perm, line[BUFSIZ]; - char *foo; - - fd = fopen(_PATH_FTPUSERS, "r"); - - if(fd == NULL) - return allowed; - - while (fgets(line, sizeof(line), fd) != NULL) { - foo = NULL; - user = strtok_r(line, " \t\n", &foo); - if (user == NULL || user[0] == '#') - continue; - perm = strtok_r(NULL, " \t\n", &foo); - if (match(user, name) == 0){ - if(perm && strcmp(perm, "allow") == 0) - allowed = ALLOWED; - else - allowed = NOT_ALLOWED; - break; - } - } - fclose(fd); - return allowed; -} -#undef ALLOWED -#undef NOT_ALLOWED - - -int do_login(int code, char *passwd) -{ - login_attempts = 0; /* this time successful */ - if (setegid((gid_t)pw->pw_gid) < 0) { - reply(550, "Can't set gid."); - return -1; - } - initgroups(pw->pw_name, pw->pw_gid); -#if defined(KRB5) - if(k_hasafs()) - k_setpag(); -#endif - - /* open wtmp before chroot */ - ftpd_logwtmp(ttyline, pw->pw_name, remotehost); - logged_in = 1; - - dochroot = checkuser(_PATH_FTPCHROOT, pw->pw_name); - if (guest) { - /* - * We MUST do a chdir() after the chroot. Otherwise - * the old current directory will be accessible as "." - * outside the new root! - */ - if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { - reply(550, "Can't set guest privileges."); - return -1; - } - } else if (dochroot) { - if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { - reply(550, "Can't change root."); - return -1; - } - } else if (chdir(pw->pw_dir) < 0) { - if (chdir("/") < 0) { - reply(530, "User %s: can't change directory to %s.", - pw->pw_name, pw->pw_dir); - return -1; - } else - lreply(code, "No directory! Logging in with home=/"); - } - if (seteuid((uid_t)pw->pw_uid) < 0) { - reply(550, "Can't set uid."); - return -1; - } - - if(use_builtin_ls == -1) { - struct stat st; - /* if /bin/ls exist and is a regular file, use it, otherwise - use built-in ls */ - if(stat("/bin/ls", &st) == 0 && - S_ISREG(st.st_mode)) - use_builtin_ls = 0; - else - use_builtin_ls = 1; - } - - /* - * Display a login message, if it exists. - * N.B. reply(code,) must follow the message. - */ - show_file(_PATH_FTPLOGINMESG, code); - if(show_file(_PATH_ISSUE_NET, code) != 0) - show_file(_PATH_ISSUE, code); - if (guest) { - reply(code, "Guest login ok, access restrictions apply."); -#ifdef HAVE_SETPROCTITLE - snprintf (proctitle, sizeof(proctitle), - "%s: anonymous/%s", - remotehost, - passwd); - setproctitle("%s", proctitle); -#endif /* HAVE_SETPROCTITLE */ - if (logging) { - char data_addr[256]; - - if (inet_ntop (his_addr->sa_family, - socket_get_address(his_addr), - data_addr, sizeof(data_addr)) == NULL) - strlcpy (data_addr, "unknown address", - sizeof(data_addr)); - - syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s(%s), %s", - remotehost, - data_addr, - passwd); - } - } else { - reply(code, "User %s logged in.", pw->pw_name); -#ifdef HAVE_SETPROCTITLE - snprintf(proctitle, sizeof(proctitle), "%s: %s", remotehost, pw->pw_name); - setproctitle("%s", proctitle); -#endif /* HAVE_SETPROCTITLE */ - if (logging) { - char data_addr[256]; - - if (inet_ntop (his_addr->sa_family, - socket_get_address(his_addr), - data_addr, sizeof(data_addr)) == NULL) - strlcpy (data_addr, "unknown address", - sizeof(data_addr)); - - syslog(LOG_INFO, "FTP LOGIN FROM %s(%s) as %s", - remotehost, - data_addr, - pw->pw_name); - } - } - umask(defumask); - return 0; -} - -/* - * Terminate login as previous user, if any, resetting state; - * used when USER command is given or login fails. - */ -static void -end_login(void) -{ - - if (seteuid((uid_t)0) < 0) - fatal("Failed to seteuid"); - if (logged_in) - ftpd_logwtmp(ttyline, "", ""); - pw = NULL; - logged_in = 0; - guest = 0; - dochroot = 0; -} - -#ifdef KRB5 -static int -krb5_verify(struct passwd *pwd, char *passwd) -{ - krb5_context context; - krb5_ccache id; - krb5_principal princ; - krb5_error_code ret; - - ret = krb5_init_context(&context); - if(ret) - return ret; - - ret = krb5_parse_name(context, pwd->pw_name, &princ); - if(ret){ - krb5_free_context(context); - return ret; - } - ret = krb5_cc_new_unique(context, "MEMORY", NULL, &id); - if(ret){ - krb5_free_principal(context, princ); - krb5_free_context(context); - return ret; - } - ret = krb5_verify_user(context, - princ, - id, - passwd, - 1, - NULL); - krb5_free_principal(context, princ); - if (k_hasafs()) { - krb5_afslog_uid_home(context, id,NULL, NULL,pwd->pw_uid, pwd->pw_dir); - } - krb5_cc_destroy(context, id); - krb5_free_context (context); - if(ret) - return ret; - return 0; -} -#endif /* KRB5 */ - -void -pass(char *passwd) -{ - int rval; - - /* some clients insists on sending a password */ - if (logged_in && askpasswd == 0){ - reply(230, "Password not necessary"); - return; - } - - if (logged_in || askpasswd == 0) { - reply(503, "Login with USER first."); - return; - } - askpasswd = 0; - rval = 1; - if (!guest) { /* "ftp" is only account allowed no password */ - if (pw == NULL) - rval = 1; /* failure below */ -#ifdef OTP - else if (otp_verify_user (&otp_ctx, passwd) == 0) { - rval = 0; - } -#endif - else if((auth_level & AUTH_OTP) == 0) { -#ifdef KRB5 - rval = krb5_verify(pw, passwd); -#endif - if (rval) - rval = unix_verify_user(pw->pw_name, passwd); - } else { -#ifdef OTP - char *s; - if ((s = otp_error(&otp_ctx)) != NULL) - lreply(530, "OTP: %s", s); -#endif - } - memset (passwd, 0, strlen(passwd)); - - /* - * If rval == 1, the user failed the authentication - * check above. If rval == 0, either Kerberos or - * local authentication succeeded. - */ - if (rval) { - char data_addr[256]; - - if (inet_ntop (his_addr->sa_family, - socket_get_address(his_addr), - data_addr, sizeof(data_addr)) == NULL) - strlcpy (data_addr, "unknown address", - sizeof(data_addr)); - - reply(530, "Login incorrect."); - if (logging) - syslog(LOG_NOTICE, - "FTP LOGIN FAILED FROM %s(%s), %s", - remotehost, - data_addr, - curname); - pw = NULL; - if (login_attempts++ >= 5) { - syslog(LOG_NOTICE, - "repeated login failures from %s(%s)", - remotehost, - data_addr); - exit(0); - } - return; - } - } - if(!do_login(230, passwd)) - return; - - /* Forget all about it... */ - end_login(); -} - -void -retrieve(const char *cmd, char *name) -{ - FILE *fin = NULL, *dout; - struct stat st; - int (*closefunc) (FILE *); - char line[BUFSIZ]; - - - if (cmd == 0) { - fin = fopen(name, "r"); - closefunc = fclose; - st.st_size = 0; - if(fin == NULL){ - int save_errno = errno; - struct cmds { - const char *ext; - const char *cmd; - const char *rev_cmd; - } cmds[] = { - {".tar", "/bin/gtar cPf - %s", NULL}, - {".tar.gz", "/bin/gtar zcPf - %s", NULL}, - {".tar.Z", "/bin/gtar ZcPf - %s", NULL}, - {".gz", "/bin/gzip -c -- %s", "/bin/gzip -c -d -- %s"}, - {".Z", "/bin/compress -c -- %s", "/bin/uncompress -c -- %s"}, - {NULL, NULL} - }; - struct cmds *p; - for(p = cmds; p->ext; p++){ - char *tail = name + strlen(name) - strlen(p->ext); - char c = *tail; - - if(strcmp(tail, p->ext) == 0 && - (*tail = 0) == 0 && - access(name, R_OK) == 0){ - snprintf (line, sizeof(line), p->cmd, name); - *tail = c; - break; - } - *tail = c; - if (p->rev_cmd != NULL) { - char *ext; - int ret; - - ret = asprintf(&ext, "%s%s", name, p->ext); - if (ret != -1) { - if (access(ext, R_OK) == 0) { - snprintf (line, sizeof(line), - p->rev_cmd, ext); - free(ext); - break; - } - free(ext); - } - } - - } - if(p->ext){ - fin = ftpd_popen(line, "r", 0, 0); - closefunc = ftpd_pclose; - st.st_size = -1; - cmd = line; - } else - errno = save_errno; - } - } else { - snprintf(line, sizeof(line), cmd, name); - name = line; - fin = ftpd_popen(line, "r", 1, 0); - closefunc = ftpd_pclose; - st.st_size = -1; - } - if (fin == NULL) { - if (errno != 0) { - perror_reply(550, name); - if (cmd == 0) { - LOGCMD("get", name); - } - } - return; - } - byte_count = -1; - if (cmd == 0){ - if(fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode)) { - reply(550, "%s: not a plain file.", name); - goto done; - } - } - if (restart_point) { - if (type == TYPE_A) { - off_t i, n; - int c; - - n = restart_point; - i = 0; - while (i++ < n) { - if ((c=getc(fin)) == EOF) { - perror_reply(550, name); - goto done; - } - if (c == '\n') - i++; - } - } else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) { - perror_reply(550, name); - goto done; - } - } - dout = dataconn(name, st.st_size, "w"); - if (dout == NULL) - goto done; - set_buffer_size(fileno(dout), 0); - send_data(fin, dout); - fclose(dout); - data = -1; - pdata = -1; -done: - if (cmd == 0) - LOGBYTES("get", name, byte_count); - (*closefunc)(fin); -} - -/* filename sanity check */ - -int -filename_check(char *filename) -{ - char *p; - - p = strrchr(filename, '/'); - if(p) - filename = p + 1; - - p = filename; - - if(isalnum((unsigned char)*p)){ - p++; - while(*p && (isalnum((unsigned char)*p) || strchr(good_chars, (unsigned char)*p))) - p++; - if(*p == '\0') - return 0; - } - lreply(553, "\"%s\" is not an acceptable filename.", filename); - lreply(553, "The filename must start with an alphanumeric " - "character and must only"); - reply(553, "consist of alphanumeric characters or any of the following: %s", - good_chars); - return 1; -} - -void -do_store(char *name, char *mode, int unique) -{ - FILE *fout, *din; - struct stat st; - int (*closefunc) (FILE *); - - if(guest && filename_check(name)) - return; - if (unique) { - char *uname; - if (stat(name, &st) == 0) { - if ((uname = gunique(name)) == NULL) - return; - name = uname; - } - LOGCMD(*mode == 'w' ? "put" : "append", name); - } - - if (restart_point) - mode = "r+"; - fout = fopen(name, mode); - closefunc = fclose; - if (fout == NULL) { - perror_reply(553, name); - LOGCMD(*mode == 'w' ? "put" : "append", name); - return; - } - byte_count = -1; - if (restart_point) { - if (type == TYPE_A) { - off_t i, n; - int c; - - n = restart_point; - i = 0; - while (i++ < n) { - if ((c=getc(fout)) == EOF) { - perror_reply(550, name); - goto done; - } - if (c == '\n') - i++; - } - /* - * We must do this seek to "current" position - * because we are changing from reading to - * writing. - */ - if (fseek(fout, 0L, SEEK_CUR) < 0) { - perror_reply(550, name); - goto done; - } - } else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) { - perror_reply(550, name); - goto done; - } - } - din = dataconn(name, (off_t)-1, "r"); - if (din == NULL) - goto done; - set_buffer_size(fileno(din), 1); - if (receive_data(din, fout) == 0) { - if((*closefunc)(fout) < 0) - perror_reply(552, name); - else { - if (unique) - reply(226, "Transfer complete (unique file name:%s).", - name); - else - reply(226, "Transfer complete."); - } - } else - (*closefunc)(fout); - fclose(din); - data = -1; - pdata = -1; -done: - LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count); -} - -static FILE * -getdatasock(const char *mode, int domain) -{ - int s, t, tries; - - if (data >= 0) - return (fdopen(data, mode)); - if (seteuid(0) < 0) - fatal("Failed to seteuid"); - s = socket(domain, SOCK_STREAM, 0); - if (s < 0) - goto bad; - socket_set_reuseaddr (s, 1); - /* anchor socket to avoid multi-homing problems */ - socket_set_address_and_port (data_source, - socket_get_address (ctrl_addr), - socket_get_port (data_source)); - - for (tries = 1; ; tries++) { - if (bind(s, data_source, - socket_sockaddr_size (data_source)) >= 0) - break; - if (errno != EADDRINUSE || tries > 10) - goto bad; - sleep(tries); - } - if (seteuid(pw->pw_uid) < 0) - fatal("Failed to seteuid"); -#ifdef IPTOS_THROUGHPUT - socket_set_tos (s, IPTOS_THROUGHPUT); -#endif - return (fdopen(s, mode)); -bad: - /* Return the real value of errno (close may change it) */ - t = errno; - if (seteuid((uid_t)pw->pw_uid) < 0) - fatal("Failed to seteuid"); - close(s); - errno = t; - return (NULL); -} - -static int -accept_with_timeout(int socket, - struct sockaddr *address, - socklen_t *address_len, - struct timeval *timeout) -{ - int ret; - fd_set rfd; - FD_ZERO(&rfd); - FD_SET(socket, &rfd); - ret = select(socket + 1, &rfd, NULL, NULL, timeout); - if(ret < 0) - return ret; - if(ret == 0) { - errno = ETIMEDOUT; - return -1; - } - return accept(socket, address, address_len); -} - -static FILE * -dataconn(const char *name, off_t size, const char *mode) -{ - char sizebuf[32]; - FILE *file; - int domain, retry = 0; - - file_size = size; - byte_count = 0; - if (size >= 0) - snprintf(sizebuf, sizeof(sizebuf), " (%ld bytes)", (long)size); - else - *sizebuf = '\0'; - if (pdata >= 0) { - struct sockaddr_storage from_ss; - struct sockaddr *from = (struct sockaddr *)&from_ss; - struct timeval timeout; - int s; - socklen_t fromlen = sizeof(from_ss); - - timeout.tv_sec = 15; - timeout.tv_usec = 0; - s = accept_with_timeout(pdata, from, &fromlen, &timeout); - if (s < 0) { - reply(425, "Can't open data connection."); - close(pdata); - pdata = -1; - return (NULL); - } - close(pdata); - pdata = s; -#if defined(IP_TOS) && defined(HAVE_SETSOCKOPT) - { - int tos = IPTOS_THROUGHPUT; - - setsockopt(s, IPPROTO_IP, IP_TOS, (void *)&tos, - sizeof(tos)); - } -#endif - reply(150, "Opening %s mode data connection for '%s'%s.", - type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); - return (fdopen(pdata, mode)); - } - if (data >= 0) { - reply(125, "Using existing data connection for '%s'%s.", - name, sizebuf); - usedefault = 1; - return (fdopen(data, mode)); - } - if (usedefault) - data_dest = his_addr; - usedefault = 1; - /* - * Default to using the same socket type as the ctrl address, - * unless we know the type of the data address. - */ - domain = data_dest->sa_family; - if (domain == PF_UNSPEC) - domain = ctrl_addr->sa_family; - - file = getdatasock(mode, domain); - if (file == NULL) { - char data_addr[256]; - - if (inet_ntop (data_source->sa_family, - socket_get_address(data_source), - data_addr, sizeof(data_addr)) == NULL) - strlcpy (data_addr, "unknown address", - sizeof(data_addr)); - - reply(425, "Can't create data socket (%s,%d): %s.", - data_addr, - socket_get_port (data_source), - strerror(errno)); - return (NULL); - } - data = fileno(file); - while (connect(data, data_dest, - socket_sockaddr_size(data_dest)) < 0) { - if (errno == EADDRINUSE && retry < swaitmax) { - sleep(swaitint); - retry += swaitint; - continue; - } - perror_reply(425, "Can't build data connection"); - fclose(file); - data = -1; - return (NULL); - } - reply(150, "Opening %s mode data connection for '%s'%s.", - type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); - return (file); -} - -/* - * Tranfer the contents of "instr" to "outstr" peer using the appropriate - * encapsulation of the data subject * to Mode, Structure, and Type. - * - * NB: Form isn't handled. - */ -static void -send_data(FILE *instr, FILE *outstr) -{ - int c, cnt, filefd, netfd; - static char *buf; - static size_t bufsize; - - transflag = 1; - switch (type) { - - case TYPE_A: - while ((c = getc(instr)) != EOF) { - if (urgflag && handleoobcmd()) - return; - byte_count++; - if(c == '\n') - sec_putc('\r', outstr); - sec_putc(c, outstr); - } - sec_fflush(outstr); - transflag = 0; - urgflag = 0; - if (ferror(instr)) - goto file_err; - if (ferror(outstr)) - goto data_err; - reply(226, "Transfer complete."); - return; - - case TYPE_I: - case TYPE_L: -#if 0 /* XXX handle urg flag */ -#if defined(HAVE_MMAP) && !defined(NO_MMAP) -#ifndef MAP_FAILED -#define MAP_FAILED (-1) -#endif - { - struct stat st; - char *chunk; - int in = fileno(instr); - if(fstat(in, &st) == 0 && S_ISREG(st.st_mode) - && st.st_size > 0) { - /* - * mmap zero bytes has potential of loosing, don't do it. - */ - chunk = mmap(0, st.st_size, PROT_READ, - MAP_SHARED, in, 0); - if((void *)chunk != (void *)MAP_FAILED) { - cnt = st.st_size - restart_point; - sec_write(fileno(outstr), chunk + restart_point, cnt); - if (munmap(chunk, st.st_size) < 0) - warn ("munmap"); - sec_fflush(outstr); - byte_count = cnt; - transflag = 0; - urgflag = 0; - } - } - } -#endif -#endif - if(transflag) { - struct stat st; - - netfd = fileno(outstr); - filefd = fileno(instr); - buf = alloc_buffer (buf, &bufsize, - fstat(filefd, &st) >= 0 ? &st : NULL); - if (buf == NULL) { - transflag = 0; - urgflag = 0; - perror_reply(451, "Local resource failure: malloc"); - return; - } - while ((cnt = read(filefd, buf, bufsize)) > 0 && - sec_write(netfd, buf, cnt) == cnt) { - byte_count += cnt; - if (urgflag && handleoobcmd()) - return; - } - sec_fflush(outstr); /* to end an encrypted stream */ - transflag = 0; - urgflag = 0; - if (cnt != 0) { - if (cnt < 0) - goto file_err; - goto data_err; - } - } - reply(226, "Transfer complete."); - return; - default: - transflag = 0; - urgflag = 0; - reply(550, "Unimplemented TYPE %d in send_data", type); - return; - } - -data_err: - transflag = 0; - urgflag = 0; - perror_reply(426, "Data connection"); - return; - -file_err: - transflag = 0; - urgflag = 0; - perror_reply(551, "Error on input file"); -} - -/* - * Transfer data from peer to "outstr" using the appropriate encapulation of - * the data subject to Mode, Structure, and Type. - * - * N.B.: Form isn't handled. - */ -static int -receive_data(FILE *instr, FILE *outstr) -{ - int cnt, bare_lfs = 0; - static char *buf; - static size_t bufsize; - struct stat st; - - transflag = 1; - - buf = alloc_buffer (buf, &bufsize, - fstat(fileno(outstr), &st) >= 0 ? &st : NULL); - if (buf == NULL) { - transflag = 0; - urgflag = 0; - perror_reply(451, "Local resource failure: malloc"); - return -1; - } - - switch (type) { - - case TYPE_I: - case TYPE_L: - while ((cnt = sec_read(fileno(instr), buf, bufsize)) > 0) { - if (write(fileno(outstr), buf, cnt) != cnt) - goto file_err; - byte_count += cnt; - if (urgflag && handleoobcmd()) - return (-1); - } - if (cnt < 0) - goto data_err; - transflag = 0; - urgflag = 0; - return (0); - - case TYPE_E: - reply(553, "TYPE E not implemented."); - transflag = 0; - urgflag = 0; - return (-1); - - case TYPE_A: - { - char *p, *q; - int cr_flag = 0; - while ((cnt = sec_read(fileno(instr), - buf + cr_flag, - bufsize - cr_flag)) > 0){ - if (urgflag && handleoobcmd()) - return (-1); - byte_count += cnt; - cnt += cr_flag; - cr_flag = 0; - for(p = buf, q = buf; p < buf + cnt;) { - if(*p == '\n') - bare_lfs++; - if(*p == '\r') { - if(p == buf + cnt - 1){ - cr_flag = 1; - p++; - continue; - }else if(p[1] == '\n'){ - *q++ = '\n'; - p += 2; - continue; - } - } - *q++ = *p++; - } - fwrite(buf, q - buf, 1, outstr); - if(cr_flag) - buf[0] = '\r'; - } - if(cr_flag) - putc('\r', outstr); - fflush(outstr); - if (ferror(instr)) - goto data_err; - if (ferror(outstr)) - goto file_err; - transflag = 0; - urgflag = 0; - if (bare_lfs) { - lreply(226, "WARNING! %d bare linefeeds received in ASCII mode\r\n" - " File may not have transferred correctly.\r\n", - bare_lfs); - } - return (0); - } - default: - reply(550, "Unimplemented TYPE %d in receive_data", type); - transflag = 0; - urgflag = 0; - return (-1); - } - -data_err: - transflag = 0; - urgflag = 0; - perror_reply(426, "Data Connection"); - return (-1); - -file_err: - transflag = 0; - urgflag = 0; - perror_reply(452, "Error writing file"); - return (-1); -} - -void -statfilecmd(char *filename) -{ - FILE *fin; - int c; - char line[LINE_MAX]; - - snprintf(line, sizeof(line), "/bin/ls -la -- %s", filename); - fin = ftpd_popen(line, "r", 1, 0); - lreply(211, "status of %s:", filename); - while ((c = getc(fin)) != EOF) { - if (c == '\n') { - if (ferror(stdout)){ - perror_reply(421, "control connection"); - ftpd_pclose(fin); - dologout(1); - /* NOTREACHED */ - } - if (ferror(fin)) { - perror_reply(551, filename); - ftpd_pclose(fin); - return; - } - putc('\r', stdout); - } - putc(c, stdout); - } - ftpd_pclose(fin); - reply(211, "End of Status"); -} - -void -statcmd(void) -{ -#if 0 - struct sockaddr_in *sin; - u_char *a, *p; - - lreply(211, "%s FTP server (%s) status:", hostname, version); - printf(" %s\r\n", version); - printf(" Connected to %s", remotehost); - if (!isdigit((unsigned char)remotehost[0])) - printf(" (%s)", inet_ntoa(his_addr.sin_addr)); - printf("\r\n"); - if (logged_in) { - if (guest) - printf(" Logged in anonymously\r\n"); - else - printf(" Logged in as %s\r\n", pw->pw_name); - } else if (askpasswd) - printf(" Waiting for password\r\n"); - else - printf(" Waiting for user name\r\n"); - printf(" TYPE: %s", typenames[type]); - if (type == TYPE_A || type == TYPE_E) - printf(", FORM: %s", formnames[form]); - if (type == TYPE_L) -#if NBBY == 8 - printf(" %d", NBBY); -#else - printf(" %d", bytesize); /* need definition! */ -#endif - printf("; STRUcture: %s; transfer MODE: %s\r\n", - strunames[stru], modenames[mode]); - if (data != -1) - printf(" Data connection open\r\n"); - else if (pdata != -1) { - printf(" in Passive mode"); - sin = &pasv_addr; - goto printaddr; - } else if (usedefault == 0) { - printf(" PORT"); - sin = &data_dest; -printaddr: - a = (u_char *) &sin->sin_addr; - p = (u_char *) &sin->sin_port; -#define UC(b) (((int) b) & 0xff) - printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]), - UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); -#undef UC - } else - printf(" No data connection\r\n"); -#endif - reply(211, "End of status"); -} - -void -fatal(char *s) -{ - - reply(451, "Error in server: %s\n", s); - reply(221, "Closing connection due to server error."); - dologout(0); - /* NOTREACHED */ -} - -static void -int_reply(int, char *, const char *, va_list) -#ifdef __GNUC__ -__attribute__ ((format (printf, 3, 0))) -#endif -; - -static void -int_reply(int n, char *c, const char *fmt, va_list ap) -{ - char buf[10240]; - char *p; - p=buf; - if(n){ - snprintf(p, sizeof(buf), "%d%s", n, c); - p+=strlen(p); - } - vsnprintf(p, sizeof(buf) - strlen(p), fmt, ap); - p+=strlen(p); - snprintf(p, sizeof(buf) - strlen(p), "\r\n"); - p+=strlen(p); - sec_fprintf(stdout, "%s", buf); - fflush(stdout); - if (debug) - syslog(LOG_DEBUG, "<--- %s- ", buf); -} - -void -reply(int n, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - int_reply(n, " ", fmt, ap); - delete_ftp_command(); - va_end(ap); -} - -void -lreply(int n, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - int_reply(n, "-", fmt, ap); - va_end(ap); -} - -void -nreply(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - int_reply(0, NULL, fmt, ap); - va_end(ap); -} - -static void -ack(char *s) -{ - - reply(250, "%s command successful.", s); -} - -void -nack(char *s) -{ - - reply(502, "%s command not implemented.", s); -} - -void -do_delete(char *name) -{ - struct stat st; - - LOGCMD("delete", name); - if (stat(name, &st) < 0) { - perror_reply(550, name); - return; - } - if (S_ISDIR(st.st_mode)) { - if (rmdir(name) < 0) { - perror_reply(550, name); - return; - } - goto done; - } - if (unlink(name) < 0) { - perror_reply(550, name); - return; - } -done: - ack("DELE"); -} - -void -cwd(const char *path) -{ - - if (chdir(path) < 0) - perror_reply(550, path); - else - ack("CWD"); -} - -void -makedir(char *name) -{ - - LOGCMD("mkdir", name); - if(guest && filename_check(name)) - return; - if (mkdir(name, 0777) < 0) - perror_reply(550, name); - else{ - if(guest) - chmod(name, 0700); /* guest has umask 777 */ - reply(257, "MKD command successful."); - } -} - -void -removedir(char *name) -{ - - LOGCMD("rmdir", name); - if (rmdir(name) < 0) - perror_reply(550, name); - else - ack("RMD"); -} - -void -pwd(void) -{ - char path[MaxPathLen]; - char *ret; - - /* SunOS has a broken getcwd that does popen(pwd) (!!!), this - * failes miserably when running chroot - */ - ret = getcwd(path, sizeof(path)); - if (ret == NULL) - reply(550, "%s.", strerror(errno)); - else - reply(257, "\"%s\" is current directory.", path); -} - -char * -renamefrom(char *name) -{ - struct stat st; - - if (stat(name, &st) < 0) { - perror_reply(550, name); - return NULL; - } - reply(350, "File exists, ready for destination name"); - return (name); -} - -void -renamecmd(char *from, char *to) -{ - - LOGCMD2("rename", from, to); - if(guest && filename_check(to)) - return; - if (rename(from, to) < 0) - perror_reply(550, "rename"); - else - ack("RNTO"); -} - -static void -dolog(struct sockaddr *sa, int len) -{ - getnameinfo_verified (sa, len, remotehost, sizeof(remotehost), - NULL, 0, 0); -#ifdef HAVE_SETPROCTITLE - snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost); - setproctitle("%s", proctitle); -#endif /* HAVE_SETPROCTITLE */ - - if (logging) { - char data_addr[256]; - - if (inet_ntop (his_addr->sa_family, - socket_get_address(his_addr), - data_addr, sizeof(data_addr)) == NULL) - strlcpy (data_addr, "unknown address", - sizeof(data_addr)); - - - syslog(LOG_INFO, "connection from %s(%s)", - remotehost, - data_addr); - } -} - -/* - * Record logout in wtmp file - * and exit with supplied status. - */ -void -dologout(int status) -{ - transflag = 0; - urgflag = 0; - if (logged_in) { -#if KRB5 - cond_kdestroy(); -#endif - seteuid((uid_t)0); /* No need to check, we call exit() below */ - ftpd_logwtmp(ttyline, "", ""); - } - /* beware of flushing buffers after a SIGPIPE */ -#ifdef XXX - exit(status); -#else - _exit(status); -#endif -} - -void abor(void) -{ - if (!transflag) - return; - reply(426, "Transfer aborted. Data connection closed."); - reply(226, "Abort successful"); - transflag = 0; -} - -static void -myoob(int signo) -{ - urgflag = 1; -} - -static char * -mec_space(char *p) -{ - while(isspace(*(unsigned char *)p)) - p++; - return p; -} - -static int -handleoobcmd(void) -{ - char *cp; - - /* only process if transfer occurring */ - if (!transflag) - return 0; - - urgflag = 0; - - cp = tmpline; - if (ftpd_getline(cp, sizeof(tmpline)) == NULL) { - reply(221, "You could at least say goodbye."); - dologout(0); - } - - if (strncasecmp("MIC", cp, 3) == 0) { - mec(mec_space(cp + 3), prot_safe); - } else if (strncasecmp("CONF", cp, 4) == 0) { - mec(mec_space(cp + 4), prot_confidential); - } else if (strncasecmp("ENC", cp, 3) == 0) { - mec(mec_space(cp + 3), prot_private); - } else if (!allow_insecure_oob) { - reply(533, "Command protection level denied " - "for paranoid reasons."); - goto out; - } - - if (secure_command()) - cp = ftp_command; - - if (strcasecmp(cp, "ABOR\r\n") == 0) { - abor(); - } else if (strcasecmp(cp, "STAT\r\n") == 0) { - if (file_size != (off_t) -1) - reply(213, "Status: %ld of %ld bytes transferred", - (long)byte_count, - (long)file_size); - else - reply(213, "Status: %ld bytes transferred", - (long)byte_count); - } -out: - return (transflag == 0); -} - -/* - * Note: a response of 425 is not mentioned as a possible response to - * the PASV command in RFC959. However, it has been blessed as - * a legitimate response by Jon Postel in a telephone conversation - * with Rick Adams on 25 Jan 89. - */ -void -pasv(void) -{ - socklen_t len; - char *p, *a; - struct sockaddr_in *sin; - - if (ctrl_addr->sa_family != AF_INET) { - reply(425, - "You cannot do PASV with something that's not IPv4"); - return; - } - - if(pdata != -1) - close(pdata); - - pdata = socket(ctrl_addr->sa_family, SOCK_STREAM, 0); - if (pdata < 0) { - perror_reply(425, "Can't open passive connection"); - return; - } - pasv_addr->sa_family = ctrl_addr->sa_family; - socket_set_address_and_port (pasv_addr, - socket_get_address (ctrl_addr), - 0); - socket_set_portrange(pdata, restricted_data_ports, - pasv_addr->sa_family); - if (seteuid(0) < 0) - fatal("Failed to seteuid"); - if (bind(pdata, pasv_addr, socket_sockaddr_size (pasv_addr)) < 0) { - if (seteuid(pw->pw_uid) < 0) - fatal("Failed to seteuid"); - goto pasv_error; - } - if (seteuid(pw->pw_uid) < 0) - fatal("Failed to seteuid"); - len = sizeof(pasv_addr_ss); - if (getsockname(pdata, pasv_addr, &len) < 0) - goto pasv_error; - if (listen(pdata, 1) < 0) - goto pasv_error; - sin = (struct sockaddr_in *)pasv_addr; - a = (char *) &sin->sin_addr; - p = (char *) &sin->sin_port; - -#define UC(b) (((int) b) & 0xff) - - reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]), - UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); - return; - -pasv_error: - close(pdata); - pdata = -1; - perror_reply(425, "Can't open passive connection"); - return; -} - -void -epsv(char *proto) -{ - socklen_t len; - - pdata = socket(ctrl_addr->sa_family, SOCK_STREAM, 0); - if (pdata < 0) { - perror_reply(425, "Can't open passive connection"); - return; - } - pasv_addr->sa_family = ctrl_addr->sa_family; - socket_set_address_and_port (pasv_addr, - socket_get_address (ctrl_addr), - 0); - socket_set_portrange(pdata, restricted_data_ports, - pasv_addr->sa_family); - if (seteuid(0) < 0) - fatal("Failed to seteuid"); - if (bind(pdata, pasv_addr, socket_sockaddr_size (pasv_addr)) < 0) { - if (seteuid(pw->pw_uid)) - fatal("Failed to seteuid"); - goto pasv_error; - } - if (seteuid(pw->pw_uid) < 0) - fatal("Failed to seteuid"); - len = sizeof(pasv_addr_ss); - if (getsockname(pdata, pasv_addr, &len) < 0) - goto pasv_error; - if (listen(pdata, 1) < 0) - goto pasv_error; - - reply(229, "Entering Extended Passive Mode (|||%d|)", - ntohs(socket_get_port (pasv_addr))); - return; - -pasv_error: - close(pdata); - pdata = -1; - perror_reply(425, "Can't open passive connection"); - return; -} - -void -eprt(char *str) -{ - char *end; - char sep; - int af; - int ret; - int port; - - usedefault = 0; - if (pdata >= 0) { - close(pdata); - pdata = -1; - } - - sep = *str++; - if (sep == '\0') { - reply(500, "Bad syntax in EPRT"); - return; - } - af = strtol (str, &end, 0); - if (af == 0 || *end != sep) { - reply(500, "Bad syntax in EPRT"); - return; - } - str = end + 1; - switch (af) { -#ifdef HAVE_IPV6 - case 2 : - data_dest->sa_family = AF_INET6; - break; -#endif - case 1 : - data_dest->sa_family = AF_INET; - break; - default : - reply(522, "Network protocol %d not supported, use (1" -#ifdef HAVE_IPV6 - ",2" -#endif - ")", af); - return; - } - end = strchr (str, sep); - if (end == NULL) { - reply(500, "Bad syntax in EPRT"); - return; - } - *end = '\0'; - ret = inet_pton (data_dest->sa_family, str, - socket_get_address (data_dest)); - - if (ret != 1) { - reply(500, "Bad address syntax in EPRT"); - return; - } - str = end + 1; - port = strtol (str, &end, 0); - if (port == 0 || *end != sep) { - reply(500, "Bad port syntax in EPRT"); - return; - } - if (port < IPPORT_RESERVED) { - reply(500, "Bad port in invalid range in EPRT"); - return; - } - socket_set_port (data_dest, htons(port)); - - if (paranoid && - (data_dest->sa_family != his_addr->sa_family || - memcmp(socket_get_address(data_dest), socket_get_address(his_addr), socket_sockaddr_size(data_dest)) != 0)) - { - reply(500, "Bad address in EPRT"); - } - reply(200, "EPRT command successful."); -} - -/* - * Generate unique name for file with basename "local". - * The file named "local" is already known to exist. - * Generates failure reply on error. - */ -static char * -gunique(char *local) -{ - static char new[MaxPathLen]; - struct stat st; - int count; - char *cp; - - cp = strrchr(local, '/'); - if (cp) - *cp = '\0'; - if (stat(cp ? local : ".", &st) < 0) { - perror_reply(553, cp ? local : "."); - return NULL; - } - if (cp) - *cp = '/'; - for (count = 1; count < 100; count++) { - snprintf (new, sizeof(new), "%s.%d", local, count); - if (stat(new, &st) < 0) - return (new); - } - reply(452, "Unique file name cannot be created."); - return (NULL); -} - -/* - * Format and send reply containing system error number. - */ -void -perror_reply(int code, const char *string) -{ - reply(code, "%s: %s.", string, strerror(errno)); -} - -static char *onefile[] = { - "", - 0 -}; - -void -list_file(char *file) -{ - if(use_builtin_ls) { - FILE *dout; - dout = dataconn(file, -1, "w"); - if (dout == NULL) - return; - set_buffer_size(fileno(dout), 0); - if(builtin_ls(dout, file) == 0) - reply(226, "Transfer complete."); - else - reply(451, "Requested action aborted. Local error in processing."); - fclose(dout); - data = -1; - pdata = -1; - } else { -#ifdef HAVE_LS_A - const char *cmd = "/bin/ls -lA %s"; -#else - const char *cmd = "/bin/ls -la %s"; -#endif - retrieve(cmd, file); - } -} - -void -send_file_list(char *whichf) -{ - struct stat st; - DIR *dirp = NULL; - struct dirent *dir; - FILE *dout = NULL; - char **dirlist, *dirname; - int simple = 0; - int freeglob = 0; - glob_t gl; - char buf[MaxPathLen]; - - if (strpbrk(whichf, "~{[*?") != NULL) { - int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE| -#ifdef GLOB_MAXPATH - GLOB_MAXPATH -#else - GLOB_LIMIT -#endif - ; - - memset(&gl, 0, sizeof(gl)); - freeglob = 1; - if (glob(whichf, flags, 0, &gl)) { - reply(550, "not found"); - goto out; - } else if (gl.gl_pathc == 0) { - errno = ENOENT; - perror_reply(550, whichf); - goto out; - } - dirlist = gl.gl_pathv; - } else { - onefile[0] = whichf; - dirlist = onefile; - simple = 1; - } - - while ((dirname = *dirlist++)) { - - if (urgflag && handleoobcmd()) - goto out; - - if (stat(dirname, &st) < 0) { - /* - * If user typed "ls -l", etc, and the client - * used NLST, do what the user meant. - */ - if (dirname[0] == '-' && *dirlist == NULL && - transflag == 0) { - list_file(dirname); - goto out; - } - perror_reply(550, whichf); - goto out; - } - - if (S_ISREG(st.st_mode)) { - if (dout == NULL) { - dout = dataconn("file list", (off_t)-1, "w"); - if (dout == NULL) - goto out; - transflag = 1; - } - snprintf(buf, sizeof(buf), "%s%s\n", dirname, - type == TYPE_A ? "\r" : ""); - sec_write(fileno(dout), buf, strlen(buf)); - byte_count += strlen(dirname) + 1; - continue; - } else if (!S_ISDIR(st.st_mode)) - continue; - - if ((dirp = opendir(dirname)) == NULL) - continue; - - while ((dir = readdir(dirp)) != NULL) { - char nbuf[MaxPathLen]; - - if (urgflag && handleoobcmd()) - goto out; - - if (!strcmp(dir->d_name, ".")) - continue; - if (!strcmp(dir->d_name, "..")) - continue; - - snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname, dir->d_name); - - /* - * We have to do a stat to insure it's - * not a directory or special file. - */ - if (simple || (stat(nbuf, &st) == 0 && - S_ISREG(st.st_mode))) { - if (dout == NULL) { - dout = dataconn("file list", (off_t)-1, "w"); - if (dout == NULL) - goto out; - transflag = 1; - } - if(strncmp(nbuf, "./", 2) == 0) - snprintf(buf, sizeof(buf), "%s%s\n", nbuf +2, - type == TYPE_A ? "\r" : ""); - else - snprintf(buf, sizeof(buf), "%s%s\n", nbuf, - type == TYPE_A ? "\r" : ""); - sec_write(fileno(dout), buf, strlen(buf)); - byte_count += strlen(nbuf) + 1; - } - } - closedir(dirp); - } - if (dout == NULL) - reply(550, "No files found."); - else if (ferror(dout) != 0) - perror_reply(550, "Data connection"); - else - reply(226, "Transfer complete."); - -out: - transflag = 0; - if (dout != NULL){ - sec_write(fileno(dout), buf, 0); /* XXX flush */ - - fclose(dout); - } - data = -1; - pdata = -1; - if (freeglob) - globfree(&gl); -} - - -int -find(char *pattern) -{ - char line[1024]; - FILE *f; - - snprintf(line, sizeof(line), - "/bin/locate -d %s -- %s", - ftp_rooted("/etc/locatedb"), - pattern); - f = ftpd_popen(line, "r", 1, 1); - if(f == NULL){ - perror_reply(550, "/bin/locate"); - return 1; - } - lreply(200, "Output from find."); - while(fgets(line, sizeof(line), f)){ - if(line[strlen(line)-1] == '\n') - line[strlen(line)-1] = 0; - nreply("%s", line); - } - reply(200, "Done"); - ftpd_pclose(f); - return 0; -} - diff --git a/appl/ftp/ftpd/ftpd_locl.h b/appl/ftp/ftpd/ftpd_locl.h deleted file mode 100644 index cff3ff3d4..000000000 --- a/appl/ftp/ftpd/ftpd_locl.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 1998 - 2000 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* $Id$ */ - -#ifndef __ftpd_locl_h__ -#define __ftpd_locl_h__ - -#ifdef HAVE_CONFIG_H -#include -#endif - -/* - * FTP server. - */ -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_PARAM_H -#include -#endif -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#if defined(HAVE_SYS_IOCTL_H) && SunOS != 40 -#include -#endif -#ifdef HAVE_SYS_IOCCOM_H -#include -#endif -#ifdef TIME_WITH_SYS_TIME -#include -#include -#elif defined(HAVE_SYS_TIME_H) -#include -#else -#include -#endif -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif -#ifdef HAVE_SYS_WAIT_H -#include -#endif - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETINET_IN_SYSTM_H -#include -#endif -#ifdef HAVE_NETINET_IP_H -#include -#endif - -#ifdef HAVE_SYS_MMAN_H -#include -#endif - -#include -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_ARPA_TELNET_H -#include -#endif - -#include -#ifdef HAVE_DIRENT_H -#include -#endif -#include -#ifdef HAVE_FCNTL_H -#include -#endif -#include -#include -#ifdef HAVE_PWD_H -#include -#endif -#include -#include -#include -#include -#include -#ifdef HAVE_SYSLOG_H -#include -#endif -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_GRP_H -#include -#endif -#include - -#ifdef HAVE_BSD_BSD_H -#include -#endif - -#include -#include "roken.h" - -#include "pathnames.h" -#include "extern.h" -#include "common.h" - -#include "security.h" - -#ifdef KRB5 -#include -#endif /* KRB5 */ - -#if defined(KRB5) -#include -#endif - -#ifdef OTP -#include -#endif - -#ifdef SOCKS -#include -extern int LIBPREFIX(fclose) (FILE *); -#endif - -/* SunOS doesn't have any declaration of fclose */ - -int fclose(FILE *stream); - -int yyparse(void); - -#ifndef LOG_FTP -#define LOG_FTP LOG_DAEMON -#endif - -#endif /* __ftpd_locl_h__ */ diff --git a/appl/ftp/ftpd/ftpusers.5 b/appl/ftp/ftpd/ftpusers.5 deleted file mode 100644 index 2e00a2b26..000000000 --- a/appl/ftp/ftpd/ftpusers.5 +++ /dev/null @@ -1,37 +0,0 @@ -.\" $Id$ -.\" -.Dd May 7, 1997 -.Dt FTPUSERS 5 -.Os KTH-KRB -.Sh NAME -.Pa /etc/ftpusers -.Nd FTP access list file -.Sh DESCRIPTION -.Pa /etc/ftpusers -contains a list of users that should be allowed or denied FTP -access. Each line contains a user, optionally followed by -.Dq allow -(anything but -.Dq allow -is ignored). The semi-user -.Dq * -matches any user. Users that has an explicit -.Dq allow , -or that does not match any line, are allowed access. Anyone else is -denied access. -.Pp -Note that this is compatible with the old format, where this file -contained a list of users that should be denied access. -.Sh EXAMPLES -This will deny anyone but -.Dq foo -and -.Dq bar -to use FTP: -.Bd -literal -foo allow -bar allow -* -.Ed -.Sh SEE ALSO -.Xr ftpd 8 diff --git a/appl/ftp/ftpd/gss_userok.c b/appl/ftp/ftpd/gss_userok.c deleted file mode 100644 index d65c581a9..000000000 --- a/appl/ftp/ftpd/gss_userok.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 1998 - 2001 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "ftpd_locl.h" -#include -#include -#include - -/* XXX a bit too much of krb5 dependency here... - What is the correct way to do this? - */ - -struct gss_krb5_data { - krb5_context context; -}; - -/* XXX sync with gssapi.c */ -struct gss_data { - gss_ctx_id_t context_hdl; - char *client_name; - gss_cred_id_t delegated_cred_handle; - void *mech_data; -}; - -int gss_userok(void*, char*); /* to keep gcc happy */ -int gss_session(void*, char*); /* to keep gcc happy */ - -int -gss_userok(void *app_data, char *username) -{ - struct gss_data *data = app_data; - krb5_error_code ret; - krb5_principal client; - struct gss_krb5_data *kdata; - - kdata = calloc(1, sizeof(struct gss_krb5_data)); - if (kdata == NULL) - return 1; - data->mech_data = kdata; - - ret = krb5_init_context(&(kdata->context)); - if (ret) { - free(kdata); - return 1; - } - - ret = krb5_parse_name(kdata->context, data->client_name, &client); - if(ret) { - krb5_free_context(kdata->context); - free(kdata); - return 1; - } - ret = krb5_kuserok(kdata->context, client, username); - if (!ret) { - krb5_free_principal(kdata->context, client); - krb5_free_context(kdata->context); - free(kdata); - return 1; - } - - ret = 0; - krb5_free_principal(kdata->context, client); - return ret; -} - -int -gss_session(void *app_data, char *username) -{ - struct gss_data *data = app_data; - krb5_error_code ret; - OM_uint32 minor_status; - struct gss_krb5_data *kdata; - - ret = 0; - - kdata = (struct gss_krb5_data *)(data->mech_data); - - /* more of krb-depend stuff :-( */ - /* gss_add_cred() ? */ - if (data->delegated_cred_handle != GSS_C_NO_CREDENTIAL) { - krb5_ccache ccache = NULL; - const char* ticketfile; - struct passwd *kpw; - - ret = krb5_cc_new_unique(kdata->context, NULL, NULL, &ccache); - if (ret) - goto fail; - - ticketfile = krb5_cc_get_name(kdata->context, ccache); - - ret = gss_krb5_copy_ccache(&minor_status, - data->delegated_cred_handle, - ccache); - if (ret) { - ret = 0; - goto fail; - } - - do_destroy_tickets = 1; - - kpw = getpwnam(username); - - if (kpw == NULL) { - unlink(ticketfile); - ret = 1; - goto fail; - } - - chown (ticketfile, kpw->pw_uid, kpw->pw_gid); - - if (asprintf(&k5ccname, "FILE:%s", ticketfile) != -1) { - esetenv ("KRB5CCNAME", k5ccname, 1); - } - afslog(NULL, 1); - fail: - if (ccache) - krb5_cc_close(kdata->context, ccache); - } - - gss_release_cred(&minor_status, &data->delegated_cred_handle); - krb5_free_context(kdata->context); - free(kdata); - return ret; -} diff --git a/appl/ftp/ftpd/klist.c b/appl/ftp/ftpd/klist.c deleted file mode 100644 index b450a3db7..000000000 --- a/appl/ftp/ftpd/klist.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 1995 - 2005 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "ftpd_locl.h" - -#ifdef KRB5 - -static int -print_cred(krb5_context context, krb5_creds *cred) -{ - char t1[128], t2[128], *str; - krb5_error_code ret; - krb5_timestamp sec; - - krb5_timeofday (context, &sec); - - if(cred->times.starttime) - krb5_format_time(context, cred->times.starttime, t1, sizeof(t1), 1); - else - krb5_format_time(context, cred->times.authtime, t1, sizeof(t1), 1); - - if(cred->times.endtime > sec) - krb5_format_time(context, cred->times.endtime, t2, sizeof(t2), 1); - else - strlcpy(t2, ">>>Expired<<<", sizeof(t2)); - - ret = krb5_unparse_name (context, cred->server, &str); - if (ret) { - lreply(500, "krb5_unparse_name: %d", ret); - return 1; - } - - lreply(200, "%-20s %-20s %s", t1, t2, str); - free(str); - return 0; -} - -static int -print_tickets (krb5_context context, - krb5_ccache ccache, - krb5_principal principal) -{ - krb5_error_code ret; - krb5_cc_cursor cursor; - krb5_creds cred; - char *str; - - ret = krb5_unparse_name (context, principal, &str); - if (ret) { - lreply(500, "krb5_unparse_name: %d", ret); - return 500; - } - - lreply(200, "%17s: %s:%s", - "Credentials cache", - krb5_cc_get_type(context, ccache), - krb5_cc_get_name(context, ccache)); - lreply(200, "%17s: %s", "Principal", str); - free (str); - - ret = krb5_cc_start_seq_get (context, ccache, &cursor); - if (ret) { - lreply(500, "krb5_cc_start_seq_get: %d", ret); - return 500; - } - - lreply(200, " Issued Expires Principal"); - - while ((ret = krb5_cc_next_cred (context, - ccache, - &cursor, - &cred)) == 0) { - if (print_cred(context, &cred)) - return 500; - krb5_free_cred_contents (context, &cred); - } - if (ret != KRB5_CC_END) { - lreply(500, "krb5_cc_get_next: %d", ret); - return 500; - } - ret = krb5_cc_end_seq_get (context, ccache, &cursor); - if (ret) { - lreply(500, "krb5_cc_end_seq_get: %d", ret); - return 500; - } - - return 200; -} - -static int -klist5(void) -{ - krb5_error_code ret; - krb5_context context; - krb5_ccache ccache; - krb5_principal principal; - int exit_status = 200; - - ret = krb5_init_context (&context); - if (ret) { - lreply(500, "krb5_init_context failed: %d", ret); - return 500; - } - - if (k5ccname) - ret = krb5_cc_resolve(context, k5ccname, &ccache); - else - ret = krb5_cc_default (context, &ccache); - if (ret) { - lreply(500, "krb5_cc_default: %d", ret); - return 500; - } - - ret = krb5_cc_get_principal (context, ccache, &principal); - if (ret) { - if(ret == ENOENT) - lreply(500, "No ticket file: %s", - krb5_cc_get_name(context, ccache)); - else - lreply(500, "krb5_cc_get_principal: %d", ret); - - return 500; - } - exit_status = print_tickets (context, ccache, principal); - - ret = krb5_cc_close (context, ccache); - if (ret) { - lreply(500, "krb5_cc_close: %d", ret); - exit_status = 500; - } - - krb5_free_principal (context, principal); - krb5_free_context (context); - return exit_status; -} -#endif - -void -klist(void) -{ -#if KRB5 - int res = klist5(); - reply(res, " "); -#else - reply(500, "Command not implemented."); -#endif -} - diff --git a/appl/ftp/ftpd/logwtmp.c b/appl/ftp/ftpd/logwtmp.c deleted file mode 100644 index 400e46d68..000000000 --- a/appl/ftp/ftpd/logwtmp.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (c) 1995 - 2000 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -#include -RCSID("$Id$"); -#endif - -#include -#include -#ifdef TIME_WITH_SYS_TIME -#include -#include -#elif defined(HAVE_SYS_TIME_H) -#include -#else -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_FCNTL_H -#include -#endif -#ifdef HAVE_UTMP_H -#include -#endif -#ifdef HAVE_UTMPX_H -#include -#endif -#ifdef HAVE_ASL_H -#include -#endif -#include -#include "extern.h" - -#ifndef WTMP_FILE -#ifdef _PATH_WTMP -#define WTMP_FILE _PATH_WTMP -#else -#define WTMP_FILE "/var/adm/wtmp" -#endif -#endif - -#ifdef HAVE_ASL_H - -#ifndef ASL_KEY_FACILITY -#define ASL_KEY_FACILITY "Facility" -#endif - -static void -ftpd_logwtmp_asl(char *line, char *name, char *host) -{ - static aslmsg m = NULL; - static int init = 0; - - if (!init) { - init = 1; - m = asl_new(ASL_TYPE_MSG); - if (m == NULL) - return; - asl_set(m, ASL_KEY_FACILITY, "org.h5l.ftpd"); - } - if (m) - asl_log(NULL, m, ASL_LEVEL_NOTICE, - "host %s/%s user %s%sconnected pid %d", - host, line, name, name[0] ? " " : "dis", (int)getpid()); -} - -#endif - -#ifndef HAVE_ASL_H - -static void -ftpd_logwtmp_wtmp(char *line, char *name, char *host) -{ - static int init = 0; - static int fd; -#ifdef WTMPX_FILE - static int fdx; -#endif - struct utmp ut; -#ifdef WTMPX_FILE - struct utmpx utx; -#endif - - memset(&ut, 0, sizeof(struct utmp)); -#ifdef HAVE_STRUCT_UTMP_UT_TYPE - if(name[0]) - ut.ut_type = USER_PROCESS; - else - ut.ut_type = DEAD_PROCESS; -#endif - strncpy(ut.ut_line, line, sizeof(ut.ut_line)); - strncpy(ut.ut_name, name, sizeof(ut.ut_name)); -#ifdef HAVE_STRUCT_UTMP_UT_PID - ut.ut_pid = getpid(); -#endif -#ifdef HAVE_STRUCT_UTMP_UT_HOST - strncpy(ut.ut_host, host, sizeof(ut.ut_host)); -#endif - ut.ut_time = time(NULL); - -#ifdef WTMPX_FILE - strncpy(utx.ut_line, line, sizeof(utx.ut_line)); - strncpy(utx.ut_user, name, sizeof(utx.ut_user)); - strncpy(utx.ut_host, host, sizeof(utx.ut_host)); -#ifdef HAVE_STRUCT_UTMPX_UT_SYSLEN - utx.ut_syslen = strlen(host) + 1; - if (utx.ut_syslen > sizeof(utx.ut_host)) - utx.ut_syslen = sizeof(utx.ut_host); -#endif - { - struct timeval tv; - - gettimeofday (&tv, 0); - utx.ut_tv.tv_sec = tv.tv_sec; - utx.ut_tv.tv_usec = tv.tv_usec; - } - - if(name[0]) - utx.ut_type = USER_PROCESS; - else - utx.ut_type = DEAD_PROCESS; -#endif - - if(!init){ - fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0); -#ifdef WTMPX_FILE - fdx = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0); -#endif - init = 1; - } - if(fd >= 0) { - write(fd, &ut, sizeof(struct utmp)); /* XXX */ -#ifdef WTMPX_FILE - write(fdx, &utx, sizeof(struct utmpx)); -#endif - } -} - -#endif /* !HAVE_ASL_H */ - -void -ftpd_logwtmp(char *line, char *name, char *host) -{ -#ifdef HAVE_ASL_H - ftpd_logwtmp_asl(line, name, host); -#else - ftpd_logwtmp_wtmp(line, name, host); -#endif -} diff --git a/appl/ftp/ftpd/ls.c b/appl/ftp/ftpd/ls.c deleted file mode 100644 index 1abb37f89..000000000 --- a/appl/ftp/ftpd/ls.c +++ /dev/null @@ -1,891 +0,0 @@ -/* - * Copyright (c) 1999 - 2002 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of KTH nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -#ifndef TEST -#include "ftpd_locl.h" - -RCSID("$Id$"); - -#else -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define sec_fprintf2 fprintf -#define sec_fflush fflush -static void list_files(FILE *out, const char **files, int n_files, int flags); -static int parse_flags(const char *options); - -int -main(int argc, char **argv) -{ - int i = 1; - int flags; - if(argc > 1 && argv[1][0] == '-') { - flags = parse_flags(argv[1]); - i = 2; - } else - flags = parse_flags(NULL); - - list_files(stdout, (const char **)argv + i, argc - i, flags); - return 0; -} -#endif - -struct fileinfo { - struct stat st; - int inode; - int bsize; - char mode[11]; - int n_link; - char *user; - char *group; - char *size; - char *major; - char *minor; - char *date; - char *filename; - char *link; -}; - -static void -free_fileinfo(struct fileinfo *f) -{ - free(f->user); - free(f->group); - free(f->size); - free(f->major); - free(f->minor); - free(f->date); - free(f->filename); - free(f->link); -} - -#define LS_DIRS (1 << 0) -#define LS_IGNORE_DOT (1 << 1) -#define LS_SORT_MODE (3 << 2) -#define SORT_MODE(f) ((f) & LS_SORT_MODE) -#define LS_SORT_NAME (1 << 2) -#define LS_SORT_MTIME (2 << 2) -#define LS_SORT_SIZE (3 << 2) -#define LS_SORT_REVERSE (1 << 4) - -#define LS_SIZE (1 << 5) -#define LS_INODE (1 << 6) -#define LS_TYPE (1 << 7) -#define LS_DISP_MODE (3 << 8) -#define DISP_MODE(f) ((f) & LS_DISP_MODE) -#define LS_DISP_LONG (1 << 8) -#define LS_DISP_COLUMN (2 << 8) -#define LS_DISP_CROSS (3 << 8) -#define LS_SHOW_ALL (1 << 10) -#define LS_RECURSIVE (1 << 11) -#define LS_EXTRA_BLANK (1 << 12) -#define LS_SHOW_DIRNAME (1 << 13) -#define LS_DIR_FLAG (1 << 14) /* these files come via list_dir */ - -#ifndef S_ISTXT -#define S_ISTXT S_ISVTX -#endif - -#if !defined(_S_IFMT) && defined(S_IFMT) -#define _S_IFMT S_IFMT -#endif - -#ifndef S_ISSOCK -#define S_ISSOCK(mode) (((mode) & _S_IFMT) == S_IFSOCK) -#endif - -#ifndef S_ISLNK -#define S_ISLNK(mode) (((mode) & _S_IFMT) == S_IFLNK) -#endif - -static size_t -block_convert(size_t blocks) -{ -#ifdef S_BLKSIZE - return blocks * S_BLKSIZE / 1024; -#else - return blocks * 512 / 1024; -#endif -} - -static int -make_fileinfo(FILE *out, const char *filename, struct fileinfo *file, int flags) -{ - char buf[128]; - int file_type = 0; - struct stat *st = &file->st; - - file->inode = st->st_ino; - file->bsize = block_convert(st->st_blocks); - - if(S_ISDIR(st->st_mode)) { - file->mode[0] = 'd'; - file_type = '/'; - } - else if(S_ISCHR(st->st_mode)) - file->mode[0] = 'c'; - else if(S_ISBLK(st->st_mode)) - file->mode[0] = 'b'; - else if(S_ISREG(st->st_mode)) { - file->mode[0] = '-'; - if(st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) - file_type = '*'; - } - else if(S_ISFIFO(st->st_mode)) { - file->mode[0] = 'p'; - file_type = '|'; - } - else if(S_ISLNK(st->st_mode)) { - file->mode[0] = 'l'; - file_type = '@'; - } - else if(S_ISSOCK(st->st_mode)) { - file->mode[0] = 's'; - file_type = '='; - } -#ifdef S_ISWHT - else if(S_ISWHT(st->st_mode)) { - file->mode[0] = 'w'; - file_type = '%'; - } -#endif - else - file->mode[0] = '?'; - { - char *x[] = { "---", "--x", "-w-", "-wx", - "r--", "r-x", "rw-", "rwx" }; - strcpy(file->mode + 1, x[(st->st_mode & S_IRWXU) >> 6]); - strcpy(file->mode + 4, x[(st->st_mode & S_IRWXG) >> 3]); - strcpy(file->mode + 7, x[(st->st_mode & S_IRWXO) >> 0]); - if((st->st_mode & S_ISUID)) { - if((st->st_mode & S_IXUSR)) - file->mode[3] = 's'; - else - file->mode[3] = 'S'; - } - if((st->st_mode & S_ISGID)) { - if((st->st_mode & S_IXGRP)) - file->mode[6] = 's'; - else - file->mode[6] = 'S'; - } - if((st->st_mode & S_ISTXT)) { - if((st->st_mode & S_IXOTH)) - file->mode[9] = 't'; - else - file->mode[9] = 'T'; - } - } - file->n_link = st->st_nlink; - { - struct passwd *pwd; - pwd = getpwuid(st->st_uid); - if(pwd == NULL) { - if (asprintf(&file->user, "%u", (unsigned)st->st_uid) == -1) - file->user = NULL; - } else - file->user = strdup(pwd->pw_name); - if (file->user == NULL) { - syslog(LOG_ERR, "out of memory"); - return -1; - } - } - { - struct group *grp; - grp = getgrgid(st->st_gid); - if(grp == NULL) { - if (asprintf(&file->group, "%u", (unsigned)st->st_gid) == -1) - file->group = NULL; - } else - file->group = strdup(grp->gr_name); - if (file->group == NULL) { - syslog(LOG_ERR, "out of memory"); - return -1; - } - } - - if(S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) { -#if defined(major) && defined(minor) - if (asprintf(&file->major, "%u", (unsigned)major(st->st_rdev)) == -1) - file->major = NULL; - if (asprintf(&file->minor, "%u", (unsigned)minor(st->st_rdev)) == -1) - file->minor = NULL; -#else - /* Don't want to use the DDI/DKI crap. */ - if (asprintf(&file->major, "%u", (unsigned)st->st_rdev) == -1) - file->major = NULL; - if (asprintf(&file->minor, "%u", 0) == -1) - file->minor = NULL; -#endif - if (file->major == NULL || file->minor == NULL) { - syslog(LOG_ERR, "out of memory"); - return -1; - } - } else { - if (asprintf(&file->size, "%lu", (unsigned long)st->st_size) == -1) - file->size = NULL; - } - - { - time_t t = time(NULL); - time_t mtime = st->st_mtime; - struct tm *tm = localtime(&mtime); - if((t - mtime > 6*30*24*60*60) || - (mtime - t > 6*30*24*60*60)) - strftime(buf, sizeof(buf), "%b %e %Y", tm); - else - strftime(buf, sizeof(buf), "%b %e %H:%M", tm); - file->date = strdup(buf); - if (file->date == NULL) { - syslog(LOG_ERR, "out of memory"); - return -1; - } - } - { - const char *p = strrchr(filename, '/'); - if(p) - p++; - else - p = filename; - if((flags & LS_TYPE) && file_type != 0) { - if (asprintf(&file->filename, "%s%c", p, file_type) == -1) - file->filename = NULL; - } else - file->filename = strdup(p); - if (file->filename == NULL) { - syslog(LOG_ERR, "out of memory"); - return -1; - } - } - if(S_ISLNK(st->st_mode)) { - int n; - n = readlink((char *)filename, buf, sizeof(buf) - 1); - if(n >= 0) { - buf[n] = '\0'; - file->link = strdup(buf); - if (file->link == NULL) { - syslog(LOG_ERR, "out of memory"); - return -1; - } - } else - sec_fprintf2(out, "readlink(%s): %s", filename, strerror(errno)); - } - return 0; -} - -static void -print_file(FILE *out, - int flags, - struct fileinfo *f, - int max_inode, - int max_bsize, - int max_n_link, - int max_user, - int max_group, - int max_size, - int max_major, - int max_minor, - int max_date) -{ - if(f->filename == NULL) - return; - - if(flags & LS_INODE) { - sec_fprintf2(out, "%*d", max_inode, f->inode); - sec_fprintf2(out, " "); - } - if(flags & LS_SIZE) { - sec_fprintf2(out, "%*d", max_bsize, f->bsize); - sec_fprintf2(out, " "); - } - sec_fprintf2(out, "%s", f->mode); - sec_fprintf2(out, " "); - sec_fprintf2(out, "%*d", max_n_link, f->n_link); - sec_fprintf2(out, " "); - sec_fprintf2(out, "%-*s", max_user, f->user); - sec_fprintf2(out, " "); - sec_fprintf2(out, "%-*s", max_group, f->group); - sec_fprintf2(out, " "); - if(f->major != NULL && f->minor != NULL) - sec_fprintf2(out, "%*s, %*s", max_major, f->major, max_minor, f->minor); - else - sec_fprintf2(out, "%*s", max_size, f->size); - sec_fprintf2(out, " "); - sec_fprintf2(out, "%*s", max_date, f->date); - sec_fprintf2(out, " "); - sec_fprintf2(out, "%s", f->filename); - if(f->link) - sec_fprintf2(out, " -> %s", f->link); - sec_fprintf2(out, "\r\n"); -} - -static int -compare_filename(struct fileinfo *a, struct fileinfo *b) -{ - if(a->filename == NULL) - return 1; - if(b->filename == NULL) - return -1; - return strcmp(a->filename, b->filename); -} - -static int -compare_mtime(struct fileinfo *a, struct fileinfo *b) -{ - if(a->filename == NULL) - return 1; - if(b->filename == NULL) - return -1; - return b->st.st_mtime - a->st.st_mtime; -} - -static int -compare_size(struct fileinfo *a, struct fileinfo *b) -{ - if(a->filename == NULL) - return 1; - if(b->filename == NULL) - return -1; - return b->st.st_size - a->st.st_size; -} - -static int list_dir(FILE*, const char*, int); - -static int -find_log10(int num) -{ - int i = 1; - while(num > 10) { - i++; - num /= 10; - } - return i; -} - -/* - * Operate as lstat but fake up entries for AFS mount points so we don't - * have to fetch them. - */ - -#ifdef KRB5 -static int do_the_afs_dance = 1; -#endif - -static int -lstat_file (const char *file, struct stat *sb) -{ -#ifdef KRB5 - if (do_the_afs_dance && - k_hasafs() - && strcmp(file, ".") - && strcmp(file, "..") - && strcmp(file, "/")) - { - struct ViceIoctl a_params; - char *dir, *last; - char *path_bkp; - static ino_t ino_counter = 0, ino_last = 0; - int ret; - const int maxsize = 2048; - - path_bkp = strdup (file); - if (path_bkp == NULL) - return -1; - - a_params.out = malloc (maxsize); - if (a_params.out == NULL) { - free (path_bkp); - return -1; - } - - /* If path contains more than the filename alone - split it */ - - last = strrchr (path_bkp, '/'); - if (last != NULL) { - if(last[1] == '\0') - /* if path ended in /, replace with `.' */ - a_params.in = "."; - else - a_params.in = last + 1; - while(last > path_bkp && *--last == '/'); - if(*last != '/' || last != path_bkp) { - *++last = '\0'; - dir = path_bkp; - } else - /* we got to the start, so this must be the root dir */ - dir = "/"; - } else { - /* file is relative to cdir */ - dir = "."; - a_params.in = path_bkp; - } - - a_params.in_size = strlen (a_params.in) + 1; - a_params.out_size = maxsize; - - ret = k_pioctl (dir, VIOC_AFS_STAT_MT_PT, &a_params, 0); - free (a_params.out); - if (ret < 0) { - free (path_bkp); - - if (errno != EINVAL) - return ret; - else - /* if we get EINVAL this is probably not a mountpoint */ - return lstat (file, sb); - } - - /* - * wow this was a mountpoint, lets cook the struct stat - * use . as a prototype - */ - - ret = lstat (dir, sb); - free (path_bkp); - if (ret < 0) - return ret; - - if (ino_last == sb->st_ino) - ino_counter++; - else { - ino_last = sb->st_ino; - ino_counter = 0; - } - sb->st_ino += ino_counter; - sb->st_nlink = 3; - - return 0; - } -#endif /* KRB5 */ - return lstat (file, sb); -} - -#define IS_DOT_DOTDOT(X) ((X)[0] == '.' && ((X)[1] == '\0' || \ - ((X)[1] == '.' && (X)[2] == '\0'))) - -static int -list_files(FILE *out, const char **files, int n_files, int flags) -{ - struct fileinfo *fi; - int i; - int *dirs = NULL; - size_t total_blocks = 0; - int n_print = 0; - int ret = 0; - - if(n_files == 0) - return 0; - - if(n_files > 1) - flags |= LS_SHOW_DIRNAME; - - fi = calloc(n_files, sizeof(*fi)); - if (fi == NULL) { - syslog(LOG_ERR, "out of memory"); - return -1; - } - for(i = 0; i < n_files; i++) { - if(lstat_file(files[i], &fi[i].st) < 0) { - sec_fprintf2(out, "%s: %s\r\n", files[i], strerror(errno)); - fi[i].filename = NULL; - } else { - int include_in_list = 1; - total_blocks += block_convert(fi[i].st.st_blocks); - if(S_ISDIR(fi[i].st.st_mode)) { - if(dirs == NULL) - dirs = calloc(n_files, sizeof(*dirs)); - if(dirs == NULL) { - syslog(LOG_ERR, "%s: %m", files[i]); - ret = -1; - goto out; - } - dirs[i] = 1; - if((flags & LS_DIRS) == 0) - include_in_list = 0; - } - if(include_in_list) { - ret = make_fileinfo(out, files[i], &fi[i], flags); - if (ret) - goto out; - n_print++; - } - } - } - switch(SORT_MODE(flags)) { - case LS_SORT_NAME: - qsort(fi, n_files, sizeof(*fi), - (int (*)(const void*, const void*))compare_filename); - break; - case LS_SORT_MTIME: - qsort(fi, n_files, sizeof(*fi), - (int (*)(const void*, const void*))compare_mtime); - break; - case LS_SORT_SIZE: - qsort(fi, n_files, sizeof(*fi), - (int (*)(const void*, const void*))compare_size); - break; - } - if(DISP_MODE(flags) == LS_DISP_LONG) { - int max_inode = 0; - int max_bsize = 0; - int max_n_link = 0; - int max_user = 0; - int max_group = 0; - int max_size = 0; - int max_major = 0; - int max_minor = 0; - int max_date = 0; - for(i = 0; i < n_files; i++) { - if(fi[i].filename == NULL) - continue; - if(fi[i].inode > max_inode) - max_inode = fi[i].inode; - if(fi[i].bsize > max_bsize) - max_bsize = fi[i].bsize; - if(fi[i].n_link > max_n_link) - max_n_link = fi[i].n_link; - if(strlen(fi[i].user) > max_user) - max_user = strlen(fi[i].user); - if(strlen(fi[i].group) > max_group) - max_group = strlen(fi[i].group); - if(fi[i].major != NULL && strlen(fi[i].major) > max_major) - max_major = strlen(fi[i].major); - if(fi[i].minor != NULL && strlen(fi[i].minor) > max_minor) - max_minor = strlen(fi[i].minor); - if(fi[i].size != NULL && strlen(fi[i].size) > max_size) - max_size = strlen(fi[i].size); - if(strlen(fi[i].date) > max_date) - max_date = strlen(fi[i].date); - } - if(max_size < max_major + max_minor + 2) - max_size = max_major + max_minor + 2; - else if(max_size - max_minor - 2 > max_major) - max_major = max_size - max_minor - 2; - max_inode = find_log10(max_inode); - max_bsize = find_log10(max_bsize); - max_n_link = find_log10(max_n_link); - - if(n_print > 0) - sec_fprintf2(out, "total %lu\r\n", (unsigned long)total_blocks); - if(flags & LS_SORT_REVERSE) - for(i = n_files - 1; i >= 0; i--) - print_file(out, - flags, - &fi[i], - max_inode, - max_bsize, - max_n_link, - max_user, - max_group, - max_size, - max_major, - max_minor, - max_date); - else - for(i = 0; i < n_files; i++) - print_file(out, - flags, - &fi[i], - max_inode, - max_bsize, - max_n_link, - max_user, - max_group, - max_size, - max_major, - max_minor, - max_date); - } else if(DISP_MODE(flags) == LS_DISP_COLUMN || - DISP_MODE(flags) == LS_DISP_CROSS) { - int max_len = 0; - int size_len = 0; - int num_files = n_files; - int columns; - int j; - for(i = 0; i < n_files; i++) { - if(fi[i].filename == NULL) { - num_files--; - continue; - } - if(strlen(fi[i].filename) > max_len) - max_len = strlen(fi[i].filename); - if(find_log10(fi[i].bsize) > size_len) - size_len = find_log10(fi[i].bsize); - } - if(num_files == 0) - goto next; - if(flags & LS_SIZE) { - columns = 80 / (size_len + 1 + max_len + 1); - max_len = 80 / columns - size_len - 1; - } else { - columns = 80 / (max_len + 1); /* get space between columns */ - max_len = 80 / columns; - } - if(flags & LS_SIZE) - sec_fprintf2(out, "total %lu\r\n", - (unsigned long)total_blocks); - if(DISP_MODE(flags) == LS_DISP_CROSS) { - for(i = 0, j = 0; i < n_files; i++) { - if(fi[i].filename == NULL) - continue; - if(flags & LS_SIZE) - sec_fprintf2(out, "%*u %-*s", size_len, fi[i].bsize, - max_len, fi[i].filename); - else - sec_fprintf2(out, "%-*s", max_len, fi[i].filename); - j++; - if(j == columns) { - sec_fprintf2(out, "\r\n"); - j = 0; - } - } - if(j > 0) - sec_fprintf2(out, "\r\n"); - } else { - int skip = (num_files + columns - 1) / columns; - - for(i = 0; i < skip; i++) { - for(j = i; j < n_files;) { - while(j < n_files && fi[j].filename == NULL) - j++; - if(flags & LS_SIZE) - sec_fprintf2(out, "%*u %-*s", size_len, fi[j].bsize, - max_len, fi[j].filename); - else - sec_fprintf2(out, "%-*s", max_len, fi[j].filename); - j += skip; - } - sec_fprintf2(out, "\r\n"); - } - } - } else { - for(i = 0; i < n_files; i++) { - if(fi[i].filename == NULL) - continue; - sec_fprintf2(out, "%s\r\n", fi[i].filename); - } - } - next: - if(((flags & LS_DIRS) == 0 || (flags & LS_RECURSIVE)) && dirs != NULL) { - for(i = 0; i < n_files; i++) { - if(dirs[i]) { - const char *p = strrchr(files[i], '/'); - if(p == NULL) - p = files[i]; - else - p++; - if(!(flags & LS_DIR_FLAG) || !IS_DOT_DOTDOT(p)) { - if((flags & LS_SHOW_DIRNAME)) { - if ((flags & LS_EXTRA_BLANK)) - sec_fprintf2(out, "\r\n"); - sec_fprintf2(out, "%s:\r\n", files[i]); - } - list_dir(out, files[i], flags | LS_DIRS | LS_EXTRA_BLANK); - } - } - } - } - out: - for(i = 0; i < n_files; i++) - free_fileinfo(&fi[i]); - free(fi); - if(dirs != NULL) - free(dirs); - return ret; -} - -static void -free_files (char **files, int n) -{ - int i; - - for (i = 0; i < n; ++i) - free (files[i]); - free (files); -} - -static int -hide_file(const char *filename, int flags) -{ - if(filename[0] != '.') - return 0; - if((flags & LS_IGNORE_DOT)) - return 1; - if(filename[1] == '\0' || (filename[1] == '.' && filename[2] == '\0')) { - if((flags & LS_SHOW_ALL)) - return 0; - else - return 1; - } - return 0; -} - -static int -list_dir(FILE *out, const char *directory, int flags) -{ - DIR *d = opendir(directory); - struct dirent *ent; - char **files = NULL; - int n_files = 0; - int ret; - - if(d == NULL) { - syslog(LOG_ERR, "%s: %m", directory); - return -1; - } - while((ent = readdir(d)) != NULL) { - void *tmp; - - if(hide_file(ent->d_name, flags)) - continue; - tmp = realloc(files, (n_files + 1) * sizeof(*files)); - if (tmp == NULL) { - syslog(LOG_ERR, "%s: out of memory", directory); - free_files (files, n_files); - closedir (d); - return -1; - } - files = tmp; - ret = asprintf(&files[n_files], "%s/%s", directory, ent->d_name); - if (ret == -1) { - syslog(LOG_ERR, "%s: out of memory", directory); - free_files (files, n_files); - closedir (d); - return -1; - } - ++n_files; - } - closedir(d); - return list_files(out, (const char**)files, n_files, flags | LS_DIR_FLAG); -} - -static int -parse_flags(const char *options) -{ -#ifdef TEST - int flags = LS_SORT_NAME | LS_IGNORE_DOT | LS_DISP_COLUMN; -#else - int flags = LS_SORT_NAME | LS_IGNORE_DOT | LS_DISP_LONG; -#endif - - const char *p; - if(options == NULL || *options != '-') - return flags; - for(p = options + 1; *p; p++) { - switch(*p) { - case '1': - flags = (flags & ~LS_DISP_MODE); - break; - case 'a': - flags |= LS_SHOW_ALL; - /*FALLTHROUGH*/ - case 'A': - flags &= ~LS_IGNORE_DOT; - break; - case 'C': - flags = (flags & ~LS_DISP_MODE) | LS_DISP_COLUMN; - break; - case 'd': - flags |= LS_DIRS; - break; - case 'f': - flags = (flags & ~LS_SORT_MODE); - break; - case 'F': - flags |= LS_TYPE; - break; - case 'i': - flags |= LS_INODE; - break; - case 'l': - flags = (flags & ~LS_DISP_MODE) | LS_DISP_LONG; - break; - case 'r': - flags |= LS_SORT_REVERSE; - break; - case 'R': - flags |= LS_RECURSIVE; - break; - case 's': - flags |= LS_SIZE; - break; - case 'S': - flags = (flags & ~LS_SORT_MODE) | LS_SORT_SIZE; - break; - case 't': - flags = (flags & ~LS_SORT_MODE) | LS_SORT_MTIME; - break; - case 'x': - flags = (flags & ~LS_DISP_MODE) | LS_DISP_CROSS; - break; - /* these are a bunch of unimplemented flags from BSD ls */ - case 'k': /* display sizes in kB */ - case 'c': /* last change time */ - case 'L': /* list symlink target */ - case 'm': /* stream output */ - case 'o': /* BSD file flags */ - case 'p': /* display / after directories */ - case 'q': /* print non-graphic characters */ - case 'u': /* use last access time */ - case 'T': /* display complete time */ - case 'W': /* include whiteouts */ - break; - } - } - return flags; -} - -int -builtin_ls(FILE *out, const char *file) -{ - int flags; - int ret; - - if(*file == '-') { - flags = parse_flags(file); - file = "."; - } else - flags = parse_flags(""); - - ret = list_files(out, &file, 1, flags); - sec_fflush(out); - return ret; -} diff --git a/appl/ftp/ftpd/pathnames.h b/appl/ftp/ftpd/pathnames.h deleted file mode 100644 index 884902905..000000000 --- a/appl/ftp/ftpd/pathnames.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)pathnames.h 8.1 (Berkeley) 6/4/93 - */ - -#ifdef HAVE_PATHS_H -#include -#endif - -#ifndef _PATH_DEVNULL -#define _PATH_DEVNULL "/dev/null" -#endif - -#ifndef _PATH_NOLOGIN -#define _PATH_NOLOGIN "/etc/nologin" -#endif - -#ifndef _PATH_BSHELL -#define _PATH_BSHELL "/bin/sh" -#endif - -#ifndef _PATH_FTPUSERS -#define _PATH_FTPUSERS SYSCONFDIR "/ftpusers" -#endif - -#define _PATH_FTPCHROOT SYSCONFDIR "/ftpchroot" -#define _PATH_FTPWELCOME SYSCONFDIR "/ftpwelcome" -#define _PATH_FTPLOGINMESG SYSCONFDIR "/motd" - -#ifndef _PATH_ISSUE -#define _PATH_ISSUE SYSCONFDIR "/issue" -#endif -#define _PATH_ISSUE_NET SYSCONFDIR "/issue.net" diff --git a/appl/ftp/ftpd/popen.c b/appl/ftp/ftpd/popen.c deleted file mode 100644 index 916e32f75..000000000 --- a/appl/ftp/ftpd/popen.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright (c) 1988, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software written by Ken Arnold and - * published in UNIX Review, Vol. 6, No. 8. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#ifdef HAVE_CONFIG_H -#include -RCSID("$Id$"); -#endif - -#include -#ifdef TIME_WITH_SYS_TIME -#include -#include -#elif defined(HAVE_SYS_TIME_H) -#include -#else -#include -#endif -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include "extern.h" - - -/* - * Special version of popen which avoids call to shell. This ensures - * no one may create a pipe to a hidden program as a side effect of a - * list or dir command. - */ -static int *pids; -static int fds; - -/* return path prepended with ~ftp if that file exists, otherwise - * return path unchanged - */ - -const char * -ftp_rooted(const char *path) -{ - static char home[MaxPathLen] = ""; - static char newpath[MaxPathLen]; - struct passwd *pwd; - - if(!home[0]) - if((pwd = k_getpwnam("ftp"))) - strlcpy(home, pwd->pw_dir, sizeof(home)); - snprintf(newpath, sizeof(newpath), "%s/%s", home, path); - if(access(newpath, X_OK)) - strlcpy(newpath, path, sizeof(newpath)); - return newpath; -} - - -#define MAXARGS 100 -#define MAXGLOBS 1000 - -FILE * -ftpd_popen(char *program, char *type, int do_stderr, int no_glob) -{ - char *cp; - FILE *iop; - int argc, gargc, pdes[2], pid; - char **pop, *argv[MAXARGS], *gargv[MAXGLOBS]; - char *foo; - - if (strcmp(type, "r") && strcmp(type, "w")) - return (NULL); - - if (!pids) { - - /* This function is ugly and should be rewritten, in - * modern unices there is no such thing as a maximum - * filedescriptor. - */ - - fds = getdtablesize(); - pids = (int*)calloc(fds, sizeof(int)); - if(!pids) - return NULL; - } - if (pipe(pdes) < 0) - return (NULL); - - /* break up string into pieces */ - foo = NULL; - for (argc = 0, cp = program; argc < MAXARGS - 1; cp = NULL) { - if (!(argv[argc++] = strtok_r(cp, " \t\n", &foo))) - break; - } - argv[MAXARGS - 1] = NULL; - - gargv[0] = (char*)ftp_rooted(argv[0]); - /* glob each piece */ - for (gargc = argc = 1; argv[argc] && gargc < MAXGLOBS - 1; argc++) { - glob_t gl; - int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE - | -#ifdef GLOB_MAXPATH - GLOB_MAXPATH -#else - GLOB_LIMIT -#endif - ; - - memset(&gl, 0, sizeof(gl)); - if (no_glob || - glob(argv[argc], flags, NULL, &gl) || - gl.gl_pathc == 0) - gargv[gargc++] = strdup(argv[argc]); - else - for (pop = gl.gl_pathv; - *pop && gargc < MAXGLOBS - 1; - pop++) - gargv[gargc++] = strdup(*pop); - globfree(&gl); - } - gargv[gargc] = NULL; - - iop = NULL; - switch(pid = fork()) { - case -1: /* error */ - close(pdes[0]); - close(pdes[1]); - goto pfree; - /* NOTREACHED */ - case 0: /* child */ - if (*type == 'r') { - if (pdes[1] != STDOUT_FILENO) { - dup2(pdes[1], STDOUT_FILENO); - close(pdes[1]); - } - if(do_stderr) - dup2(STDOUT_FILENO, STDERR_FILENO); - close(pdes[0]); - } else { - if (pdes[0] != STDIN_FILENO) { - dup2(pdes[0], STDIN_FILENO); - close(pdes[0]); - } - close(pdes[1]); - } - execv(gargv[0], gargv); - gargv[0] = argv[0]; - execv(gargv[0], gargv); - _exit(1); - } - /* parent; assume fdopen can't fail... */ - if (*type == 'r') { - iop = fdopen(pdes[0], type); - close(pdes[1]); - } else { - iop = fdopen(pdes[1], type); - close(pdes[0]); - } - pids[fileno(iop)] = pid; - -pfree: - for (argc = 1; gargv[argc] != NULL; argc++) - free(gargv[argc]); - - - return (iop); -} - -int -ftpd_pclose(FILE *iop) -{ - int fdes, status; - pid_t pid; - sigset_t sigset, osigset; - - /* - * pclose returns -1 if stream is not associated with a - * `popened' command, or, if already `pclosed'. - */ - if (pids == 0 || pids[fdes = fileno(iop)] == 0) - return (-1); - fclose(iop); - sigemptyset(&sigset); - sigaddset(&sigset, SIGINT); - sigaddset(&sigset, SIGQUIT); - sigaddset(&sigset, SIGHUP); - sigprocmask(SIG_BLOCK, &sigset, &osigset); - while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR) - continue; - sigprocmask(SIG_SETMASK, &osigset, NULL); - pids[fdes] = 0; - if (pid < 0) - return (pid); - if (WIFEXITED(status)) - return (WEXITSTATUS(status)); - return (1); -} diff --git a/appl/gssmask/Makefile.am b/appl/gssmask/Makefile.am index 63b740fa4..55673a039 100644 --- a/appl/gssmask/Makefile.am +++ b/appl/gssmask/Makefile.am @@ -8,5 +8,6 @@ gssmask_SOURCES = gssmask.c common.c common.h protocol.h gssmaestro_SOURCES = gssmaestro.c common.c common.h protocol.h -LDADD = $(top_builddir)/lib/gssapi/libgssapi.la $(LIB_roken) +LDADD = $(top_builddir)/lib/gssapi/libgssapi.la $(LIB_roken) $(top_builddir)/lib/krb5/libkrb5.la +EXTRA_DIST = NTMakefile diff --git a/appl/gssmask/NTMakefile b/appl/gssmask/NTMakefile new file mode 100644 index 000000000..4ad1dc4f7 --- /dev/null +++ b/appl/gssmask/NTMakefile @@ -0,0 +1,35 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=appl\gssmask + +!include ../../windows/NTMakefile.w32 + diff --git a/appl/gssmask/common.c b/appl/gssmask/common.c index 8d7d8fa22..733db9013 100644 --- a/appl/gssmask/common.c +++ b/appl/gssmask/common.c @@ -55,7 +55,7 @@ add_list(char ****list, size_t *listlen, char **str, size_t len) size_t i; *list = erealloc(*list, sizeof(**list) * (*listlen + 1)); - (*list)[*listlen] = ecalloc(len, sizeof(**list)); + (*list)[*listlen] = ecalloc(len, sizeof(***list)); for (i = 0; i < len; i++) (*list)[*listlen][i] = str[i]; (*listlen)++; diff --git a/appl/gssmask/common.h b/appl/gssmask/common.h index cd9b0817f..96d10ff0a 100644 --- a/appl/gssmask/common.h +++ b/appl/gssmask/common.h @@ -37,13 +37,6 @@ #include #endif -/* - * pthread support is disable because the pthread - * test have no "application pthread libflags" variable, - * when this is fixed pthread support can be enabled again. - */ -#undef ENABLE_PTHREAD_SUPPORT - #include #ifdef HAVE_SYS_UTSNAME_H #include @@ -65,6 +58,13 @@ #include "protocol.h" +/* + * pthread support is disable because the pthread + * test have no "application pthread libflags" variable, + * when this is fixed pthread support can be enabled again. + */ +#undef ENABLE_PTHREAD_SUPPORT + krb5_error_code store_string(krb5_storage *, const char *); diff --git a/appl/gssmask/gssmaestro.c b/appl/gssmask/gssmaestro.c index b38c1b8a5..9ccf1de40 100644 --- a/appl/gssmask/gssmaestro.c +++ b/appl/gssmask/gssmaestro.c @@ -270,26 +270,27 @@ wait_log(struct client *c) int32_t port; struct sockaddr_storage sast; socklen_t salen = sizeof(sast); - int fd, fd2, ret; + krb5_socket_t sock, sock2; + int ret; memset(&sast, 0, sizeof(sast)); assert(sizeof(sast) >= c->salen); - fd = socket(c->sa->sa_family, SOCK_STREAM, 0); - if (fd < 0) + sock = socket(c->sa->sa_family, SOCK_STREAM, 0); + if (sock == rk_INVALID_SOCKET) err(1, "failed to build socket for %s's logging port", c->moniker); - ((struct sockaddr *)&sast)->sa_family = c->sa->sa_family; - ret = bind(fd, (struct sockaddr *)&sast, c->salen); + sast.ss_family = c->sa->sa_family; + ret = bind(sock, (struct sockaddr *)&sast, c->salen); if (ret < 0) err(1, "failed to bind %s's logging port", c->moniker); - if (listen(fd, SOMAXCONN) < 0) + if (listen(sock, SOMAXCONN) < 0) err(1, "failed to listen %s's logging port", c->moniker); salen = sizeof(sast); - ret = getsockname(fd, (struct sockaddr *)&sast, &salen); + ret = getsockname(sock, (struct sockaddr *)&sast, &salen); if (ret < 0) err(1, "failed to get address of local socket for %s", c->moniker); @@ -299,12 +300,12 @@ wait_log(struct client *c) put32(c, ntohs(port)); salen = sizeof(sast); - fd2 = accept(fd, (struct sockaddr *)&sast, &salen); - if (fd2 < 0) + sock2 = accept(sock, (struct sockaddr *)&sast, &salen); + if (sock2 == rk_INVALID_SOCKET) err(1, "failed to accept local socket for %s", c->moniker); - close(fd); + rk_closesocket(sock); - return fd2; + return sock2; } @@ -327,7 +328,7 @@ build_context(struct client *ipeer, struct client *apeer, krb5_data_zero(&itoken); while (!iDone || !aDone) { - + if (iDone) { warnx("iPeer already done, aPeer want extra rtt"); val = GSMERR_ERROR; @@ -405,7 +406,7 @@ build_context(struct client *ipeer, struct client *apeer, out: return val; } - + static void test_mic(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2) { @@ -474,10 +475,10 @@ test_wrap_ext(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2, int32_t val; header.data = "header"; - header.length = 6; + header.length = sizeof("header") - 1; msg.data = "0123456789abcdef"; /* padded for most enctypes */ - msg.length = 32; + msg.length = sizeof("0123456789abcdef") - 1; trailer.data = "trailer"; trailer.length = 7; @@ -540,17 +541,17 @@ test_token(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2, int w if (val) return val; val = test_wrap_ext(c2, hc2, c1, hc1, 1, 0); if (val) return val; - + val = test_wrap_ext(c1, hc1, c2, hc2, 1, 1); if (val) return val; val = test_wrap_ext(c2, hc2, c1, hc1, 1, 1); if (val) return val; - + val = test_wrap_ext(c1, hc1, c2, hc2, 0, 0); if (val) return val; val = test_wrap_ext(c2, hc2, c1, hc1, 0, 0); if (val) return val; - + val = test_wrap_ext(c1, hc1, c2, hc2, 0, 1); if (val) return val; val = test_wrap_ext(c2, hc2, c1, hc1, 0, 1); @@ -565,7 +566,7 @@ log_function(void *ptr) { struct client *c = ptr; int32_t cmd, line; - char *file, *string; + char *file = NULL, *string = NULL; while (1) { if (krb5_ret_int32(c->logsock, &cmd)) @@ -575,7 +576,6 @@ log_function(void *ptr) case eLogSetMoniker: if (krb5_ret_string(c->logsock, &file)) goto out; - free(file); break; case eLogInfo: case eLogFailure: @@ -590,8 +590,6 @@ log_function(void *ptr) fprintf(logfile, "%s:%lu: %s\n", file, (unsigned long)line, string); fflush(logfile); - free(file); - free(string); if (krb5_store_int32(c->logsock, 0)) goto out; break; @@ -600,6 +598,8 @@ log_function(void *ptr) } } out: + free(file); + free(string); return 0; } @@ -610,7 +610,8 @@ connect_client(const char *slave) char *name, *port; struct client *c = ecalloc(1, sizeof(*c)); struct addrinfo hints, *res0, *res; - int ret, fd; + int ret; + krb5_socket_t sock; name = estrdup(slave); port = strchr(name, ':'); @@ -628,13 +629,13 @@ connect_client(const char *slave) if (ret) errx(1, "error resolving %s", name); - for (res = res0, fd = -1; res; res = res->ai_next) { - fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (fd < 0) + for (res = res0, sock = rk_INVALID_SOCKET; res; res = res->ai_next) { + sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (sock == rk_INVALID_SOCKET) continue; - if (connect(fd, res->ai_addr, res->ai_addrlen) < 0) { - close(fd); - fd = -1; + if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) { + rk_closesocket(sock); + sock = rk_INVALID_SOCKET; continue; } c->sa = ecalloc(1, res->ai_addrlen); @@ -642,12 +643,12 @@ connect_client(const char *slave) c->salen = res->ai_addrlen; break; /* okay we got one */ } - if (fd < 0) + if (sock == rk_INVALID_SOCKET) err(1, "connect to host: %s", name); - freeaddrinfo(res); + freeaddrinfo(res0); - c->sock = krb5_storage_from_fd(fd); - close(fd); + c->sock = krb5_storage_from_socket(sock); + rk_closesocket(sock); if (c->sock == NULL) errx(1, "krb5_storage_from_fd"); @@ -667,14 +668,12 @@ connect_client(const char *slave) } if (logfile) { - int fd; - printf("starting log socket to client %s\n", c->moniker); - fd = wait_log(c); + sock = wait_log(c); - c->logsock = krb5_storage_from_fd(fd); - close(fd); + c->logsock = krb5_storage_from_socket(sock); + rk_closesocket(sock); if (c->logsock == NULL) errx(1, "failed to create log krb5_storage"); #ifdef ENABLE_PTHREAD_SUPPORT @@ -780,7 +779,7 @@ main(int argc, char **argv) if (password == NULL) errx(1, "password missing from %s", user); *password++ = 0; - + if (slaves.num_strings == 0) errx(1, "no principals"); @@ -834,7 +833,7 @@ main(int argc, char **argv) int32_t hCred, val, delegCred; int32_t clientC, serverC; struct client *c = clients[i]; - + if (c->target_name == NULL) continue; @@ -893,18 +892,18 @@ main(int argc, char **argv) int32_t hCred, val, delegCred = 0; int32_t clientC = 0, serverC = 0; struct client *client, *server; - + p = list[i]; - + client = get_client(p[0]); - + val = acquire_cred(client, user, password, 1, &hCred); if (val != GSMERR_OK) errx(1, "failed to acquire_cred: %d", (int)val); for (j = 1; j < num_clients + 1; j++) { server = get_client(p[j % num_clients]); - + if (server->target_name == NULL) break; @@ -921,11 +920,11 @@ main(int argc, char **argv) warnx("build_context failed: %d", (int)val); break; } - + val = test_token(client, clientC, server, serverC, wrap_ext); if (val) break; - + toast_resource(client, clientC); toast_resource(server, serverC); if (!delegCred) { diff --git a/appl/gssmask/gssmask.c b/appl/gssmask/gssmask.c index 8cee0695b..c27e885b5 100644 --- a/appl/gssmask/gssmask.c +++ b/appl/gssmask/gssmask.c @@ -73,10 +73,13 @@ logmessage(struct client *c, const char *file, unsigned int lineno, char *message; va_list ap; int32_t ackid; + int ret; va_start(ap, fmt); - vasprintf(&message, fmt, ap); + ret = vasprintf(&message, fmt, ap); va_end(ap); + if (ret == -1) + errx(1, "out of memory"); if (logfile) fprintf(logfile, "%s:%u: %d %s\n", file, lineno, level, message); @@ -229,7 +232,7 @@ acquire_cred(struct client *c, "krb5_get_init_creds failed: %d", ret); return convert_krb5_to_gsm(ret); } - + ret = krb5_cc_new_unique(context, "MEMORY", NULL, &id); if (ret) krb5_err (context, 1, ret, "krb5_cc_initialize"); @@ -309,7 +312,8 @@ HandleOP(InitContext) gss_ctx_id_t ctx; gss_cred_id_t creds; gss_name_t gss_target_name; - gss_buffer_desc input_token, output_token; + gss_buffer_desc input_token; + gss_buffer_desc output_token = {0, 0}; gss_OID oid = GSS_C_NO_OID; gss_buffer_t input_token_ptr = GSS_C_NO_BUFFER; @@ -358,7 +362,7 @@ HandleOP(InitContext) if (ctx) krb5_errx(context, 1, "initcreds, context not NULL, but first req"); } - + if ((flags & GSS_C_DELEG_FLAG) != 0) logmessage(c, __FILE__, __LINE__, 0, "init_sec_context delegating"); if ((flags & GSS_C_DCE_STYLE) != 0) @@ -427,7 +431,6 @@ HandleOP(AcceptContext) gss_ctx_id_t ctx; gss_cred_id_t deleg_cred = GSS_C_NO_CREDENTIAL; gss_buffer_desc input_token, output_token; - gss_buffer_t input_token_ptr = GSS_C_NO_BUFFER; ret32(c, hContext); ret32(c, flags); @@ -440,7 +443,6 @@ HandleOP(AcceptContext) if (in_token.length) { input_token.length = in_token.length; input_token.value = in_token.data; - input_token_ptr = &input_token; } else { input_token.length = 0; input_token.value = NULL; @@ -484,7 +486,7 @@ HandleOP(AcceptContext) gss_release_cred(&min_stat, &deleg_cred); deleg_hcred = 0; } - + gsm_error = convert_gss_to_gsm(maj_stat); @@ -644,7 +646,8 @@ static int HandleOP(GetVersionAndCapabilities) { int32_t cap = HAS_MONIKER; - char name[256] = "unknown", *str; + char *name = NULL, *str = NULL; + int ret; if (targetname) cap |= ISSERVER; /* is server */ @@ -653,18 +656,24 @@ HandleOP(GetVersionAndCapabilities) { struct utsname ut; if (uname(&ut) == 0) { - snprintf(name, sizeof(name), "%s-%s-%s", - ut.sysname, ut.version, ut.machine); + if (asprintf(&name, "%s-%s-%s", + ut.sysname, ut.version, ut.machine) == -1) { + errx(1, "out of memory"); + } } } #endif - asprintf(&str, "gssmask %s %s", PACKAGE_STRING, name); + ret = asprintf(&str, "gssmask %s %s", PACKAGE_STRING, + name ? name : "unknown"); + if (ret == -1) + errx(1, "out of memory"); put32(c, GSSMAGGOTPROTOCOL); put32(c, cap); putstring(c, str); free(str); + free(name); return 0; } @@ -683,7 +692,8 @@ static int HandleOP(SetLoggingSocket) { int32_t portnum; - int fd, ret; + krb5_socket_t sock; + int ret; ret32(c, portnum); @@ -692,22 +702,22 @@ HandleOP(SetLoggingSocket) socket_set_port((struct sockaddr *)(&c->sa), htons(portnum)); - fd = socket(((struct sockaddr *)&c->sa)->sa_family, SOCK_STREAM, 0); - if (fd < 0) + sock = socket(((struct sockaddr *)&c->sa)->sa_family, SOCK_STREAM, 0); + if (sock == rk_INVALID_SOCKET) return 0; - ret = connect(fd, (struct sockaddr *)&c->sa, c->salen); + ret = connect(sock, (struct sockaddr *)&c->sa, c->salen); if (ret < 0) { logmessage(c, __FILE__, __LINE__, 0, "failed connect to log port: %s", strerror(errno)); - close(fd); + rk_closesocket(sock); return 0; } if (c->logging) krb5_storage_free(c->logging); - c->logging = krb5_storage_from_fd(fd); - close(fd); + c->logging = krb5_storage_from_socket(sock); + rk_closesocket(sock); krb5_store_int32(c->logging, eLogSetMoniker); store_string(c->logging, c->moniker); @@ -799,7 +809,7 @@ HandleOP(Unwrap) if (maj_stat != GSS_S_COMPLETE) errx(1, "gss_unwrap failed: %d/%d", maj_stat, min_stat); - + krb5_data_free(&token); if (maj_stat == GSS_S_COMPLETE) { token.data = output_token.value; @@ -848,23 +858,12 @@ HandleOP(CallExtension) errx(1, "CallExtension"); } -krb5_error_code KRB5_LIB_FUNCTION -_krb5_pk_enterprise_cert ( - krb5_context /*context*/, - const char */*user_id*/, - krb5_const_realm /*realm*/, - krb5_principal */*principal*/); - - static int HandleOP(AcquirePKInitCreds) { - krb5_error_code ret; int32_t flags; krb5_data pfxdata; char fn[] = "FILE:/tmp/pkcs12-creds-XXXXXXX"; - const char *default_realm = "H5L.ORG"; - krb5_principal principal = NULL; int fd; ret32(c, flags); @@ -878,16 +877,6 @@ HandleOP(AcquirePKInitCreds) krb5_data_free(&pfxdata); close(fd); - /* get credentials */ - - ret = _krb5_pk_enterprise_cert(context, fn, default_realm, &principal); - if (ret) - krb5_err(context, 1, ret, "krb5_pk_enterprise_certs"); - - - if (principal) - krb5_free_principal(context, principal); - put32(c, -1); /* hResource */ put32(c, GSMERR_NOT_SUPPORTED); return 0; @@ -966,7 +955,9 @@ HandleOP(WrapExt) memcpy(p, iov[4].buffer.value, iov[4].buffer.length); p += iov[4].buffer.length; memcpy(p, iov[5].buffer.value, iov[5].buffer.length); +#if 0 /* Would be needed to keep going, but presently unused */ p += iov[5].buffer.length; +#endif gss_release_iov_buffer(NULL, iov, iov_len); @@ -1030,7 +1021,7 @@ HandleOP(UnwrapExt) if (maj_stat != GSS_S_COMPLETE) errx(1, "gss_unwrap failed: %d/%d", maj_stat, min_stat); - + if (maj_stat == GSS_S_COMPLETE) { token.data = iov[1].buffer.value; token.length = iov[1].buffer.length; @@ -1100,9 +1091,10 @@ find_op(int32_t op) } static struct client * -create_client(int fd, int port, const char *moniker) +create_client(krb5_socket_t sock, int port, const char *moniker) { struct client *c; + int ret; c = ecalloc(1, sizeof(*c)); @@ -1111,23 +1103,28 @@ create_client(int fd, int port, const char *moniker) } else { char hostname[MAXHOSTNAMELEN]; gethostname(hostname, sizeof(hostname)); - asprintf(&c->moniker, "gssmask: %s:%d", hostname, port); + ret = asprintf(&c->moniker, "gssmask: %s:%d", hostname, port); + if (ret == -1) + c->moniker = NULL; } + if (!c->moniker) + errx(1, "out of memory"); + { c->salen = sizeof(c->sa); - getpeername(fd, (struct sockaddr *)&c->sa, &c->salen); - + getpeername(sock, (struct sockaddr *)&c->sa, &c->salen); + getnameinfo((struct sockaddr *)&c->sa, c->salen, c->servername, sizeof(c->servername), - NULL, 0, NI_NUMERICHOST); + NULL, 0, NI_NUMERICHOST|NI_NUMERICSERV|NI_NUMERICSCOPE); } - c->sock = krb5_storage_from_fd(fd); + c->sock = krb5_storage_from_socket(sock); if (c->sock == NULL) - errx(1, "krb5_storage_from_fd"); + errx(1, "krb5_storage_from_socket"); - close(fd); + rk_closesocket(sock); return c; } @@ -1215,6 +1212,7 @@ int main(int argc, char **argv) { int optidx = 0; + krb5_error_code ret; setprogname (argv[0]); @@ -1240,7 +1238,9 @@ main(int argc, char **argv) errx (1, "Bad port `%s'", port_str); } - krb5_init_context(&context); + ret = krb5_init_context(&context); + if (ret) + errx(1, "Error initializing kerberos: %d", ret); { const char *lf = logfile_str; @@ -1252,7 +1252,7 @@ main(int argc, char **argv) err(1, "error opening %s", lf); } - mini_inetd(htons(port)); + mini_inetd(htons(port), NULL); fprintf(logfile, "connected\n"); { diff --git a/appl/kf/Makefile.am b/appl/kf/Makefile.am index eb78cca99..0b38057ca 100644 --- a/appl/kf/Makefile.am +++ b/appl/kf/Makefile.am @@ -17,4 +17,4 @@ LDADD = $(top_builddir)/lib/krb5/libkrb5.la \ $(top_builddir)/lib/asn1/libasn1.la \ $(LIB_roken) -EXTRA_DIST = $(man_MANS) +EXTRA_DIST = NTMakefile $(man_MANS) diff --git a/appl/kf/NTMakefile b/appl/kf/NTMakefile new file mode 100644 index 000000000..6ade4ab9b --- /dev/null +++ b/appl/kf/NTMakefile @@ -0,0 +1,35 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=appl\kf + +!include ../../windows/NTMakefile.w32 + diff --git a/appl/kf/kf.1 b/appl/kf/kf.1 index c43026d75..290e6bb52 100644 --- a/appl/kf/kf.1 +++ b/appl/kf/kf.1 @@ -1,39 +1,39 @@ .\" Copyright (c) 2000 - 2001 Kungliga Tekniska Högskolan -.\" (Royal Institute of Technology, Stockholm, Sweden). -.\" All rights reserved. +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. .\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: .\" -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. .\" -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. .\" -.\" 3. Neither the name of the Institute nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. .\" -.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" .\" $Id$ .\" .Dd July 2, 2000 .Dt KF 1 -.Os Heimdal +.Os .Sh NAME .Nm kf .Nd securely forward tickets @@ -41,20 +41,20 @@ .Nm .Oo .Fl p Ar port | -.Fl -port Ns = Ns Ar port +.Fl Fl port Ns = Ns Ar port .Oc .Oo .Fl l Ar login | -.Fl -login Ns = Ns Ar login +.Fl Fl login Ns = Ns Ar login .Oc .Oo .Fl c Ar ccache | -.Fl -ccache Ns = Ns Ar ccache +.Fl Fl ccache Ns = Ns Ar ccache .Oc .Op Fl F | -forwardable .Op Fl G | -no-forwardable .Op Fl h | -help -.Op Fl -version +.Op Fl Fl version .Ar host ... .Sh DESCRIPTION The @@ -65,17 +65,17 @@ Options supported are: .Bl -tag -width indent .It Xo .Fl p Ar port , -.Fl -port Ns = Ns Ar port +.Fl Fl port Ns = Ns Ar port .Xc port to connect to .It Xo .Fl l Ar login , -.Fl -login Ns = Ns Ar login +.Fl Fl login Ns = Ns Ar login .Xc remote login name .It Xo .Fl c Ar ccache , -.Fl -ccache Ns = Ns Ar ccache +.Fl Fl ccache Ns = Ns Ar ccache .Xc remote cred cache .It Fl F , -forwardable @@ -83,7 +83,7 @@ forward forwardable credentials .It Fl G , -no-forwardable do not forward forwardable credentials .It Fl h , -help -.It Fl -version +.It Fl Fl version .El .Pp .Nm @@ -94,7 +94,7 @@ In order for .Nm to work you will need to acquire your initial ticket with forwardable flag, i.e. -.Nm kinit Fl -forwardable . +.Nm kinit Fl Fl forwardable . .Pp .Nm telnet is able to forward tickets by itself. diff --git a/appl/kf/kf.c b/appl/kf/kf.c index e3e72ab06..fd4f17498 100644 --- a/appl/kf/kf.c +++ b/appl/kf/kf.c @@ -51,38 +51,38 @@ static struct getargs args[] = { "Forward forwardable credentials", NULL }, { "forwardable",'G',arg_negative_flag,&forwardable, "Don't forward forwardable credentials", NULL }, - { "help", 'h', arg_flag, &help_flag }, - { "version", 0, arg_flag, &version_flag } + { "help", 'h', arg_flag, &help_flag, NULL, NULL }, + { "version", 0, arg_flag, &version_flag, NULL, NULL } }; static int num_args = sizeof(args) / sizeof(args[0]); static void -usage(int code, struct getargs *args, int num_args) +usage(int code, struct getargs *inargs, int num_inargs) { - arg_printusage(args, num_args, NULL, "hosts"); + arg_printusage(inargs, num_inargs, NULL, "hosts"); exit(code); } static int -client_setup(krb5_context *context, int *argc, char **argv) +client_setup(krb5_context *ctx, int *argc, char **argv) { - int optind = 0; + int optidx = 0; int port = 0; int status; setprogname (argv[0]); - status = krb5_init_context (context); + status = krb5_init_context (ctx); if (status) errx(1, "krb5_init_context failed: %d", status); - forwardable = krb5_config_get_bool (*context, NULL, + forwardable = krb5_config_get_bool (*ctx, NULL, "libdefaults", "forwardable", NULL); - if (getarg (args, num_args, *argc, argv, &optind)) + if (getarg (args, num_args, *argc, argv, &optidx)) usage(1, args, num_args); if(help_flag) @@ -107,11 +107,11 @@ client_setup(krb5_context *context, int *argc, char **argv) } if (port == 0) - port = krb5_getportbyname (*context, KF_PORT_NAME, "tcp", KF_PORT_NUM); + port = krb5_getportbyname (*ctx, KF_PORT_NAME, "tcp", KF_PORT_NUM); - if(*argc - optind < 1) + if(*argc - optidx < 1) usage(1, args, num_args); - *argc = optind; + *argc = optidx; return port; } @@ -122,7 +122,7 @@ client_setup(krb5_context *context, int *argc, char **argv) */ static int -proto (int sock, const char *hostname, const char *service, +proto (int sock, const char *hostname, const char *svc, char *message, size_t len) { krb5_auth_context auth_context; @@ -153,7 +153,7 @@ proto (int sock, const char *hostname, const char *service, status = krb5_sname_to_principal (context, hostname, - service, + svc, KRB5_NT_SRV_HST, &server); if (status) { @@ -277,11 +277,11 @@ proto (int sock, const char *hostname, const char *service, } krb5_data_free (&data); - return(strcmp(message, "ok")); + return strcmp(message, "ok") != 0; } static int -doit (const char *hostname, int port, const char *service, +doit (const char *hostname, int port, const char *svc, char *message, size_t len) { struct addrinfo *ai, *a; @@ -312,7 +312,9 @@ doit (const char *hostname, int port, const char *service, continue; } freeaddrinfo (ai); - return proto (s, hostname, service, message, len); + error = proto(s, hostname, svc, message, len); + close(s); + return error; } warnx ("failed to contact %s", hostname); freeaddrinfo (ai); @@ -322,6 +324,7 @@ doit (const char *hostname, int port, const char *service, int main(int argc, char **argv) { + char userbuf[128]; int argcc,port,i; int ret=0; @@ -329,7 +332,7 @@ main(int argc, char **argv) port = client_setup(&context, &argcc, argv); if (remote_name == NULL) { - remote_name = get_default_username (); + remote_name = roken_get_username(userbuf, sizeof(userbuf)); if (remote_name == NULL) errx (1, "who are you?"); } diff --git a/appl/kf/kfd.8 b/appl/kf/kfd.8 index 847e24083..4b8b82299 100644 --- a/appl/kf/kfd.8 +++ b/appl/kf/kfd.8 @@ -1,39 +1,39 @@ .\" Copyright (c) 2000 - 2002 Kungliga Tekniska Högskolan -.\" (Royal Institute of Technology, Stockholm, Sweden). -.\" All rights reserved. +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. .\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: .\" -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. .\" -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. .\" -.\" 3. Neither the name of the Institute nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. .\" -.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" .\" $Id$ .\" .Dd July 2, 2000 .Dt KFD 8 -.Os Heimdal +.Os .Sh NAME .Nm kfd .Nd receive forwarded tickets @@ -41,15 +41,15 @@ .Nm .Oo .Fl p Ar port | -.Fl -port Ns = Ns Ar port +.Fl Fl port Ns = Ns Ar port .Oc .Op Fl i | -inetd .Oo .Fl R Ar regpag | -.Fl -regpag Ns = Ns Ar regpag +.Fl Fl regpag Ns = Ns Ar regpag .Oc .Op Fl h | -help -.Op Fl -version +.Op Fl Fl version .Sh DESCRIPTION This is the daemon for .Xr kf 1 . @@ -57,14 +57,14 @@ Supported options: .Bl -tag -width indent .It Xo .Fl p Ar port , -.Fl -port Ns = Ns Ar port +.Fl Fl port Ns = Ns Ar port .Xc port to listen to .It Fl i , -inetd not started from inetd .It Xo .Fl R Ar regpag , -.Fl -regpag= Ns Ar regpag +.Fl Fl regpag= Ns Ar regpag .Xc path to regpag binary .El diff --git a/appl/kf/kfd.c b/appl/kf/kfd.c index 10f8ef3df..9099bab9b 100644 --- a/appl/kf/kfd.c +++ b/appl/kf/kfd.c @@ -49,26 +49,26 @@ static struct getargs args[] = { { "inetd",'i',arg_flag, &do_inetd, "Not started from inetd", NULL }, { "regpag",'R',arg_string,®pag_str,"path to regpag binary","regpag"}, - { "help", 'h', arg_flag, &help_flag }, - { "version", 0, arg_flag, &version_flag } + { "help", 'h', arg_flag, &help_flag, NULL, NULL }, + { "version", 0, arg_flag, &version_flag, NULL, NULL } }; static int num_args = sizeof(args) / sizeof(args[0]); static void -usage(int code, struct getargs *args, int num_args) +usage(int code, struct getargs *inargs, int num_inargs) { - arg_printusage(args, num_args, NULL, ""); + arg_printusage(inargs, num_inargs, NULL, ""); exit(code); } static int -server_setup(krb5_context *context, int argc, char **argv) +server_setup(krb5_context *ctx, int argc, char **argv) { int port = 0; int local_argc; - local_argc = krb5_program_setup(context, argc, argv, args, num_args, usage); + local_argc = krb5_program_setup(ctx, argc, argv, args, num_args, usage); if(help_flag) (*usage)(0, args, num_args); @@ -92,7 +92,7 @@ server_setup(krb5_context *context, int argc, char **argv) } if (port == 0) - port = krb5_getportbyname (*context, KF_PORT_NAME, "tcp", KF_PORT_NUM); + port = krb5_getportbyname (*ctx, KF_PORT_NAME, "tcp", KF_PORT_NUM); if(argv[local_argc] != NULL) usage(1, args, num_args); @@ -120,7 +120,7 @@ kfd_match_version(const void *arg, const char *version) } static int -proto (int sock, const char *service) +proto (int sock, const char *svc) { krb5_auth_context auth_context; krb5_error_code status; @@ -151,7 +151,7 @@ proto (int sock, const char *service) status = krb5_sname_to_principal (context, hostname, - service, + svc, KRB5_NT_SRV_HST, &server); if (status) @@ -281,11 +281,11 @@ proto (int sock, const char *service) } static int -doit (int port, const char *service) +doit (int port, const char *svc) { if (do_inetd) - mini_inetd(port); - return proto (STDIN_FILENO, service); + mini_inetd(port, NULL); + return proto (STDIN_FILENO, svc); } int diff --git a/appl/kx/ChangeLog b/appl/kx/ChangeLog deleted file mode 100644 index 478463027..000000000 --- a/appl/kx/ChangeLog +++ /dev/null @@ -1,457 +0,0 @@ -2007-04-19 Love Hörnquist Åstrand - - * make encoding function independent of krb4 and krb5, enable - removal of krb4 - -2006-10-07 Love Hörnquist Åstrand - - * Makefile.am: Add man_MANS to EXTRA_DIST - -2006-05-05 Love Hörnquist Åstrand - - * Rename u_intXX_t to uintXX_t - -2005-07-09 Love Hörquist Åstrand - - * kxd.c (doit): only cleaup for active sockets, passive does it - own cleaning up - - * fix unconst and shadow warnings - -2005-07-07 Assar Westerlund - - * krb4.c: Do not assume that des_key_schedule is an - array. - -2005-06-07 Love Hörquist Åstrand - - * (recv_conn): init variables to using them uninitialized - -2005-04-30 Love Hörquist Åstrand - - * kx.c (connect_host): make sure s is initialized - -2005-04-20 Love Hörquist Åstrand - - * krb5.c: cast size_t to unsigned long - -2004-03-15 Love Hörquist Åstrand - - * krb5.c (krb5_destroy): free allocated memory, not something else - -2004-03-07 Love Hörquist Åstrand - - * rxtelnet.1: document new behavior - - * rxtelnet.in: even if kx failes, start anyway From: Harald Barth - - -2004-02-18 Love Hörquist Åstrand - - * krb4.c: remove dup on - -2004-01-08 Love Hörquist Åstrand - - * krb5.c: clean up krb5 support, log to syslog instead of stdout - (very confusing for the other end tcp connection), patch - originally from joda - -2003-11-13 Johan Danielsson - - * rxtelnet.in: add telnet -F option - -2003-05-15 Love Hörquist Åstrand - - * kxd.c (recv_conn): pass pointer to sockaddr, not pointer to - pointer - - * kxd.c (recv_conn): get sizeof of the sockaddr_storage, not the - sockaddr pointer - - * kxd.c (recv_conn): if getnameinfo failes, send error to client - (and syslog) - -2003-04-16 Johan Danielsson - - * kx.c (doit_{passive,active}): use kc->thataddr directly - - * kx.h: don't directly use sockaddr_storage, since we can't always - know what it looks like - -2003-04-11 Love Hörquist Åstrand - - * rxterm.1: spelling, from jmc - * rxtelnet.1: spelling, from jmc - * kxd.8: spelling, from jmc - * kx.1: spelling, from jmc - -2003-02-25 Love Hörquist Åstrand - - * krb4.c: remove \n from warnx, from NetBSD - -2002-12-11 Johan Danielsson - - * kx.c (connect_host): pass size of thisaddr_ss to getsockname - -2002-10-15 Johan Danielsson - - * some ipv6 support (from Love) - -2002-09-09 Johan Danielsson - - * krb5.c (krb5_authenticate): use subkey - -2002-08-22 Johan Danielsson - - * common.c: remove only reference to strndup - -2002-05-07 Johan Danielsson - - * krb5.c: use krb5_warn where appropriate - -2002-03-18 Johan Danielsson - - * rxtelnet.in, rxterm.in: add forward (-f) option - -2001-09-17 Assar Westerlund - - * kx.h: add a kludge to make it build on aix (that defines NOERROR - in both sys/stream.h and arpa/nameser.h and considers that a fatal - error) - -2001-07-12 Assar Westerlund - - * common.c (connect_local_xsocket): handle a tcp socket as last - resort - - * rxterm.in: add -K (send arguments to kx) - * rxtelnet.in: add -K (send arguments to kx) - -2001-06-21 Assar Westerlund - - * rxterm.in: add -b for pointing to the rsh program. from - - * rxtelnet.in: add -b for pointing to the telnet program. from - - -2001-01-17 Johan Danielsson - - * common.c: don't write to string constants - -2000-12-31 Assar Westerlund - - * krb5.c (krb5_make_context): handle krb5_init_context failure - consistently - -2000-10-08 Assar Westerlund - - * kxd.c (doit_passive): check that fds are not too large to select - on - * kx.c (doit_active): check that fds are not too large to select - on - * krb5.c (krb5_copy_encrypted): check that fds are not too large - to select on - * krb4.c (krb4_copy_encrypted): check that fds are not too large - to select on - -2000-07-17 Johan Danielsson - - * Makefile.am: use conditional for X - -2000-06-10 Assar Westerlund - - * Makefile.in: use INSTALL_SCRIPT for installing rxterm, rxtelnet, - tenletxr - -2000-04-19 Assar Westerlund - - * common.c: try hostname uncanonified if getaddrinfo() fails - -2000-02-06 Assar Westerlund - - * kx.h: remove old prorotypes - -2000-01-08 Assar Westerlund - - * common.c (match_local_auth): handle ai_canonname being set in - any of the addresses returnedby getaddrinfo. glibc apparently - returns the reverse lookup of every address in ai_canonname. - -1999-12-28 Assar Westerlund - - * kxd.c (main): call krb5_getportbyname with the default in - host-byte-order - -1999-12-17 Assar Westerlund - - * common.c (match_local_auth): remove extra brace. spotted by - Jakob Schlyter - -1999-12-16 Assar Westerlund - - * common.c (match_local_auth): handle ai_canonname not being set - -1999-12-06 Assar Westerlund - - * krb4.c (krb4_authenticate): the NAT address might not be the one - for the relevant realm, try anyway. - * kxd.c (recv_conn): type correctness - * kx.c (connect_host): typo - -1999-12-05 Assar Westerlund - - * common.c (INADDR_LOOPBACK): remove. now in roken. - - * kxd.c (recv_conn): use getnameinfo_verified - * kxd.c (recv_conn): replace inaddr2str with getnameinfo - -1999-12-04 Assar Westerlund - - * kx.c (connect_host): use getaddrinfo - * common.c (find_auth_cookie, match_local_auth): re-write to use - getaddrinfo - -1999-11-27 Assar Westerlund - - * kxd.c (recv_conn): better errors when getting unrecognized data - -1999-11-25 Assar Westerlund - - * krb4.c (krb4_authenticate): obtain the `local' address when - doing NAT. also turn on passive mode. From - -1999-11-18 Assar Westerlund - - * krb5.c (krb5_destroy): free the correct part of the context - -1999-11-02 Assar Westerlund - - * kx.c (main): redo the v4/v5 selection for consistency. -4 -> - try only v4 -5 -> try only v5 none, -45 -> try v5, v4 - -1999-10-10 Assar Westerlund - - * Makefile.am (CLEANFILES): add generated files so that they get - cleaned away - -1999-09-29 Assar Westerlund - - * common.c (match_local_auth): only look for FamilyLocal (and - FamilyWild) cookies. This will not work when we start talking tcp - to the local X-server but `connect_local_xsocket' and the rest of - the code doesn't handle it anyway and the old code could (and did) - pick up the wrong cookie sometimes. If we have to match - FamilyInternet cookies, the search order has to be changed anyway - -1999-09-02 Assar Westerlund - - * kxd.c (childhandler): watch for child `wait_on_pid' to die. - (recv_conn): set `wait_on_pid' instead of looping on waitpid here - also. This should solve the problem of kxd looping which was - caused by the signal handler getting invoked before this waitpid - and reaping the child leaving this poor loop without any child - -1999-08-19 Assar Westerlund - - * kxd.c (recv_conn): give better error message - (doit_active): don't die if fork gives EAGAIN - -1999-08-19 Johan Danielsson - - * kxd.c (recv_conn): call setjob on crays; - (doit_passive): if fork fails with EAGAIN, don't shutdown, just close - the connection re-implement `-t' flag - -1999-07-12 Assar Westerlund - - * Makefile.am: handle not building X programs - -1999-06-23 Assar Westerlund - - * kx.c: conditionalize krb_enable_debug - -1999-06-20 Assar Westerlund - - * kxd.c (main): hopefully do inetd confusion right - -1999-06-15 Assar Westerlund - - * krb4.c (krb4_authenticate): get rid of a warning - - * kx.h: const-pollution - - * kx.c: use get_default_username and resulting const pollution - - * context.c (context_set): const pollution - -1999-05-22 Assar Westerlund - - * kxd.c (recv_conn): fix syslog messages - (main): fix inetd_flag thinko - -1999-05-21 Assar Westerlund - - * kx.c (main): don't byte-swap the argument to krb5_getportbyname - - * kx.c (main): try to use $USERNAME - -1999-05-10 Assar Westerlund - - * Makefile.in (SOURCES*): update sources list - - * kx.c (main): forgot to conditionalize some KRB5 code - - * kxd.c (main): use getarg - (*): handle v4 and/or v5 - - * kx.h: update - - * kx.c (main): use getarg. - (*): handle v4 and/or v5 - - * common.c (do_enccopy, copy_encrypted): remove use - net_{read,write} instead of krb_net_{read,write} - (krb_get_int, krb_put_int): include fallback of these for when we - compile without krb4 - - * Makefile.am (*_SOURCES): remove encdata, add krb[45].c, - context.c - (LDADD): add krb5 - - * krb4.c, krb5.c, context.c: new files - -1999-05-08 Assar Westerlund - - * kxd.c (doit_passive): handle error code from - create_and_write_cookie - - * kx.c (doit_active): handle error code from - create_and_write_cookie - - * common.c (create_and_write_cookie): try to return better (and - correct) errors. Based on a patch from Love - - * common.c (try_pie): more braces - (match_local_auth): new function - (find_auth_cookie): new function - (replace_cookie): don't just take the first auth cookie. based on - patch from Ake Sandgren - -Wed Apr 7 23:39:23 1999 Assar Westerlund - - * common.c (get_xsockets): init local variable to get rid of a gcc - warning - -Thu Apr 1 21:11:36 1999 Johan Danielsson - - * Makefile.in: fix for writeauth.o - -Fri Mar 19 15:12:31 1999 Johan Danielsson - - * kx.c: add gcc-braces - -Thu Mar 18 11:18:20 1999 Johan Danielsson - - * Makefile.am: include Makefile.am.common - -Thu Mar 11 14:58:32 1999 Johan Danielsson - - * writeauth.c: protoize - - * common.c: fix some warnings - -Wed Mar 10 19:33:39 1999 Johan Danielsson - - * kxd.c: openlog -> roken_openlog - -Wed Feb 3 22:01:55 1999 Assar Westerlund - - * rxtelnet.in: print out what telnet program we are running. From - - - * tenletxr.in: add --version, [-h | --help], -v - - * rxterm.in: add --version, [-h | --help], -v - - * rxtelnet.in: add --version, [-h | --help], -v - - * Makefile.in (rxterm, rxtelnet, telnetxr): substitute VERSION and - PACKAGE - - * rxtelnet.in: update usage string - -Fri Jan 22 23:51:05 1999 Assar Westerlund - - * common.c (verify_and_remove_cookies): give back a meaningful - error message if we're using the wrong cookie - -Fri Dec 18 17:42:02 1998 Assar Westerlund - - * common.c (replace_cookie): try to handle the case of not finding - any cookies - -Sun Nov 22 10:31:53 1998 Assar Westerlund - - * Makefile.in (WFLAGS): set - -Wed Nov 18 20:25:37 1998 Assar Westerlund - - * rxtelnet.in: new argument -n for not starting any terminal - emulator - - * kx.c (doit_passive): parse $DISPLAY correctly - -Fri Oct 2 06:34:51 1998 Assar Westerlund - - * kx.c (doit_active): check DISPLAY to figure out what local - socket to connect to. From Åke Sandgren - -Thu Oct 1 23:02:29 1998 Johan Danielsson - - * kx.h: case MAY_HAVE_X11_PIPES with Solaris - -Tue Sep 29 02:22:44 1998 Assar Westerlund - - * kx.c: fix from Ake Sandgren - -Mon Sep 28 18:04:03 1998 Johan Danielsson - - * common.c (try_pipe): return -1 if I_PUSH fails with ENOSYS - -Sat Sep 26 17:34:21 1998 Assar Westerlund - - * kxd.c: create sockets before setuid to handle Solaris' strange - permissions on /tmp/.X11-{unix,pipe} - - * common.c (chown_xsockets): new function - - * kx.h (chown_xsockets): new prototype - -Sun Aug 16 18:34:30 1998 Assar Westerlund - - * kxd.c (doit_passive): conditionalize stream pipe code - - * implement support for Solaris's named-pipe X transport - -Thu May 28 17:20:39 1998 Johan Danielsson - - * common.c: fix for (compiler?) bug in solaris 2.4 bind - - * kx.c: get_xsockets returns int, not unsigned - -Wed May 27 04:20:20 1998 Assar Westerlund - - * kxd.c (doit): better error reporting - -Tue May 26 17:41:23 1998 Johan Danielsson - - * kx.c: use krb_enable_debug - -Mon May 25 05:22:18 1998 Assar Westerlund - - * Makefile.in (clean): remove encdata.c - -Fri May 1 07:16:36 1998 Assar Westerlund - - * kx.c: unifdef -DHAVE_H_ERRNO - diff --git a/appl/kx/Makefile.am b/appl/kx/Makefile.am deleted file mode 100644 index b5f026ca4..000000000 --- a/appl/kx/Makefile.am +++ /dev/null @@ -1,70 +0,0 @@ -# $Id$ - -include $(top_srcdir)/Makefile.am.common - -AM_CPPFLAGS += $(X_CFLAGS) - -WFLAGS += $(WFLAGS_NOIMPLICITINT) - -if HAVE_X - -bin_PROGRAMS = kx -bin_SCRIPTS = rxterm rxtelnet tenletxr -libexec_PROGRAMS = kxd - -else - -bin_PROGRAMS = -bin_SCRIPTS = -libexec_PROGRAMS = - -endif - -CLEANFILES = rxterm rxtelnet tenletxr - -if NEED_WRITEAUTH -XauWriteAuth_c = writeauth.c -endif - -kx_SOURCES = \ - kx.c \ - kx.h \ - common.c \ - context.c \ - krb5.c \ - $(XauWriteAuth_c) - -EXTRA_kx_SOURCES = writeauth.c - -kxd_SOURCES = \ - kxd.c \ - kx.h \ - common.c \ - context.c \ - krb5.c \ - $(XauWriteAuth_c) - -EXTRA_kxd_SOURCES = writeauth.c - -EXTRA_DIST = rxterm.in rxtelnet.in tenletxr.in $(man_MANS) - -man_MANS = kx.1 rxtelnet.1 rxterm.1 tenletxr.1 kxd.8 - -rxterm: rxterm.in - sed -e "s!%bindir%!$(bindir)!" $(srcdir)/rxterm.in > $@ - chmod +x $@ - -rxtelnet: rxtelnet.in - sed -e "s!%bindir%!$(bindir)!" $(srcdir)/rxtelnet.in > $@ - chmod +x $@ - -tenletxr: tenletxr.in - sed -e "s!%bindir%!$(bindir)!" $(srcdir)/tenletxr.in > $@ - chmod +x $@ - -LDADD = \ - $(LIB_kafs) \ - $(LIB_krb5) \ - $(LIB_hcrypto) \ - $(LIB_roken) \ - $(X_LIBS) $(LIB_XauReadAuth) $(X_PRE_LIBS) $(X_EXTRA_LIBS) diff --git a/appl/kx/common.c b/appl/kx/common.c deleted file mode 100644 index 9c3b20672..000000000 --- a/appl/kx/common.c +++ /dev/null @@ -1,813 +0,0 @@ -/* - * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "kx.h" - -RCSID("$Id$"); - -char x_socket[MaxPathLen]; - -uint32_t display_num; -char display[MaxPathLen]; -int display_size = sizeof(display); -char xauthfile[MaxPathLen]; -int xauthfile_size = sizeof(xauthfile); -u_char cookie[16]; -size_t cookie_len = sizeof(cookie); - -#ifndef X_UNIX_PATH -#define X_UNIX_PATH "/tmp/.X11-unix/X" -#endif - -#ifndef X_PIPE_PATH -#define X_PIPE_PATH "/tmp/.X11-pipe/X" -#endif - -/* - * Allocate a unix domain socket in `s' for display `dpy' and with - * filename `pattern' - * - * 0 if all is OK - * -1 if bind failed badly - * 1 if dpy is already used */ - -static int -try_socket (struct x_socket *s, int dpy, const char *pattern) -{ - struct sockaddr_un addr; - int fd; - - fd = socket (AF_UNIX, SOCK_STREAM, 0); - if (fd < 0) - err (1, "socket AF_UNIX"); - memset (&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - snprintf (addr.sun_path, sizeof(addr.sun_path), pattern, dpy); - if(bind(fd, - (struct sockaddr *)&addr, - sizeof(addr)) < 0) { - close (fd); - if (errno == EADDRINUSE || - errno == EACCES /* Cray return EACCESS */ -#ifdef ENOTUNIQ - || errno == ENOTUNIQ /* bug in Solaris 2.4 */ -#endif - ) - return 1; - else - return -1; - } - s->fd = fd; - s->pathname = strdup (addr.sun_path); - if (s->pathname == NULL) - errx (1, "strdup: out of memory"); - s->flags = UNIX_SOCKET; - return 0; -} - -#ifdef MAY_HAVE_X11_PIPES -/* - * Allocate a stream (masqueraded as a named pipe) - * - * 0 if all is OK - * -1 if bind failed badly - * 1 if dpy is already used - */ - -static int -try_pipe (struct x_socket *s, int dpy, const char *pattern) -{ - char path[MAXPATHLEN]; - int ret; - int fd; - int pipefd[2]; - - snprintf (path, sizeof(path), pattern, dpy); - fd = open (path, O_WRONLY | O_CREAT | O_EXCL, 0600); - if (fd < 0) { - if (errno == EEXIST) - return 1; - else - return -1; - } - - close (fd); - - ret = pipe (pipefd); - if (ret < 0) - err (1, "pipe"); - - ret = ioctl (pipefd[1], I_PUSH, "connld"); - if (ret < 0) { - if(errno == ENOSYS) - return -1; - err (1, "ioctl I_PUSH"); - } - - ret = fattach (pipefd[1], path); - if (ret < 0) - err (1, "fattach %s", path); - - s->fd = pipefd[0]; - close (pipefd[1]); - s->pathname = strdup (path); - if (s->pathname == NULL) - errx (1, "strdup: out of memory"); - s->flags = STREAM_PIPE; - return 0; -} -#endif /* MAY_HAVE_X11_PIPES */ - -/* - * Try to create a TCP socket in `s' corresponding to display `dpy'. - * - * 0 if all is OK - * -1 if bind failed badly - * 1 if dpy is already used - */ - -static int -try_tcp (struct x_socket *s, int dpy) -{ - struct sockaddr_in tcpaddr; - struct in_addr local; - int one = 1; - int fd; - - memset(&local, 0, sizeof(local)); - local.s_addr = htonl(INADDR_LOOPBACK); - - fd = socket (AF_INET, SOCK_STREAM, 0); - if (fd < 0) - err (1, "socket AF_INET"); -#if defined(TCP_NODELAY) && defined(HAVE_SETSOCKOPT) - setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (void *)&one, - sizeof(one)); -#endif - memset (&tcpaddr, 0, sizeof(tcpaddr)); - tcpaddr.sin_family = AF_INET; - tcpaddr.sin_addr = local; - tcpaddr.sin_port = htons(6000 + dpy); - if (bind (fd, (struct sockaddr *)&tcpaddr, - sizeof(tcpaddr)) < 0) { - close (fd); - if (errno == EADDRINUSE) - return 1; - else - return -1; - } - s->fd = fd; - s->pathname = NULL; - s->flags = TCP; - return 0; -} - -/* - * The potential places to create unix sockets. - */ - -static char *x_sockets[] = { -X_UNIX_PATH "%u", -"/var/X/.X11-unix/X" "%u", -"/usr/spool/sockets/X11/" "%u", -NULL -}; - -/* - * Dito for stream pipes. - */ - -#ifdef MAY_HAVE_X11_PIPES -static char *x_pipes[] = { -X_PIPE_PATH "%u", -"/var/X/.X11-pipe/X" "%u", -NULL -}; -#endif - -/* - * Create the directory corresponding to dirname of `path' or fail. - */ - -static void -try_mkdir (const char *path) -{ - char *dir; - char *p; - int oldmask; - - if((dir = strdup (path)) == NULL) - errx (1, "strdup: out of memory"); - p = strrchr (dir, '/'); - if (p) - *p = '\0'; - - oldmask = umask(0); - mkdir (dir, 01777); - umask (oldmask); - free (dir); -} - -/* - * Allocate a display, returning the number of sockets in `number' and - * all the corresponding sockets in `sockets'. If `tcp_socket' is - * true, also allcoaet a TCP socket. - * - * The return value is the display allocated or -1 if an error occurred. - */ - -int -get_xsockets (int *number, struct x_socket **sockets, int tcp_socket) -{ - int dpy; - struct x_socket *s; - int n; - int i; - - s = malloc (sizeof(*s) * 5); - if (s == NULL) - errx (1, "malloc: out of memory"); - - try_mkdir (X_UNIX_PATH); - try_mkdir (X_PIPE_PATH); - - for(dpy = 4; dpy < 256; ++dpy) { - char **path; - int tmp = 0; - - n = 0; - for (path = x_sockets; *path; ++path) { - tmp = try_socket (&s[n], dpy, *path); - if (tmp == -1) { - if (errno != ENOTDIR && errno != ENOENT) - err(1, "failed to open '%s'", *path); - } else if (tmp == 1) { - while(--n >= 0) { - close (s[n].fd); - free (s[n].pathname); - } - break; - } else if (tmp == 0) - ++n; - } - if (tmp == 1) - continue; - -#ifdef MAY_HAVE_X11_PIPES - for (path = x_pipes; *path; ++path) { - tmp = try_pipe (&s[n], dpy, *path); - if (tmp == -1) { - if (errno != ENOTDIR && errno != ENOENT && errno != ENOSYS) - err(1, "failed to open '%s'", *path); - } else if (tmp == 1) { - while (--n >= 0) { - close (s[n].fd); - free (s[n].pathname); - } - break; - } else if (tmp == 0) - ++n; - } - - if (tmp == 1) - continue; -#endif - - if (tcp_socket) { - tmp = try_tcp (&s[n], dpy); - if (tmp == -1) - err(1, "failed to open tcp stocket"); - else if (tmp == 1) { - while (--n >= 0) { - close (s[n].fd); - free (s[n].pathname); - } - break; - } else if (tmp == 0) - ++n; - } - break; - } - if (dpy == 256) - errx (1, "no free x-servers"); - for (i = 0; i < n; ++i) - if (s[i].flags & LISTENP - && listen (s[i].fd, SOMAXCONN) < 0) - err (1, "listen %s", s[i].pathname ? s[i].pathname : "tcp"); - *number = n; - *sockets = s; - return dpy; -} - -/* - * Change owner on the `n' sockets in `sockets' to `uid', `gid'. - * Return 0 is succesful or -1 if an error occurred. - */ - -int -chown_xsockets (int n, struct x_socket *sockets, uid_t uid, gid_t gid) -{ - int i; - - for (i = 0; i < n; ++i) - if (sockets[i].pathname != NULL) - if (chown (sockets[i].pathname, uid, gid) < 0) - return -1; - return 0; -} - -/* - * Connect to local display `dnr' with local transport or TCP. - * Return a file descriptor. - */ - -int -connect_local_xsocket (unsigned dnr) -{ - int fd; - char **path; - - for (path = x_sockets; *path; ++path) { - struct sockaddr_un addr; - - fd = socket (AF_UNIX, SOCK_STREAM, 0); - if (fd < 0) - break; - memset (&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - snprintf (addr.sun_path, sizeof(addr.sun_path), *path, dnr); - if (connect (fd, (struct sockaddr *)&addr, sizeof(addr)) == 0) - return fd; - close(fd); - } - { - struct sockaddr_in addr; - - fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd < 0) - err (1, "socket AF_INET"); - memset (&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - addr.sin_port = htons(6000 + dnr); - if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == 0) - return fd; - close(fd); - } - err (1, "connecting to local display %u", dnr); -} - -/* - * Create a cookie file with a random cookie for the localhost. The - * file name will be stored in `xauthfile' (but not larger than - * `xauthfile_size'), and the cookie returned in `cookie', `cookie_sz'. - * Return 0 if succesful, or errno. - */ - -int -create_and_write_cookie (char *file, - size_t file_size, - u_char *cookie_buf, - size_t cookie_sz) -{ - Xauth auth; - char tmp[64]; - int fd; - FILE *f; - char hostname[MaxHostNameLen]; - int saved_errno; - - gethostname (hostname, sizeof(hostname)); - - auth.family = FamilyLocal; - auth.address = hostname; - auth.address_length = strlen(auth.address); - snprintf (tmp, sizeof(tmp), "%d", display_num); - auth.number_length = strlen(tmp); - auth.number = tmp; - auth.name = COOKIE_TYPE; - auth.name_length = strlen(auth.name); - auth.data_length = cookie_sz; - auth.data = (char*)cookie_buf; -#ifdef KRB5 - krb5_generate_random_block (cookie_buf, cookie_sz); -#else - krb_generate_random_block (cookie_buf, cookie_sz); -#endif - - strlcpy(file, "/tmp/AXXXXXX", file_size); - fd = mkstemp(file); - if(fd < 0) { - saved_errno = errno; - syslog(LOG_ERR, "create_and_write_cookie: mkstemp: %m"); - return saved_errno; - } - f = fdopen(fd, "r+"); - if(f == NULL){ - saved_errno = errno; - close(fd); - return errno; - } - if(XauWriteAuth(f, &auth) == 0) { - saved_errno = errno; - fclose(f); - return saved_errno; - } - - /* - * I would like to write a cookie for localhost:n here, but some - * stupid code in libX11 will not look for cookies of that type, - * so we are forced to use FamilyWild instead. - */ - - auth.family = FamilyWild; - auth.address_length = 0; - - if (XauWriteAuth(f, &auth) == 0) { - saved_errno = errno; - fclose (f); - return saved_errno; - } - - if(fclose(f)) - return errno; - return 0; -} - -/* - * Verify and remove cookies. Read and parse a X-connection from - * `fd'. Check the cookie used is the same as in `cookie'. Remove the - * cookie and copy the rest of it to `sock'. - * Expect cookies iff cookiesp. - * Return 0 iff ok. - * - * The protocol is as follows: - * - * C->S: [Bl] 1 - * unused 1 - * protocol major version 2 - * protocol minor version 2 - * length of auth protocol name(n) 2 - * length of auth protocol data 2 - * unused 2 - * authorization protocol name n - * pad pad(n) - * authorization protocol data d - * pad pad(d) - * - * S->C: Failed - * 0 1 - * length of reason 1 - * protocol major version 2 - * protocol minor version 2 - * length in 4 bytes unit of - * additional data (n+p)/4 2 - * reason n - * unused p = pad(n) - */ - -int -verify_and_remove_cookies (int fd, int sock, int cookiesp) -{ - u_char beg[12]; - int bigendianp; - unsigned n, d, npad, dpad; - char *protocol_name, *protocol_data; - u_char zeros[6] = {0, 0, 0, 0, 0, 0}; - u_char refused[20] = {0, 10, - 0, 0, /* protocol major version */ - 0, 0, /* protocol minor version */ - 0, 0, /* length of additional data / 4 */ - 'b', 'a', 'd', ' ', 'c', 'o', 'o', 'k', 'i', 'e', - 0, 0}; - - if (net_read (fd, beg, sizeof(beg)) != sizeof(beg)) - return 1; - if (net_write (sock, beg, 6) != 6) - return 1; - bigendianp = beg[0] == 'B'; - if (bigendianp) { - n = (beg[6] << 8) | beg[7]; - d = (beg[8] << 8) | beg[9]; - } else { - n = (beg[7] << 8) | beg[6]; - d = (beg[9] << 8) | beg[8]; - } - npad = (4 - (n % 4)) % 4; - dpad = (4 - (d % 4)) % 4; - protocol_name = malloc(n + npad); - if (n + npad != 0 && protocol_name == NULL) - return 1; - protocol_data = malloc(d + dpad); - if (d + dpad != 0 && protocol_data == NULL) { - free (protocol_name); - return 1; - } - if (net_read (fd, protocol_name, n + npad) != n + npad) - goto fail; - if (net_read (fd, protocol_data, d + dpad) != d + dpad) - goto fail; - if (cookiesp) { - if (strncmp (protocol_name, COOKIE_TYPE, strlen(COOKIE_TYPE)) != 0) - goto refused; - if (d != cookie_len || - memcmp (protocol_data, cookie, cookie_len) != 0) - goto refused; - } - free (protocol_name); - free (protocol_data); - if (net_write (sock, zeros, 6) != 6) - return 1; - return 0; -refused: - refused[2] = beg[2]; - refused[3] = beg[3]; - refused[4] = beg[4]; - refused[5] = beg[5]; - if (bigendianp) - refused[7] = 3; - else - refused[6] = 3; - - net_write (fd, refused, sizeof(refused)); -fail: - free (protocol_name); - free (protocol_data); - return 1; -} - -/* - * Return 0 iff `cookie' is compatible with the cookie for the - * localhost with name given in `ai' (or `hostname') and display - * number in `disp_nr'. - */ - -static int -match_local_auth (Xauth* auth, - struct addrinfo *ai, const char *hostname, int disp_nr) -{ - int auth_disp; - char *tmp_disp; - struct addrinfo *a; - - tmp_disp = malloc(auth->number_length + 1); - if (tmp_disp == NULL) - return -1; - memcpy(tmp_disp, auth->number, auth->number_length); - tmp_disp[auth->number_length] = '\0'; - auth_disp = atoi(tmp_disp); - free (tmp_disp); - if (auth_disp != disp_nr) - return 1; - for (a = ai; a != NULL; a = a->ai_next) { - if ((auth->family == FamilyLocal - || auth->family == FamilyWild) - && a->ai_canonname != NULL - && strncmp (auth->address, - a->ai_canonname, - auth->address_length) == 0) - return 0; - } - if (hostname != NULL - && (auth->family == FamilyLocal - || auth->family == FamilyWild) - && strncmp (auth->address, hostname, auth->address_length) == 0) - return 0; - return 1; -} - -/* - * Find `our' cookie from the cookie file `f' and return it or NULL. - */ - -static Xauth* -find_auth_cookie (FILE *f) -{ - Xauth *ret = NULL; - char local_hostname[MaxHostNameLen]; - char *display_str = getenv("DISPLAY"); - char d[MaxHostNameLen + 4]; - char *colon; - struct addrinfo *ai; - struct addrinfo hints; - int disp; - int error; - - if(display_str == NULL) - display_str = ":0"; - strlcpy(d, display_str, sizeof(d)); - display_str = d; - colon = strchr (display_str, ':'); - if (colon == NULL) - disp = 0; - else { - *colon = '\0'; - disp = atoi (colon + 1); - } - if (strcmp (display_str, "") == 0 - || strncmp (display_str, "unix", 4) == 0 - || strncmp (display_str, "localhost", 9) == 0) { - gethostname (local_hostname, sizeof(local_hostname)); - display_str = local_hostname; - } - memset (&hints, 0, sizeof(hints)); - hints.ai_flags = AI_CANONNAME; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - - error = getaddrinfo (display_str, NULL, &hints, &ai); - if (error) - ai = NULL; - - for (; (ret = XauReadAuth (f)) != NULL; XauDisposeAuth(ret)) { - if (match_local_auth (ret, ai, display_str, disp) == 0) { - if (ai != NULL) - freeaddrinfo (ai); - return ret; - } - } - if (ai != NULL) - freeaddrinfo (ai); - return NULL; -} - -/* - * Get rid of the cookie that we were sent and get the correct one - * from our own cookie file instead. - */ - -int -replace_cookie(int xserver, int fd, char *filename, int cookiesp) /* XXX */ -{ - u_char beg[12]; - int bigendianp; - unsigned n, d, npad, dpad; - FILE *f; - u_char zeros[6] = {0, 0, 0, 0, 0, 0}; - - if (net_read (fd, beg, sizeof(beg)) != sizeof(beg)) - return 1; - if (net_write (xserver, beg, 6) != 6) - return 1; - bigendianp = beg[0] == 'B'; - if (bigendianp) { - n = (beg[6] << 8) | beg[7]; - d = (beg[8] << 8) | beg[9]; - } else { - n = (beg[7] << 8) | beg[6]; - d = (beg[9] << 8) | beg[8]; - } - if (n != 0 || d != 0) - return 1; - f = fopen(filename, "r"); - if (f != NULL) { - Xauth *auth = find_auth_cookie (f); - u_char len[6] = {0, 0, 0, 0, 0, 0}; - - fclose (f); - - if (auth != NULL) { - n = auth->name_length; - d = auth->data_length; - } else { - n = 0; - d = 0; - } - if (bigendianp) { - len[0] = n >> 8; - len[1] = n & 0xFF; - len[2] = d >> 8; - len[3] = d & 0xFF; - } else { - len[0] = n & 0xFF; - len[1] = n >> 8; - len[2] = d & 0xFF; - len[3] = d >> 8; - } - if (net_write (xserver, len, 6) != 6) { - XauDisposeAuth(auth); - return 1; - } - if(n != 0 && net_write (xserver, auth->name, n) != n) { - XauDisposeAuth(auth); - return 1; - } - npad = (4 - (n % 4)) % 4; - if (npad && net_write (xserver, zeros, npad) != npad) { - XauDisposeAuth(auth); - return 1; - } - if (d != 0 && net_write (xserver, auth->data, d) != d) { - XauDisposeAuth(auth); - return 1; - } - XauDisposeAuth(auth); - dpad = (4 - (d % 4)) % 4; - if (dpad && net_write (xserver, zeros, dpad) != dpad) - return 1; - } else { - if(net_write(xserver, zeros, 6) != 6) - return 1; - } - return 0; -} - -/* - * Some simple controls on the address and corresponding socket - */ - -int -suspicious_address (int sock, struct sockaddr *addr) -{ - char data[40]; - socklen_t len = sizeof(data); - - switch (addr->sa_family) { - case AF_INET: - return ((struct sockaddr_in *)addr)->sin_addr.s_addr != - htonl(INADDR_LOOPBACK) -#if defined(IP_OPTIONS) && defined(HAVE_GETSOCKOPT) - || getsockopt (sock, IPPROTO_IP, IP_OPTIONS, data, &len) < 0 - || len != 0 -#endif - ; - break; -#ifdef HAVE_IPV6 - case AF_INET6: - /* XXX check route headers */ - return !IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6*)addr)->sin6_addr); -#endif - default: - return 1; - } -} - -/* - * This really sucks, but these functions are used and if we're not - * linking against libkrb they don't exist. Using the heimdal storage - * functions will not work either cause we do not always link with - * libkrb5 either. - */ - -int -kx_get_int(void *f, uint32_t *to, int size, int lsb) -{ - int i; - unsigned char *from = (unsigned char *)f; - - *to = 0; - if(lsb){ - for(i = size-1; i >= 0; i--) - *to = (*to << 8) | from[i]; - }else{ - for(i = 0; i < size; i++) - *to = (*to << 8) | from[i]; - } - return size; -} - -int -kx_put_int(uint32_t from, void *to, size_t rem, int size) -{ - int i; - unsigned char *p = (unsigned char *)to; - - if (rem < size) - return -1; - - for(i = size - 1; i >= 0; i--){ - p[i] = from & 0xff; - from >>= 8; - } - return size; -} diff --git a/appl/kx/krb5.c b/appl/kx/krb5.c deleted file mode 100644 index ac72530f7..000000000 --- a/appl/kx/krb5.c +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright (c) 1995 - 2005 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "kx.h" - -RCSID("$Id$"); - -#ifdef KRB5 - -struct krb5_kx_context { - krb5_context context; - krb5_keyblock *keyblock; - krb5_crypto crypto; - krb5_principal client; - krb5_log_facility *log; - -}; - -typedef struct krb5_kx_context krb5_kx_context; - -#define K5DATA(kc) ((krb5_kx_context*)kc->data) -#define CONTEXT(kc) (K5DATA(kc)->context) - -/* - * Destroy the krb5 context in `c'. - */ - -static void -krb5_destroy (kx_context *kc) -{ - if (K5DATA(kc)->keyblock) - krb5_free_keyblock (CONTEXT(kc), K5DATA(kc)->keyblock); - if (K5DATA(kc)->crypto) - krb5_crypto_destroy (CONTEXT(kc), K5DATA(kc)->crypto); - if (K5DATA(kc)->client) - krb5_free_principal (CONTEXT(kc), K5DATA(kc)->client); - if (CONTEXT(kc)) - krb5_free_context (CONTEXT(kc)); - memset (kc->data, 0, sizeof(krb5_kx_context)); - free (kc->data); -} - -/* - * Read the authentication information from `s' and return 0 if - * succesful, else -1. - */ - -static int -krb5_authenticate (kx_context *kc, int s) -{ - krb5_auth_context auth_context = NULL; - krb5_error_code ret; - krb5_principal server; - const char *host = kc->host; - - ret = krb5_sname_to_principal (CONTEXT(kc), - host, "host", KRB5_NT_SRV_HST, &server); - if (ret) { - krb5_warn (CONTEXT(kc), ret, "krb5_sname_to_principal: %s", host); - return 1; - } - - ret = krb5_sendauth (CONTEXT(kc), - &auth_context, - &s, - KX_VERSION, - NULL, - server, - AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); - if (ret) { - if(ret != KRB5_SENDAUTH_BADRESPONSE) - krb5_warn (CONTEXT(kc), ret, "krb5_sendauth: %s", host); - return 1; - } - - ret = krb5_auth_con_getkey (CONTEXT(kc), auth_context, - &K5DATA(kc)->keyblock); - if (ret) { - krb5_warn (CONTEXT(kc), ret, "krb5_auth_con_getkey: %s", host); - krb5_auth_con_free (CONTEXT(kc), auth_context); - return 1; - } - - ret = krb5_crypto_init (CONTEXT(kc), K5DATA(kc)->keyblock, - 0, &K5DATA(kc)->crypto); - if (ret) { - krb5_warn (CONTEXT(kc), ret, "krb5_crypto_init"); - krb5_auth_con_free (CONTEXT(kc), auth_context); - return 1; - } - return 0; -} - -/* - * Read an encapsulated krb5 packet from `fd' into `buf' (of size - * `len'). Return the number of bytes read or 0 on EOF or -1 on - * error. - */ - -static ssize_t -krb5_read (kx_context *kc, - int fd, void *buf, size_t len) -{ - size_t data_len, outer_len; - krb5_error_code ret; - unsigned char tmp[4]; - krb5_data data; - int l; - - l = krb5_net_read (CONTEXT(kc), &fd, tmp, 4); - if (l == 0) - return l; - if (l != 4) - return -1; - data_len = (tmp[0] << 24) | (tmp[1] << 16) | (tmp[2] << 8) | tmp[3]; - outer_len = krb5_get_wrapped_length (CONTEXT(kc), - K5DATA(kc)->crypto, data_len); - if (outer_len > len) - return -1; - if (krb5_net_read (CONTEXT(kc), &fd, buf, outer_len) != outer_len) - return -1; - - ret = krb5_decrypt (CONTEXT(kc), K5DATA(kc)->crypto, - KRB5_KU_OTHER_ENCRYPTED, - buf, outer_len, &data); - if (ret) { - krb5_warn (CONTEXT(kc), ret, "krb5_decrypt"); - return -1; - } - if (data_len > data.length) { - krb5_data_free (&data); - return -1; - } - memmove (buf, data.data, data_len); - krb5_data_free (&data); - return data_len; -} - -/* - * Write an encapsulated krb5 packet on `fd' with the data in `buf, - * len'. Return len or -1 on error. - */ - -static ssize_t -krb5_write(kx_context *kc, - int fd, const void *buf, size_t len) -{ - krb5_data data; - krb5_error_code ret; - unsigned char tmp[4]; - size_t outlen; - - ret = krb5_encrypt (CONTEXT(kc), K5DATA(kc)->crypto, - KRB5_KU_OTHER_ENCRYPTED, - buf, len, &data); - if (ret){ - krb5_warn (CONTEXT(kc), ret, "krb5_write"); - return -1; - } - - outlen = data.length; - tmp[0] = (len >> 24) & 0xFF; - tmp[1] = (len >> 16) & 0xFF; - tmp[2] = (len >> 8) & 0xFF; - tmp[3] = (len >> 0) & 0xFF; - - if (krb5_net_write (CONTEXT(kc), &fd, tmp, 4) != 4 || - krb5_net_write (CONTEXT(kc), &fd, data.data, outlen) != outlen) { - krb5_data_free (&data); - return -1; - } - krb5_data_free (&data); - return len; -} - -/* - * Copy from the unix socket `from_fd' encrypting to `to_fd'. - * Return 0, -1 or len. - */ - -static int -copy_out (kx_context *kc, int from_fd, int to_fd) -{ - char buf[32768]; - ssize_t len; - - len = read (from_fd, buf, sizeof(buf)); - if (len == 0) - return 0; - if (len < 0) { - krb5_warn (CONTEXT(kc), errno, "read"); - return len; - } - return krb5_write (kc, to_fd, buf, len); -} - -/* - * Copy from the socket `from_fd' decrypting to `to_fd'. - * Return 0, -1 or len. - */ - -static int -copy_in (kx_context *kc, int from_fd, int to_fd) -{ - char buf[33000]; /* XXX */ - - ssize_t len; - - len = krb5_read (kc, from_fd, buf, sizeof(buf)); - if (len == 0) - return 0; - if (len < 0) { - krb5_warn (CONTEXT(kc), errno, "krb5_read"); - return len; - } - - return krb5_net_write (CONTEXT(kc), &to_fd, buf, len); -} - -/* - * Copy data between `fd1' and `fd2', encrypting in one direction and - * decrypting in the other. - */ - -static int -krb5_copy_encrypted (kx_context *kc, int fd1, int fd2) -{ - for (;;) { - fd_set fdset; - int ret; - - if (fd1 >= FD_SETSIZE || fd2 >= FD_SETSIZE) { - krb5_warnx (CONTEXT(kc), "fd too large"); - return 1; - } - - FD_ZERO(&fdset); - FD_SET(fd1, &fdset); - FD_SET(fd2, &fdset); - - ret = select (max(fd1, fd2)+1, &fdset, NULL, NULL, NULL); - if (ret < 0 && errno != EINTR) { - krb5_warn (CONTEXT(kc), errno, "select"); - return 1; - } - if (FD_ISSET(fd1, &fdset)) { - ret = copy_out (kc, fd1, fd2); - if (ret <= 0) - return ret; - } - if (FD_ISSET(fd2, &fdset)) { - ret = copy_in (kc, fd2, fd1); - if (ret <= 0) - return ret; - } - } -} - -/* - * Return 0 if the user authenticated on `kc' is allowed to login as - * `user'. - */ - -static int -krb5_userok (kx_context *kc, char *user) -{ - krb5_error_code ret; - char *tmp; - - ret = krb5_unparse_name (CONTEXT(kc), K5DATA(kc)->client, &tmp); - if (ret) - krb5_err (CONTEXT(kc), 1, ret, "krb5_unparse_name"); - kc->user = tmp; - - return !krb5_kuserok (CONTEXT(kc), K5DATA(kc)->client, user); -} - -/* - * Create an instance of an krb5 context. - */ - -void -krb5_make_context (kx_context *kc) -{ - krb5_kx_context *c; - krb5_error_code ret; - - kc->authenticate = krb5_authenticate; - kc->userok = krb5_userok; - kc->read = krb5_read; - kc->write = krb5_write; - kc->copy_encrypted = krb5_copy_encrypted; - kc->destroy = krb5_destroy; - kc->user = NULL; - kc->data = malloc(sizeof(krb5_kx_context)); - - if (kc->data == NULL) { - syslog (LOG_ERR, "failed to malloc %lu bytes", - (unsigned long)sizeof(krb5_kx_context)); - exit(1); - } - memset (kc->data, 0, sizeof(krb5_kx_context)); - c = (krb5_kx_context *)kc->data; - ret = krb5_init_context (&c->context); - if (ret) { - syslog (LOG_ERR, "failed initialise krb5 context"); - exit(1); - } -} - -/* - * Receive authentication information on `sock' (first four bytes - * in `buf'). - */ - -int -recv_v5_auth (kx_context *kc, int sock, u_char *buf) -{ - uint32_t len; - krb5_error_code ret; - krb5_principal server; - krb5_auth_context auth_context = NULL; - krb5_ticket *ticket; - - if (memcmp (buf, "\x00\x00\x00\x13", 4) != 0) - return 1; - len = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3]); - if (net_read(sock, buf, len) != len) { - syslog (LOG_ERR, "read: %m"); - exit (1); - } - if (len != sizeof(KRB5_SENDAUTH_VERSION) - || memcmp (buf, KRB5_SENDAUTH_VERSION, len) != 0) { - syslog (LOG_ERR, "bad sendauth version: %.8s", buf); - exit (1); - } - - krb5_make_context (kc); - krb5_openlog(CONTEXT(kc), "kxd", &K5DATA(kc)->log); - krb5_set_warn_dest(CONTEXT(kc), K5DATA(kc)->log); - - ret = krb5_sock_to_principal (CONTEXT(kc), sock, "host", - KRB5_NT_SRV_HST, &server); - if (ret) { - syslog (LOG_ERR, "krb5_sock_to_principal: %s", - krb5_get_err_text (CONTEXT(kc), ret)); - exit (1); - } - - ret = krb5_recvauth (CONTEXT(kc), - &auth_context, - &sock, - KX_VERSION, - server, - KRB5_RECVAUTH_IGNORE_VERSION, - NULL, - &ticket); - krb5_free_principal (CONTEXT(kc), server); - if (ret) { - syslog (LOG_ERR, "krb5_sock_to_principal: %s", - krb5_get_err_text (CONTEXT(kc), ret)); - exit (1); - } - - ret = krb5_auth_con_getkey (CONTEXT(kc), auth_context, &K5DATA(kc)->keyblock); - if (ret) { - syslog (LOG_ERR, "krb5_auth_con_getkey: %s", - krb5_get_err_text (CONTEXT(kc), ret)); - exit (1); - } - - ret = krb5_crypto_init (CONTEXT(kc), K5DATA(kc)->keyblock, 0, &K5DATA(kc)->crypto); - if (ret) { - syslog (LOG_ERR, "krb5_crypto_init: %s", - krb5_get_err_text (CONTEXT(kc), ret)); - exit (1); - } - - K5DATA(kc)->client = ticket->client; - ticket->client = NULL; - krb5_free_ticket (CONTEXT(kc), ticket); - - krb5_auth_con_free(CONTEXT(kc), auth_context); - - return 0; -} - -#endif /* KRB5 */ diff --git a/appl/kx/kx.1 b/appl/kx/kx.1 deleted file mode 100644 index 14a117008..000000000 --- a/appl/kx/kx.1 +++ /dev/null @@ -1,93 +0,0 @@ -.\" Copyright (c) 1996 - 1997 Kungliga Tekniska Högskolan -.\" (Royal Institute of Technology, Stockholm, Sweden). -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" 3. Neither the name of the Institute nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" $Id$ -.\" -.Dd September 27, 1996 -.Dt KX 1 -.Os KTH-KRB -.Sh NAME -.Nm kx -.Nd -securely forward X conections -.Sh SYNOPSIS -.Ar kx -.Op Fl l Ar username -.Op Fl k -.Op Fl d -.Op Fl t -.Op Fl p Ar port -.Op Fl P -.Ar host -.Sh DESCRIPTION -The -.Nm -program forwards an X connection from a remote client to a local screen -through an authenticated and encrypted stream. Options supported by -.Nm kx : -.Bl -tag -width Ds -.It Fl l -Log in on the remote the host as user -.Ar username . -.It Fl k -Do not enable keep-alives on the TCP connections. -.It Fl d -Do not fork. This is mainly useful for debugging. -.It Fl t -Listen not only on a UNIX-domain socket but on a TCP socket as well. -.It Fl p -Use the port -.Ar port . -.It Fl P -Force passive mode. -.El -.Pp -This program is used by -.Nm rxtelnet -and -.Nm rxterm -and you should not need to run it directly. -.Pp -It connects to a -.Nm kxd -on the host -.Ar host -and then will relay the traffic from the remote X clients to the local -server. When started, it prints the display and Xauthority-file to be -used on host -.Ar host -and then goes to the background, waiting for connections from the -remote -.Nm kxd . -.Sh SEE ALSO -.Xr rxtelnet 1 , -.Xr rxterm 1 , -.Xr kxd 8 diff --git a/appl/kx/kx.c b/appl/kx/kx.c deleted file mode 100644 index 641683b00..000000000 --- a/appl/kx/kx.c +++ /dev/null @@ -1,711 +0,0 @@ -/* - * Copyright (c) 1995-2003 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "kx.h" - -RCSID("$Id$"); - -static int nchild; -static int donep; - -/* - * Signal handler that justs waits for the children when they die. - */ - -static RETSIGTYPE -childhandler (int sig) -{ - pid_t pid; - int status; - - do { - pid = waitpid (-1, &status, WNOHANG|WUNTRACED); - if (pid > 0 && (WIFEXITED(status) || WIFSIGNALED(status))) - if (--nchild == 0 && donep) - exit (0); - } while(pid > 0); - signal (SIGCHLD, childhandler); - SIGRETURN(0); -} - -/* - * Handler for SIGUSR1. - * This signal means that we should wait until there are no children - * left and then exit. - */ - -static RETSIGTYPE -usr1handler (int sig) -{ - donep = 1; - - SIGRETURN(0); -} - -/* - * Almost the same as for SIGUSR1, except we should exit immediately - * if there are no active children. - */ - -static RETSIGTYPE -usr2handler (int sig) -{ - donep = 1; - if (nchild == 0) - exit (0); - - SIGRETURN(0); -} - -/* - * Establish authenticated connection. Return socket or -1. - */ - -static int -connect_host (kx_context *kc) -{ - struct addrinfo *ai, *a; - struct addrinfo hints; - int error; - char portstr[NI_MAXSERV]; - socklen_t addrlen; - int s = -1; - struct sockaddr_storage thisaddr_ss; - struct sockaddr *thisaddr = (struct sockaddr *)&thisaddr_ss; - - memset (&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - - snprintf (portstr, sizeof(portstr), "%u", ntohs(kc->port)); - - error = getaddrinfo (kc->host, portstr, &hints, &ai); - if (error) { - warnx ("%s: %s", kc->host, gai_strerror(error)); - return -1; - } - - for (a = ai; a != NULL; a = a->ai_next) { - s = socket (a->ai_family, a->ai_socktype, a->ai_protocol); - if (s < 0) - continue; - if (connect (s, a->ai_addr, a->ai_addrlen) < 0) { - warn ("connect(%s)", kc->host); - close (s); - continue; - } - break; - } - - if (a == NULL) { - freeaddrinfo (ai); - return -1; - } - - addrlen = sizeof(thisaddr_ss); - if (getsockname (s, thisaddr, &addrlen) < 0 || - addrlen != a->ai_addrlen) - err(1, "getsockname(%s)", kc->host); - memcpy (&kc->__ss_this, thisaddr, sizeof(kc->__ss_this)); - kc->thisaddr_len = addrlen; - memcpy (&kc->__ss_that, a->ai_addr, sizeof(kc->__ss_that)); - kc->thataddr_len = a->ai_addrlen; - freeaddrinfo (ai); - if ((*kc->authenticate)(kc, s)) - return -1; - return s; -} - -/* - * Get rid of the cookie that we were sent and get the correct one - * from our own cookie file instead and then just copy data in both - * directions. - */ - -static int -passive_session (int xserver, int fd, kx_context *kc) -{ - if (replace_cookie (xserver, fd, XauFileName(), 1)) - return 1; - else - return copy_encrypted (kc, xserver, fd); -} - -static int -active_session (int xserver, int fd, kx_context *kc) -{ - if (verify_and_remove_cookies (xserver, fd, 1)) - return 1; - else - return copy_encrypted (kc, xserver, fd); -} - -/* - * fork (unless debugp) and print the output that will be used by the - * script to capture the display, xauth cookie and pid. - */ - -static void -status_output (int debugp) -{ - if(debugp) - printf ("%u\t%s\t%s\n", (unsigned)getpid(), display, xauthfile); - else { - pid_t pid; - - pid = fork(); - if (pid < 0) { - err(1, "fork"); - } else if (pid > 0) { - printf ("%u\t%s\t%s\n", (unsigned)pid, display, xauthfile); - exit (0); - } else { - fclose(stdout); - } - } -} - -/* - * Obtain an authenticated connection on `kc'. Send a kx message - * saying we are `kc->user' and want to use passive mode. Wait for - * answer on that connection and fork of a child for every new - * connection we have to make. - */ - -static int -doit_passive (kx_context *kc) -{ - int otherside; - u_char msg[1024], *p; - int len; - uint32_t tmp; - const char *host = kc->host; - - otherside = connect_host (kc); - - if (otherside < 0) - return 1; -#if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT) - if (kc->keepalive_flag) { - int one = 1; - - setsockopt (otherside, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, - sizeof(one)); - } -#endif - - p = msg; - *p++ = INIT; - len = strlen(kc->user); - p += kx_put_int (len, p, sizeof(msg) - 1, 4); - memcpy(p, kc->user, len); - p += len; - *p++ = PASSIVE | (kc->keepalive_flag ? KEEP_ALIVE : 0); - if (kx_write (kc, otherside, msg, p - msg) != p - msg) - err (1, "write to %s", host); - len = kx_read (kc, otherside, msg, sizeof(msg)); - if (len <= 0) - errx (1, - "error reading initial message from %s: " - "this probably means it's using an old version.", - host); - p = (u_char *)msg; - if (*p == ERROR) { - p++; - p += kx_get_int (p, &tmp, 4, 0); - errx (1, "%s: %.*s", host, (int)tmp, p); - } else if (*p != ACK) { - errx (1, "%s: strange msg %d", host, *p); - } else - p++; - p += kx_get_int (p, &tmp, 4, 0); - memcpy(display, p, tmp); - display[tmp] = '\0'; - p += tmp; - - p += kx_get_int (p, &tmp, 4, 0); - memcpy(xauthfile, p, tmp); - xauthfile[tmp] = '\0'; - p += tmp; - - status_output (kc->debug_flag); - for (;;) { - pid_t child; - - len = kx_read (kc, otherside, msg, sizeof(msg)); - if (len < 0) - err (1, "read from %s", host); - else if (len == 0) - return 0; - - p = (u_char *)msg; - if (*p == ERROR) { - p++; - p += kx_get_int (p, &tmp, 4, 0); - errx (1, "%s: %.*s", host, (int)tmp, p); - } else if(*p != NEW_CONN) { - errx (1, "%s: strange msg %d", host, *p); - } else { - p++; - p += kx_get_int (p, &tmp, 4, 0); - } - - ++nchild; - child = fork (); - if (child < 0) { - warn("fork"); - continue; - } else if (child == 0) { - int fd; - int xserver; - - close (otherside); - - socket_set_port(kc->thataddr, htons(tmp)); - - fd = socket (kc->thataddr->sa_family, SOCK_STREAM, 0); - if (fd < 0) - err(1, "socket"); -#if defined(TCP_NODELAY) && defined(HAVE_SETSOCKOPT) - { - int one = 1; - - setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (void *)&one, - sizeof(one)); - } -#endif -#if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT) - if (kc->keepalive_flag) { - int one = 1; - - setsockopt (fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, - sizeof(one)); - } -#endif - - if (connect (fd, kc->thataddr, kc->thataddr_len) < 0) - err(1, "connect(%s)", host); - { - int d = 0; - char *s; - - s = getenv ("DISPLAY"); - if (s != NULL) { - s = strchr (s, ':'); - if (s != NULL) - d = atoi (s + 1); - } - - xserver = connect_local_xsocket (d); - if (xserver < 0) - return 1; - } - return passive_session (xserver, fd, kc); - } else { - } - } -} - -/* - * Allocate a local pseudo-xserver and wait for connections - */ - -static int -doit_active (kx_context *kc) -{ - int otherside; - int nsockets; - struct x_socket *sockets; - u_char msg[1024], *p; - int len; - int tmp, tmp2; - char *str; - int i; - size_t rem; - uint32_t other_port; - int error; - const char *host = kc->host; - - otherside = connect_host (kc); - if (otherside < 0) - return 1; -#if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT) - if (kc->keepalive_flag) { - int one = 1; - - setsockopt (otherside, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, - sizeof(one)); - } -#endif - p = msg; - rem = sizeof(msg); - *p++ = INIT; - --rem; - len = strlen(kc->user); - tmp = kx_put_int (len, p, rem, 4); - if (tmp < 0) - return 1; - p += tmp; - rem -= tmp; - memcpy(p, kc->user, len); - p += len; - rem -= len; - *p++ = (kc->keepalive_flag ? KEEP_ALIVE : 0); - --rem; - - str = getenv("DISPLAY"); - if (str == NULL || (str = strchr(str, ':')) == NULL) - str = ":0"; - len = strlen (str); - tmp = kx_put_int (len, p, rem, 4); - if (tmp < 0) - return 1; - rem -= tmp; - p += tmp; - memcpy (p, str, len); - p += len; - rem -= len; - - str = getenv("XAUTHORITY"); - if (str == NULL) - str = ""; - len = strlen (str); - tmp = kx_put_int (len, p, rem, 4); - if (tmp < 0) - return 1; - p += len; - rem -= len; - memcpy (p, str, len); - p += len; - rem -= len; - - if (kx_write (kc, otherside, msg, p - msg) != p - msg) - err (1, "write to %s", host); - - len = kx_read (kc, otherside, msg, sizeof(msg)); - if (len < 0) - err (1, "read from %s", host); - p = (u_char *)msg; - if (*p == ERROR) { - uint32_t u32; - - p++; - p += kx_get_int (p, &u32, 4, 0); - errx (1, "%s: %.*s", host, (int)u32, p); - } else if (*p != ACK) { - errx (1, "%s: strange msg %d", host, *p); - } - - tmp2 = get_xsockets (&nsockets, &sockets, kc->tcp_flag); - if (tmp2 < 0) - errx(1, "Failed to open sockets"); - display_num = tmp2; - if (kc->tcp_flag) - snprintf (display, display_size, "localhost:%u", display_num); - else - snprintf (display, display_size, ":%u", display_num); - error = create_and_write_cookie (xauthfile, xauthfile_size, - cookie, cookie_len); - if (error) - errx(1, "failed creating cookie file: %s", strerror(error)); - - status_output (kc->debug_flag); - for (;;) { - fd_set fdset; - pid_t child; - int fd, thisfd = -1; - socklen_t zero = 0; - - FD_ZERO(&fdset); - for (i = 0; i < nsockets; ++i) { - if (sockets[i].fd >= FD_SETSIZE) - errx (1, "fd too large"); - FD_SET(sockets[i].fd, &fdset); - } - if (select(FD_SETSIZE, &fdset, NULL, NULL, NULL) <= 0) - continue; - for (i = 0; i < nsockets; ++i) - if (FD_ISSET(sockets[i].fd, &fdset)) { - thisfd = sockets[i].fd; - break; - } - fd = accept (thisfd, NULL, &zero); - if (fd < 0) { - if (errno == EINTR) - continue; - else - err(1, "accept"); - } - - p = msg; - *p++ = NEW_CONN; - if (kx_write (kc, otherside, msg, p - msg) != p - msg) - err (1, "write to %s", host); - len = kx_read (kc, otherside, msg, sizeof(msg)); - if (len < 0) - err (1, "read from %s", host); - p = (u_char *)msg; - if (*p == ERROR) { - uint32_t val; - - p++; - p += kx_get_int (p, &val, 4, 0); - errx (1, "%s: %.*s", host, (int)val, p); - } else if (*p != NEW_CONN) { - errx (1, "%s: strange msg %d", host, *p); - } else { - p++; - p += kx_get_int (p, &other_port, 4, 0); - } - - ++nchild; - child = fork (); - if (child < 0) { - warn("fork"); - continue; - } else if (child == 0) { - int s; - - for (i = 0; i < nsockets; ++i) - close (sockets[i].fd); - - close (otherside); - - socket_set_port(kc->thataddr, htons(tmp)); - - s = socket (kc->thataddr->sa_family, SOCK_STREAM, 0); - if (s < 0) - err(1, "socket"); -#if defined(TCP_NODELAY) && defined(HAVE_SETSOCKOPT) - { - int one = 1; - - setsockopt (s, IPPROTO_TCP, TCP_NODELAY, (void *)&one, - sizeof(one)); - } -#endif -#if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT) - if (kc->keepalive_flag) { - int one = 1; - - setsockopt (s, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, - sizeof(one)); - } -#endif - - if (connect (s, kc->thataddr, kc->thataddr_len) < 0) - err(1, "connect"); - - return active_session (fd, s, kc); - } else { - close (fd); - } - } -} - -/* - * Should we interpret `disp' as this being a passive call? - */ - -static int -check_for_passive (const char *disp) -{ - char local_hostname[MaxHostNameLen]; - - gethostname (local_hostname, sizeof(local_hostname)); - - return disp != NULL && - (*disp == ':' - || strncmp(disp, "unix", 4) == 0 - || strncmp(disp, "localhost", 9) == 0 - || strncmp(disp, local_hostname, strlen(local_hostname)) == 0); -} - -/* - * Set up signal handlers and then call the functions. - */ - -static int -doit (kx_context *kc, int passive_flag) -{ - signal (SIGCHLD, childhandler); - signal (SIGUSR1, usr1handler); - signal (SIGUSR2, usr2handler); - if (passive_flag) - return doit_passive (kc); - else - return doit_active (kc); -} - -#ifdef KRB5 - -/* - * Start a v5-authenticatated kx connection. - */ - -static int -doit_v5 (const char *host, int port, const char *user, - int passive_flag, int debug_flag, int keepalive_flag, int tcp_flag) -{ - int ret; - kx_context context; - - krb5_make_context (&context); - context_set (&context, - host, user, port, debug_flag, keepalive_flag, tcp_flag); - - ret = doit (&context, passive_flag); - context_destroy (&context); - return ret; -} -#endif /* KRB5 */ - -/* - * Variables set from the arguments - */ - -#ifdef KRB5 -static int use_v5 = -1; -#endif -static char *port_str = NULL; -static const char *user = NULL; -static int tcp_flag = 0; -static int passive_flag = 0; -static int keepalive_flag = 1; -static int debug_flag = 0; -static int version_flag = 0; -static int help_flag = 0; - -struct getargs args[] = { -#ifdef KRB5 - { "krb5", '5', arg_flag, &use_v5, "Use Kerberos V5", - NULL }, -#endif - { "port", 'p', arg_string, &port_str, "Use this port", - "number-of-service" }, - { "user", 'l', arg_string, &user, "Run as this user", - NULL }, - { "tcp", 't', arg_flag, &tcp_flag, - "Use a TCP connection for X11" }, - { "passive", 'P', arg_flag, &passive_flag, - "Force a passive connection" }, - { "keepalive", 'k', arg_negative_flag, &keepalive_flag, - "disable keep-alives" }, - { "debug", 'd', arg_flag, &debug_flag, - "Enable debug information" }, - { "version", 0, arg_flag, &version_flag, "Print version", - NULL }, - { "help", 0, arg_flag, &help_flag, NULL, - NULL } -}; - -static void -usage(int ret) -{ - arg_printusage (args, - sizeof(args) / sizeof(args[0]), - NULL, - "host"); - exit (ret); -} - -/* - * kx - forward an x-connection over a kerberos-encrypted channel. - */ - -int -main(int argc, char **argv) -{ - int port = 0; - int optidx = 0; - int ret = 1; - char *host = NULL; - - setprogname (argv[0]); - - if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, - &optidx)) - usage (1); - - if (help_flag) - usage (0); - - if (version_flag) { - print_version (NULL); - return 0; - } - - if (optidx != argc - 1) - usage (1); - - host = argv[optidx]; - - if (port_str) { - struct servent *s = roken_getservbyname (port_str, "tcp"); - - if (s) - port = s->s_port; - else { - char *ptr; - - port = strtol (port_str, &ptr, 10); - if (port == 0 && ptr == port_str) - errx (1, "Bad port `%s'", port_str); - port = htons(port); - } - } - - if (user == NULL) { - user = get_default_username (); - if (user == NULL) - errx (1, "who are you?"); - } - - if (!passive_flag) - passive_flag = check_for_passive (getenv("DISPLAY")); - -#if defined(HAVE_KERNEL_ENABLE_DEBUG) - if (krb_debug_flag) - krb_enable_debug (); -#endif - -#ifdef KRB5 - if (ret && use_v5) { - if (port == 0) - port = krb5_getportbyname(NULL, "kx", "tcp", KX_PORT); - ret = doit_v5 (host, port, user, - passive_flag, debug_flag, keepalive_flag, tcp_flag); - } -#endif - return ret; -} diff --git a/appl/kx/kx.h b/appl/kx/kx.h deleted file mode 100644 index dbc5c08ee..000000000 --- a/appl/kx/kx.h +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* $Id$ */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#include -#include -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_PWD_H -#include -#endif -#ifdef HAVE_GRP_H -#include -#endif -#ifdef HAVE_SYSLOG_H -#include -#endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef TIME_WITH_SYS_TIME -#include -#include -#elif defined(HAVE_SYS_TIME_H) -#include -#else -#include -#endif -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif -#ifdef HAVE_SYS_SELECT_H -#include -#endif -#ifdef HAVE_SYS_WAIT_H -#include -#endif -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETINET_TCP_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_SYS_UN_H -#include -#endif -#include -#include -#include - -#ifdef HAVE_SYS_STREAM_H -#include -#endif -#ifdef HAVE_SYS_STROPTS_H -#include -#endif - -/* defined by aix's sys/stream.h and again by arpa/nameser.h */ - -#undef NOERROR - -/* as far as we know, this is only used with later versions of Slowlaris */ -#if SunOS >= 50 && defined(HAVE_SYS_STROPTS_H) && defined(HAVE_FATTACH) && defined(I_PUSH) -#define MAY_HAVE_X11_PIPES -#endif - -#ifdef SOCKS -#include -/* This doesn't belong here. */ -struct tm *localtime(const time_t *); -struct hostent *gethostbyname(const char *); -#endif - -#ifdef KRB5 -#include -#endif - -#include -#include -#include - -struct x_socket { - char *pathname; - int fd; - enum { - LISTENP = 0x80, - TCP = LISTENP | 1, - UNIX_SOCKET = LISTENP | 2, - STREAM_PIPE = 3 - } flags; -}; - -extern char x_socket[]; -extern uint32_t display_num; -extern char display[]; -extern int display_size; -extern char xauthfile[]; -extern int xauthfile_size; -extern u_char cookie[]; -extern size_t cookie_len; - -int get_xsockets (int *number, struct x_socket **sockets, int tcpp); -int chown_xsockets (int n, struct x_socket *sockets, uid_t uid, gid_t gid); - -int connect_local_xsocket (unsigned dnr); -int create_and_write_cookie (char *file, - size_t file_size, - u_char *cookie_buf, - size_t sz); -int verify_and_remove_cookies (int fd, int sock, int cookiesp); -int replace_cookie(int xserver, int fd, char *filename, int cookiesp); - -int suspicious_address (int sock, struct sockaddr *addr); - -#define KX_PORT 2111 - -#define KX_OLD_VERSION "KXSERV.1" -#define KX_VERSION "KXSERV.2" - -#define COOKIE_TYPE "MIT-MAGIC-COOKIE-1" - -enum { INIT = 0, ACK = 1, NEW_CONN = 2, ERROR = 3 }; - -enum kx_flags { PASSIVE = 1, KEEP_ALIVE = 2 }; - -typedef enum kx_flags kx_flags; - -struct kx_context { - int (*authenticate)(struct kx_context *kc, int s); - int (*userok)(struct kx_context *kc, char *user); - ssize_t (*read)(struct kx_context *kc, - int fd, void *buf, size_t len); - ssize_t (*write)(struct kx_context *kc, - int fd, const void *buf, size_t len); - int (*copy_encrypted)(struct kx_context *kc, - int fd1, int fd2); - void (*destroy)(struct kx_context *kc); - const char *host; - const char *user; - int port; - int debug_flag; - int keepalive_flag; - int tcp_flag; - struct sockaddr_storage __ss_this; - struct sockaddr_storage __ss_that; - struct sockaddr *thisaddr; - struct sockaddr *thataddr; - socklen_t thisaddr_len, thataddr_len; - void *data; -}; - -typedef struct kx_context kx_context; - -void -context_set (kx_context *kc, const char *host, const char *user, int port, - int debug_flag, int keepalive_flag, int tcp_flag); - -void -context_destroy (kx_context *kc); - -int -context_authenticate (kx_context *kc, int s); - -int -context_userok (kx_context *kc, char *user); - -ssize_t -kx_read (kx_context *kc, int fd, void *buf, size_t len); - -ssize_t -kx_write (kx_context *kc, int fd, const void *buf, size_t len); - -int -copy_encrypted (kx_context *kc, int fd1, int fd2); - -#ifdef KRB5 - -void -krb5_make_context (kx_context *c); - -int -recv_v5_auth (kx_context *kc, int sock, u_char *buf); - -#endif - -void -fatal (kx_context *kc, int fd, char *format, ...) -#ifdef __GNUC__ -__attribute__ ((format (printf, 3, 4))) -#endif -; - -int -kx_get_int(void *f, uint32_t *to, int size, int lsb); - -int -kx_put_int(uint32_t from, void *to, size_t rem, int size); diff --git a/appl/kx/kxd.8 b/appl/kx/kxd.8 deleted file mode 100644 index 871e79b4f..000000000 --- a/appl/kx/kxd.8 +++ /dev/null @@ -1,84 +0,0 @@ -.\" Copyright (c) 1996 - 1997, 2001 Kungliga Tekniska Högskolan -.\" (Royal Institute of Technology, Stockholm, Sweden). -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" 3. Neither the name of the Institute nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" $Id$ -.\" -.Dd September 27, 1996 -.Dt KXD 8 -.Os KTH-KRB -.Sh NAME -.Nm kxd -.Nd -securely forward X conections -.Sh SYNOPSIS -.Ar kxd -.Op Fl t -.Op Fl i -.Op Fl p Ar port -.Sh DESCRIPTION -This is the daemon for -.Nm kx . -.Pp -Options supported by -.Nm kxd : -.Bl -tag -width Ds -.It Fl t -TCP. Normally -.Nm kxd -will only listen for X connections on a UNIX socket, but some machines -(for example, Cray) have X libraries that are not able to use UNIX -sockets and thus you need to use TCP to talk to the pseudo-xserver -created by -.Nm kxd . -This option decreases the security significantly and should only be -used when it is necessary and you have considered the consequences of -doing so. -.It Fl i -Interactive. Do not expect to be started by -.Nm inetd , -but allocate and listen to the socket yourself. Handy for testing -and debugging. -.It Fl p -Port. Listen on the port -.Ar port . -Only usable with -.Fl i . -.El -.Sh EXAMPLES -Put the following in -.Pa /etc/inetd.conf : -.Bd -literal -kx stream tcp nowait root /usr/athena/libexec/kxd kxd -.Ed -.Sh SEE ALSO -.Xr kx 1 , -.Xr rxtelnet 1 , -.Xr rxterm 1 diff --git a/appl/kx/kxd.c b/appl/kx/kxd.c deleted file mode 100644 index 65bd1a18f..000000000 --- a/appl/kx/kxd.c +++ /dev/null @@ -1,779 +0,0 @@ -/* - * Copyright (c) 1995 - 2003 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "kx.h" - -RCSID("$Id$"); - -static pid_t wait_on_pid = -1; -static int done = 0; - -/* - * Signal handler that justs waits for the children when they die. - */ - -static RETSIGTYPE -childhandler (int sig) -{ - pid_t pid; - int status; - - do { - pid = waitpid (-1, &status, WNOHANG|WUNTRACED); - if (pid > 0 && pid == wait_on_pid) - done = 1; - } while(pid > 0); - signal (SIGCHLD, childhandler); - SIGRETURN(0); -} - -/* - * Print the error message `format' and `...' on fd and die. - */ - -void -fatal (kx_context *kc, int fd, char *format, ...) -{ - u_char msg[1024]; - u_char *p; - va_list args; - int len; - - va_start(args, format); - p = msg; - *p++ = ERROR; - vsnprintf ((char *)p + 4, sizeof(msg) - 5, format, args); - syslog (LOG_ERR, "%s", (char *)p + 4); - len = strlen ((char *)p + 4); - p += kx_put_int (len, p, 4, 4); - p += len; - kx_write (kc, fd, msg, p - msg); - va_end(args); - exit (1); -} - -/* - * Remove all sockets and cookie files. - */ - -static void -cleanup(int nsockets, struct x_socket *sockets) -{ - int i; - - if(xauthfile[0]) - unlink(xauthfile); - for (i = 0; i < nsockets; ++i) { - if (sockets[i].pathname != NULL) { - unlink (sockets[i].pathname); - free (sockets[i].pathname); - } - } - free(sockets); -} - -/* - * Prepare to receive a connection on `sock'. - */ - -static int -recv_conn (int sock, kx_context *kc, - int *dispnr, int *nsockets, struct x_socket **sockets, - int tcp_flag) -{ - u_char msg[1024], *p; - char user[256]; - socklen_t addrlen; - struct passwd *passwd; - char remotehost[MaxHostNameLen]; - char remoteaddr[INET6_ADDRSTRLEN]; - int ret = 1; - int flags; - int len; - uint32_t tmp32; - - memset(kc, 0, sizeof(*kc)); - *nsockets = 0; - *sockets = NULL; - *dispnr = 0; - - addrlen = sizeof(kc->__ss_this); - kc->thisaddr = (struct sockaddr*)&kc->__ss_this; - if (getsockname (sock, kc->thisaddr, &addrlen) < 0) { - syslog (LOG_ERR, "getsockname: %m"); - exit (1); - } - kc->thisaddr_len = addrlen; - addrlen = sizeof(kc->__ss_that); - kc->thataddr = (struct sockaddr*)&kc->__ss_that; - if (getpeername (sock, kc->thataddr, &addrlen) < 0) { - syslog (LOG_ERR, "getpeername: %m"); - exit (1); - } - kc->thataddr_len = addrlen; - - getnameinfo_verified (kc->thataddr, - kc->thataddr_len, - remotehost, sizeof(remotehost), - NULL, 0, 0); - - if (net_read (sock, msg, 4) != 4) { - syslog (LOG_ERR, "read: %m"); - exit (1); - } - -#ifdef KRB5 - if (ret && recv_v5_auth (kc, sock, msg) == 0) - ret = 0; -#endif - if (ret) { - syslog (LOG_ERR, "unrecognized auth protocol: %x %x %x %x", - msg[0], msg[1], msg[2], msg[3]); - exit (1); - } - - len = kx_read (kc, sock, msg, sizeof(msg)); - if (len < 0) { - syslog (LOG_ERR, "kx_read failed"); - exit (1); - } - p = (u_char *)msg; - if (*p != INIT) - fatal(kc, sock, "Bad message"); - p++; - if ((p - msg) < sizeof(msg)) - fatal(kc, sock, "user"); - - p += kx_get_int (p, &tmp32, 4, 0); - if (tmp32 >= sizeof(user) - 1) - fatal(kc, sock, "user name too long"); - if ((p - msg) + tmp32 >= sizeof(msg)) - fatal(kc, sock, "user too long"); - memcpy (user, p, tmp32); - p += tmp32; - user[tmp32] = '\0'; - - passwd = k_getpwnam (user); - if (passwd == NULL) - fatal (kc, sock, "cannot find uid for %s", user); - - if (context_userok (kc, user) != 0) - fatal (kc, sock, "%s not allowed to login as %s", - kc->user, user); - - if ((p - msg) >= sizeof(msg)) - fatal(kc, sock, "user too long"); - - flags = *p++; - - if (flags & PASSIVE) { - pid_t pid; - int tmp; - - tmp = get_xsockets (nsockets, sockets, tcp_flag); - if (tmp < 0) { - fatal (kc, sock, "Cannot create X socket(s): %s", - strerror(errno)); - } - *dispnr = tmp; - - if (chown_xsockets (*nsockets, *sockets, - passwd->pw_uid, passwd->pw_gid)) { - cleanup (*nsockets, *sockets); - fatal (kc, sock, "Cannot chown sockets: %s", - strerror(errno)); - } - - pid = fork(); - if (pid == -1) { - cleanup (*nsockets, *sockets); - fatal (kc, sock, "fork: %s", strerror(errno)); - } else if (pid != 0) { - wait_on_pid = pid; - while (!done) - pause (); - cleanup (*nsockets, *sockets); - exit (0); - } - } - - if (setgid (passwd->pw_gid) || - initgroups(passwd->pw_name, passwd->pw_gid) || -#ifdef HAVE_GETUDBNAM /* XXX this happens on crays */ - setjob(passwd->pw_uid, 0) == -1 || -#endif - setuid(passwd->pw_uid)) { - syslog(LOG_ERR, "setting uid/groups: %m"); - fatal (kc, sock, "cannot set uid"); - } - - ret = getnameinfo(kc->thataddr, kc->thataddr_len, - remoteaddr, sizeof(remoteaddr), - NULL, 0, NI_NUMERICHOST); - if (ret != 0) - fatal (kc, sock, "getnameinfo failed: %s", gai_strerror(ret)); - - syslog (LOG_INFO, "from %s(%s): %s -> %s", - remotehost, remoteaddr, - kc->user, user); - umask(077); - if (!(flags & PASSIVE)) { - p += kx_get_int (p, &tmp32, 4, 0); - if (tmp32 > display_size) - fatal(kc, sock, "display too large"); - if ((p - msg) + tmp32 + 8 >= sizeof(msg)) - fatal(kc, sock, "user too long"); - memcpy (display, p, tmp32); - display[tmp32] = '\0'; - p += tmp32; - p += kx_get_int (p, &tmp32, 4, 0); - len = min(tmp32, xauthfile_size); - memcpy (xauthfile, p, len); - xauthfile[len] = '\0'; - } -#if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT) - if (flags & KEEP_ALIVE) { - int one = 1; - - setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, - sizeof(one)); - } -#endif - return flags; -} - -/* - * - */ - -static int -passive_session (kx_context *kc, int fd, int sock, int cookiesp) -{ - if (verify_and_remove_cookies (fd, sock, cookiesp)) - return 1; - else - return copy_encrypted (kc, fd, sock); -} - -/* - * - */ - -static int -active_session (kx_context *kc, int fd, int sock, int cookiesp) -{ - fd = connect_local_xsocket(0); - - if (replace_cookie (fd, sock, xauthfile, cookiesp)) - return 1; - else - return copy_encrypted (kc, fd, sock); -} - -/* - * Handle a new connection. - */ - -static int -doit_conn (kx_context *kc, - int fd, int meta_sock, int flags, int cookiesp) -{ - int sock, sock2, port; - struct sockaddr_storage __ss_addr; - struct sockaddr *addr = (struct sockaddr*)&__ss_addr; - struct sockaddr_storage __ss_thisaddr; - struct sockaddr *thisaddr = (struct sockaddr*)&__ss_thisaddr; - socklen_t addrlen; - u_char msg[1024], *p; - - sock = socket (kc->thisaddr->sa_family, SOCK_STREAM, 0); - if (sock < 0) { - syslog (LOG_ERR, "socket: %m"); - return 1; - } -#if defined(TCP_NODELAY) && defined(HAVE_SETSOCKOPT) - { - int one = 1; - setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, (void *)&one, sizeof(one)); - } -#endif -#if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT) - if (flags & KEEP_ALIVE) { - int one = 1; - - setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, - sizeof(one)); - } -#endif - memset (&__ss_addr, 0, sizeof(__ss_addr)); - addr->sa_family = kc->thisaddr->sa_family; - if (kc->thisaddr_len > sizeof(__ss_addr)) { - syslog(LOG_ERR, "error in af"); - return 1; - } - if (bind (sock, addr, kc->thisaddr_len) < 0) { - syslog (LOG_ERR, "bind: %m"); - return 1; - } - addrlen = sizeof(__ss_addr); - if (getsockname (sock, addr, &addrlen) < 0) { - syslog (LOG_ERR, "getsockname: %m"); - return 1; - } - if (listen (sock, SOMAXCONN) < 0) { - syslog (LOG_ERR, "listen: %m"); - return 1; - } - port = socket_get_port(addr); - - p = msg; - *p++ = NEW_CONN; - p += kx_put_int (ntohs(port), p, 4, 4); - - if (kx_write (kc, meta_sock, msg, p - msg) < 0) { - syslog (LOG_ERR, "write: %m"); - return 1; - } - - addrlen = sizeof(__ss_thisaddr); - sock2 = accept (sock, thisaddr, &addrlen); - if (sock2 < 0) { - syslog (LOG_ERR, "accept: %m"); - return 1; - } - close (sock); - close (meta_sock); - - if (flags & PASSIVE) - return passive_session (kc, fd, sock2, cookiesp); - else - return active_session (kc, fd, sock2, cookiesp); -} - -/* - * Is the current user the owner of the console? - */ - -static void -check_user_console (kx_context *kc, int fd) -{ - struct stat sb; - - if (stat ("/dev/console", &sb) < 0) - fatal (kc, fd, "Cannot stat /dev/console: %s", strerror(errno)); - if (getuid() != sb.st_uid) - fatal (kc, fd, "Permission denied"); -} - -/* close down the new connection with a reasonable error message */ -static void -close_connection(int fd, const char *message) -{ - char buf[264]; /* max message */ - char *p; - int lsb = 0; - size_t mlen; - - mlen = strlen(message); - if(mlen > 255) - mlen = 255; - - /* read first part of connection packet, to get byte order */ - if(read(fd, buf, 6) != 6) { - close(fd); - return; - } - if(buf[0] == 0x6c) - lsb++; - p = buf; - *p++ = 0; /* failed */ - *p++ = mlen; /* length of message */ - p += 4; /* skip protocol version */ - p += 2; /* skip additional length */ - memcpy(p, message, mlen); /* copy message */ - p += mlen; - while((p - buf) % 4) /* pad to multiple of 4 bytes */ - *p++ = 0; - - /* now fill in length of additional data */ - if(lsb) { - buf[6] = (p - buf - 8) / 4; - buf[7] = 0; - }else{ - buf[6] = 0; - buf[7] = (p - buf - 8) / 4; - } - write(fd, buf, p - buf); - close(fd); -} - - -/* - * Handle a passive session on `sock' - */ - -static int -doit_passive (kx_context *kc, - int sock, - int flags, - int dispnr, - int nsockets, - struct x_socket *sockets, - int tcp_flag) -{ - int tmp; - int len; - size_t rem; - u_char msg[1024], *p; - int error; - - display_num = dispnr; - if (tcp_flag) - snprintf (display, display_size, "localhost:%u", display_num); - else - snprintf (display, display_size, ":%u", display_num); - error = create_and_write_cookie (xauthfile, xauthfile_size, - cookie, cookie_len); - if (error) { - cleanup(nsockets, sockets); - fatal (kc, sock, "Cookie-creation failed: %s", strerror(error)); - return 1; - } - - p = msg; - rem = sizeof(msg); - *p++ = ACK; - --rem; - - len = strlen (display); - tmp = kx_put_int (len, p, rem, 4); - if (tmp < 0 || rem < len + 4) { - syslog (LOG_ERR, "doit: buffer too small"); - cleanup(nsockets, sockets); - return 1; - } - p += tmp; - rem -= tmp; - - memcpy (p, display, len); - p += len; - rem -= len; - - len = strlen (xauthfile); - tmp = kx_put_int (len, p, rem, 4); - if (tmp < 0 || rem < len + 4) { - syslog (LOG_ERR, "doit: buffer too small"); - cleanup(nsockets, sockets); - return 1; - } - p += tmp; - rem -= tmp; - - memcpy (p, xauthfile, len); - p += len; - rem -= len; - - if(kx_write (kc, sock, msg, p - msg) < 0) { - syslog (LOG_ERR, "write: %m"); - cleanup(nsockets, sockets); - return 1; - } - for (;;) { - pid_t child; - int fd = -1; - fd_set fds; - int i; - int ret; - int cookiesp = TRUE; - - FD_ZERO(&fds); - if (sock >= FD_SETSIZE) { - syslog (LOG_ERR, "fd too large"); - cleanup(nsockets, sockets); - return 1; - } - - FD_SET(sock, &fds); - for (i = 0; i < nsockets; ++i) { - if (sockets[i].fd >= FD_SETSIZE) { - syslog (LOG_ERR, "fd too large"); - cleanup(nsockets, sockets); - return 1; - } - FD_SET(sockets[i].fd, &fds); - } - ret = select(FD_SETSIZE, &fds, NULL, NULL, NULL); - if(ret <= 0) - continue; - if(FD_ISSET(sock, &fds)){ - /* there are no processes left on the remote side - */ - cleanup(nsockets, sockets); - exit(0); - } else if(ret) { - for (i = 0; i < nsockets; ++i) { - if (FD_ISSET(sockets[i].fd, &fds)) { - if (sockets[i].flags == TCP) { - struct sockaddr_storage __ss_peer; - struct sockaddr *peer = (struct sockaddr*)&__ss_peer; - socklen_t slen = sizeof(__ss_peer); - - fd = accept (sockets[i].fd, - peer, - &slen); - if (fd < 0 && errno != EINTR) - syslog (LOG_ERR, "accept: %m"); - - /* XXX */ - if (fd >= 0 && suspicious_address (fd, peer)) { - close (fd); - fd = -1; - errno = EINTR; - } - } else if(sockets[i].flags == UNIX_SOCKET) { - socklen_t zero = 0; - - fd = accept (sockets[i].fd, NULL, &zero); - - if (fd < 0 && errno != EINTR) - syslog (LOG_ERR, "accept: %m"); -#ifdef MAY_HAVE_X11_PIPES - } else if(sockets[i].flags == STREAM_PIPE) { - /* - * this code tries to handle the - * send fd-over-pipe stuff for - * solaris - */ - - struct strrecvfd strrecvfd; - - ret = ioctl (sockets[i].fd, - I_RECVFD, &strrecvfd); - if (ret < 0 && errno != EINTR) { - syslog (LOG_ERR, "ioctl I_RECVFD: %m"); - } - - /* XXX */ - if (ret == 0) { - if (strrecvfd.uid != getuid()) { - close (strrecvfd.fd); - fd = -1; - errno = EINTR; - } else { - fd = strrecvfd.fd; - cookiesp = FALSE; - } - } -#endif /* MAY_HAVE_X11_PIPES */ - } else - abort (); - break; - } - } - } - if (fd < 0) { - if (errno == EINTR) - continue; - else - return 1; - } - - child = fork (); - if (child < 0) { - syslog (LOG_ERR, "fork: %m"); - if(errno != EAGAIN) - return 1; - close_connection(fd, strerror(errno)); - } else if (child == 0) { - for (i = 0; i < nsockets; ++i) - close (sockets[i].fd); - return doit_conn (kc, fd, sock, flags, cookiesp); - } else { - close (fd); - } - } -} - -/* - * Handle an active session on `sock' - */ - -static int -doit_active (kx_context *kc, - int sock, - int flags, - int tcp_flag) -{ - u_char msg[1024], *p; - - check_user_console (kc, sock); - - p = msg; - *p++ = ACK; - - if(kx_write (kc, sock, msg, p - msg) < 0) { - syslog (LOG_ERR, "write: %m"); - return 1; - } - for (;;) { - pid_t child; - int len; - - len = kx_read (kc, sock, msg, sizeof(msg)); - if (len < 0) { - syslog (LOG_ERR, "read: %m"); - return 1; - } - p = (u_char *)msg; - if (*p != NEW_CONN) { - syslog (LOG_ERR, "bad_message: %d", *p); - return 1; - } - - child = fork (); - if (child < 0) { - syslog (LOG_ERR, "fork: %m"); - if (errno != EAGAIN) - return 1; - } else if (child == 0) { - return doit_conn (kc, sock, sock, flags, 1); - } else { - } - } -} - -/* - * Receive a connection on `sock' and process it. - */ - -static int -doit(int sock, int tcp_flag) -{ - int ret; - kx_context context; - int dispnr; - int nsockets; - struct x_socket *sockets; - int flags; - - flags = recv_conn (sock, &context, &dispnr, &nsockets, &sockets, tcp_flag); - - if (flags & PASSIVE) { - ret = doit_passive (&context, sock, flags, dispnr, - nsockets, sockets, tcp_flag); - } else { - ret = doit_active (&context, sock, flags, tcp_flag); - cleanup(nsockets, sockets); - } - context_destroy (&context); - return ret; -} - -static char *port_str = NULL; -static int inetd_flag = 1; -static int tcp_flag = 0; -static int version_flag = 0; -static int help_flag = 0; - -struct getargs args[] = { - { "inetd", 'i', arg_negative_flag, &inetd_flag, - "Not started from inetd" }, - { "tcp", 't', arg_flag, &tcp_flag, "Use TCP" }, - { "port", 'p', arg_string, &port_str, "Use this port", - "port" }, - { "version", 0, arg_flag, &version_flag }, - { "help", 0, arg_flag, &help_flag } -}; - -static void -usage(int ret) -{ - arg_printusage (args, - sizeof(args) / sizeof(args[0]), - NULL, - "host"); - exit (ret); -} - -/* - * kxd - receive a forwarded X conncection - */ - -int -main (int argc, char **argv) -{ - int port; - int optidx = 0; - - setprogname (argv[0]); - roken_openlog ("kxd", LOG_ODELAY | LOG_PID, LOG_DAEMON); - - if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, - &optidx)) - usage (1); - - if (help_flag) - usage (0); - - if (version_flag) { - print_version (NULL); - return 0; - } - - if(port_str) { - struct servent *s = roken_getservbyname (port_str, "tcp"); - - if (s) - port = s->s_port; - else { - char *ptr; - - port = strtol (port_str, &ptr, 10); - if (port == 0 && ptr == port_str) - errx (1, "bad port `%s'", port_str); - port = htons(port); - } - } else { -#if defined(KRB5) - port = krb5_getportbyname(NULL, "kx", "tcp", KX_PORT); -#else -#error define KRB5 -#endif - } - - if (!inetd_flag) - mini_inetd (port); - - signal (SIGCHLD, childhandler); - return doit(STDIN_FILENO, tcp_flag); -} diff --git a/appl/kx/rxtelnet.1 b/appl/kx/rxtelnet.1 deleted file mode 100644 index 3759abf4e..000000000 --- a/appl/kx/rxtelnet.1 +++ /dev/null @@ -1,129 +0,0 @@ -.\" Copyright (c) 1996 - 1998, 2001 - 2002 Kungliga Tekniska Högskolan -.\" (Royal Institute of Technology, Stockholm, Sweden). -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" 3. Neither the name of the Institute nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" $Id$ -.\" -.Dd March 7, 2004 -.Dt RXTELNET 1 -.Os KTH_KRB -.Sh NAME -.Nm rxtelnet -.Nd -start a telnet and forward X-connections. -.Sh SYNOPSIS -.Nm rxtelnet -.Op Fl l Ar username -.Op Fl k -.Op Fl t Ar telnet_args -.Op Fl x Ar xterm_args -.Op Fl K Ar kx_args -.Op Fl w Ar term_emulator -.Op Fl b Ar telnet_program -.Op Fl n -.Op Fl v -.Ar host -.Op Ar port -.Sh DESCRIPTION -The -.Nm -program starts an -.Nm xterm -window with a telnet to host -.Ar host . -From this window you will also be able to run X clients that will be -able to connect securely to your X server. If -.Ar port -is given, that port will be used instead of the default. -.Pp -If setting up the X forwarding failes, -.Nm -will still telnet in to the remote host, but without X forwarding. -.Pp -The supported options are: -.Bl -tag -width Ds -.It Fl l -Log in on the remote host as user -.Ar username . -.It Fl k -Disables keep-alives. -.It Fl t -Send -.Ar telnet_args -as arguments to -.Nm telnet . -.It Fl x -Send -.Ar xterm_args -as arguments to -.Nm xterm . -.It Fl X -Send -.Ar kx_args -as arguments to -.Nm kx . -.It Fl w -Use -.Ar term_emulator -instead of xterm. -.It Fl b -Use -.Ar telnet_program -instead of telnet. -.It Fl n -Do not start any terminal emulator. -.It Fl v -Be verbose. -.El -.Sh EXAMPLE -To login from host -.Va foo -(where your display is) -to host -.Va bar , -you might do the following. -.Bl -enum -.It -On foo: -.Nm -.Va bar -.It -You will get a new window with a -.Nm telnet -to -.Va bar . -In this window you will be able to start X clients. -.El -.Sh SEE ALSO -.Xr kx 1 , -.Xr rxterm 1 , -.Xr telnet 1 , -.Xr tenletxr 1 , -.Xr kxd 8 diff --git a/appl/kx/rxtelnet.in b/appl/kx/rxtelnet.in deleted file mode 100644 index d5cf010f2..000000000 --- a/appl/kx/rxtelnet.in +++ /dev/null @@ -1,72 +0,0 @@ -#!/bin/sh -# $Id$ -# -usage="Usage: $0 [-l username] [-k] [-fF] [-t args_to_telnet] [-x args_to_xterm] [-K args_to_kx] [-w term_emulator] [-b telnet_binary] [-n] [-v] [-h | --help] [--version] host [port]" -binary=telnet -term= -kx_args=-P -while true -do - case $1 in - -l) telnet_args="${telnet_args} -l $2 "; kx_args="${kx_args} -l $2"; title="${2}@"; shift 2;; - -t) telnet_args="${telnet_args} $2 "; shift 2;; - -x) xterm_args="${xterm_args} $2 "; shift 2;; - -f) telnet_args="${telnet_args} -f"; shift;; - -F) telnet_args="${telnet_args} -F"; shift;; - -k) kx_args="${kx_args} -k"; shift;; - -K) kx_args="${kx_args} $2 "; shift 2;; - -n) term=none; shift;; - -w) term=$2; shift 2;; - -b) binary=$2; shift 2;; - --version) echo "$0: %PACKAGE% %VERSION%"; exit 0;; - -h) echo $usage; exit 0;; - --help) echo $usage; exit 0;; - -v) set -x; verb=1; shift;; - -*) echo "$0: Bad option $1"; echo $usage; exit 1;; - *) break;; - esac -done -if test $# -lt 1; then - echo $usage - exit 1 -fi -host=$1 -port=$2 -title="${title}${host}" -bindir=%bindir% -pdc_trams=`dirname $0` -PATH=$pdc_trams:$bindir:$PATH -export PATH -set -- `kx $kx_args $host` -if test $# -ne 3; then - echo "Warning: Cound not setup X forwarding" - pid=NO - disp="" - auth="" -else - screen=`echo $DISPLAY | sed -ne 's/[^:]*:[0-9]*\(\.[0-9]*\)/\1/p'` - pid=$1 - disp=${2}${screen} - auth=$3 -fi -oldifs=$IFS -IFS=: -set -- $PATH -IFS=$oldifs -if test -z "$term"; then - for j in xterm dtterm aixterm dxterm hpterm; do - for i in $*; do - test -n "$i" || i="." - if test -x $i/$j; then - term=$j; break 2 - fi - done - done -fi -test "$verb" && echo "Telnet command used is `type $binary`." -if test -n "$term" -a "$term" != "none"; then - ($term -title $title -n $title $xterm_args -e env DISPLAY=$disp XAUTHORITY=$auth $binary -D $telnet_args $host $port; test x"$pid" != xNO && kill -USR2 $pid) & -else - env DISPLAY=$disp XAUTHORITY=$auth $binary -D $telnet_args $host $port - test x"$pid" != xNO && kill -USR2 $pid -fi diff --git a/appl/kx/rxterm.1 b/appl/kx/rxterm.1 deleted file mode 100644 index f8f62ffd3..000000000 --- a/appl/kx/rxterm.1 +++ /dev/null @@ -1,121 +0,0 @@ -.\" Copyright (c) 1996 - 1997, 2001 - 2003 Kungliga Tekniska Högskolan -.\" (Royal Institute of Technology, Stockholm, Sweden). -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" 3. Neither the name of the Institute nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" $Id$ -.\" -.Dd April 11, 2003 -.Dt RXTERM 1 -.Os KTH_KRB -.Sh NAME -.Nm rxterm -.Nd -start a secure remote xterm -.Sh SYNOPSIS -.Nm rxterm -.Op Fl l Ar username -.Op Fl k -.Op Fl r Ar rsh_args -.Op Fl x Ar xterm_args -.Op Fl K Ar kx_args -.Op Fl w Ar term_emulator -.Op Fl b Ar rsh_program -.Ar host -.Op Ar port -.Sh DESCRIPTION -The -.Nm -program starts an -.Nm xterm -window on host -.Ar host . -From this window you will also be able to run X clients that will be -able to connect securely to your X server. If -.Ar port -is given, that port will be used instead of the default. -.Pp -The supported options are: -.Bl -tag -width Ds -.It Fl l -Log in on the remote host as user -.Ar username . -.It Fl k -Disable keep-alives. -.It Fl r -Send -.Ar rsh_args -as arguments to -.Nm rsh . -.It Fl x -Send -.Ar xterm_args -as arguments to -.Nm xterm . -.It Fl X -Send -.Ar kx_args -as arguments to -.Nm kx . -.It Fl w -Use -.Ar term_emulator -instead of xterm. -.It Fl b -Use -.Ar rsh_program -instead of rsh. -.It Fl v -Be verbose. -.El -.Sh EXAMPLE -To login from host -.Va foo -(where your display is) -to host -.Va bar , -you might do the following. -.Bl -enum -.It -On foo: -.Nm -.Va bar -.It -You will get a new window running an -.Nm xterm -on host -.Va bar . -In this window you will be able to start X clients. -.El -.Sh SEE ALSO -.Xr kx 1 , -.Xr rsh 1 , -.Xr rxtelnet 1 , -.Xr tenletxr 1 , -.Xr kxd 8 diff --git a/appl/kx/rxterm.in b/appl/kx/rxterm.in deleted file mode 100644 index d0a409031..000000000 --- a/appl/kx/rxterm.in +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh -# $Id$ -# -usage="Usage: $0 [-l username] [-k] [-f] [-r rsh_args] [-x xterm_args] [-K kx_args] [-w term_emulator] [-b rsh_binary][-v] [-h | --help] [--version] host" -binary=rsh -term=xterm -while true -do - case $1 in - -l) rsh_args="${rsh_args} -l $2 "; kx_args="${kx_args} -l $2"; title="${2}@"; shift 2;; - -r) rsh_args="${rsh_args} $2 "; shift 2;; - -x) xterm_args="${xterm_args} $2 "; shift 2;; - -f) rsh_args="${rsh_args} -f"; shift;; - -k) kx_args="${kx_args} -k"; shift;; - -K) kx_args="${kx_args} $2 "; shift 2;; - -w) term=$2; shift 2;; - -b) binary=$2; shift 2;; - --version) echo "$0: %PACKAGE% %VERSION%"; exit 0;; - -h) echo $usage; exit 0;; - --help) echo $usage; exit 0;; - -v) set -x; shift;; - -*) echo "$0: Bad option $1"; echo $usage; exit 1;; - *) break;; - esac -done -if test $# -lt 1; then - echo "Usage: $0 host [arguments to $term]" - exit 1 -fi -host=$1 -title="${title}${host}" -bindir=%bindir% -pdc_trams=`dirname $0` -PATH=$pdc_trams:$bindir:$PATH -export PATH -set -- `kx $kx_args $host` -if test $# -ne 3; then - exit 1 -fi -screen=`echo $DISPLAY | sed -ne 's/[^:]*:[0-9]*\(\.[0-9]*\)/\1/p'` -pid=$1 -disp=${2}${screen} -auth=$3 -kill -USR1 $pid -$binary -n $rsh_args $host "/bin/sh -c 'DISPLAY=$disp XAUTHORITY=$auth $term -T $title -n $title $xterm_args /dev/null 2>/dev/null &'" diff --git a/appl/kx/tenletxr.1 b/appl/kx/tenletxr.1 deleted file mode 100644 index 27d7e2e2f..000000000 --- a/appl/kx/tenletxr.1 +++ /dev/null @@ -1,92 +0,0 @@ -.\" Copyright (c) 1997, 2001 - 2002 Kungliga Tekniska Högskolan -.\" (Royal Institute of Technology, Stockholm, Sweden). -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" 3. Neither the name of the Institute nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" $Id$ -.\" -.Dd March 31, 1997 -.Dt TENLETXR 1 -.Os KTH_KRB -.Sh NAME -.Nm tenletxr -.Nd -forward X-connections backwards. -.Sh SYNOPSIS -.Nm tenletxr -.Op Fl l Ar username -.Op Fl k -.Ar host -.Op Ar port -.Sh DESCRIPTION -The -.Nm -program -enables forwarding of X-connections from this machine to host -.Ar host . -If -.Ar port -is given, that port will be used instead of the default. -.Pp -The supported options are: -.Bl -tag -width Ds -.It Fl l -Log in on the remote host as user -.Ar username -.It Fl k -Disables keep-alives. -.El -.Sh EXAMPLE -To login from host -.Va foo -to host -.Va bar -(where your display is), -you might do the following. -.Bl -enum -.It -On foo: -.Nm -.Va bar -.It -You will get a new shell where you will be able to start X clients -that will show their windows on -.Va bar . -.El -.Sh BUGS -It currently checks if you have permission to run it by checking if -you own -.Pa /dev/console -on the remote host. -.Sh SEE ALSO -.Xr kx 1 , -.Xr rxtelnet 1 , -.Xr rxterm 1 , -.Xr telnet 1 , -.Xr kxd 8 diff --git a/appl/kx/tenletxr.in b/appl/kx/tenletxr.in deleted file mode 100644 index e0b57ae8c..000000000 --- a/appl/kx/tenletxr.in +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh -# $Id$ -# -usage="Usage: $0 [-l username] [-k] [-v] [-h | --help] [--version] host [port]" -while true -do - case $1 in - -l) kx_args="${kx_args} -l $2"; shift 2;; - -k) kx_args="${kx_args} -k"; shift;; - --version) echo "$0: %PACKAGE% %VERSION%"; exit 0;; - -h) echo $usage; exit 0;; - --help) echo $usage; exit 0;; - -v) set -x; shift;; - -*) echo "$0: Bad option $1"; echo $usage; exit 1;; - *) break;; - esac -done -if test $# -lt 1; then - echo $usage - exit 1 -fi -host=$1 -port=$2 -bindir=%bindir% -pdc_trams=`dirname $0` -PATH=$pdc_trams:$bindir:$PATH -export PATH -set -- `kx $kx_args $host` -if test $# -ne 3; then - exit 1 -fi -screen=`echo $DISPLAY | sed -ne 's/[^:]*:[0-9]*\(\.[0-9]*\)/\1/p'` -pid=$1 -disp=${2}${screen} -auth=$3 -env DISPLAY=$disp XAUTHORITY=$auth $SHELL -kill -USR2 $pid diff --git a/appl/kx/writeauth.c b/appl/kx/writeauth.c deleted file mode 100644 index d142278c9..000000000 --- a/appl/kx/writeauth.c +++ /dev/null @@ -1,73 +0,0 @@ -/* $XConsortium: AuWrite.c,v 1.6 94/04/17 20:15:45 gildea Exp $ */ - -/* - -Copyright (c) 1988 X Consortium - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of the X Consortium shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from the X Consortium. - -*/ - -#ifdef HAVE_CONFIG_H -#include -RCSID("$Id$"); -#endif - -#include - -static int -write_short (unsigned short s, FILE *file) -{ - unsigned char file_short[2]; - - file_short[0] = (s & (unsigned)0xff00) >> 8; - file_short[1] = s & 0xff; - if (fwrite (file_short, sizeof (file_short), 1, file) != 1) - return 0; - return 1; -} - -static int -write_counted_string (unsigned short count, char *string, FILE *file) -{ - if (write_short (count, file) == 0) - return 0; - if (fwrite (string, (int) sizeof (char), (int) count, file) != count) - return 0; - return 1; -} - -int -XauWriteAuth (FILE *auth_file, Xauth *auth) -{ - if (write_short (auth->family, auth_file) == 0) - return 0; - if (write_counted_string (auth->address_length, auth->address, auth_file) == 0) - return 0; - if (write_counted_string (auth->number_length, auth->number, auth_file) == 0) - return 0; - if (write_counted_string (auth->name_length, auth->name, auth_file) == 0) - return 0; - if (write_counted_string (auth->data_length, auth->data, auth_file) == 0) - return 0; - return 1; -} diff --git a/appl/login/ChangeLog b/appl/login/ChangeLog deleted file mode 100644 index 68ab1d120..000000000 --- a/appl/login/ChangeLog +++ /dev/null @@ -1,366 +0,0 @@ -2008-04-15 Love Hörnquist Åstrand - - * utmp_login.c: Reorder to avoid prototype. - - * login_locl.h: If cygwin doesnt have WTMPX_FILE, it uses wtmp for - wtmpx http://www.cygwin.com/ml/cygwin/2006-12/msg00630.html - -2008-04-10 Love Hörnquist Åstrand - - * utmp_login.c: Remove utmp warning on mac os x - -2006-12-05 Love Hörnquist Åstrand - - * limits_conf.c: Clear errno before calling the strtol - functions. From Paul Stoeber to OpenBSD by Ray Lai and Björn - Sandell. - - * limits_conf.c: Report to syslog strings that start with NUL; - prevents negative index array access. Ray Lai of OpenBSD via Björn - Sandell. - -2006-10-07 Love Hörnquist Åstrand - - * Makefile.am: Add man_MANS to EXTRA_DIST - -2006-09-22 Love Hörnquist Åstrand - - * read_string.c: try to not call signaction for signal 0 and use - NSIG if it exists to determin how many signals there exists, also, - only restore those signalhandlers that we got out. - -2006-04-27 Love Hörnquist Åstrand - - * login_locl.h: Include "loginpaths.h" - - * loginpaths.h: Shared paths between login and rshd. - -2006-01-09 Johan Danielsson - - * login.c: log successful logins - -2005-08-08 Love Hörnquist Åstrand - - * login.c (do_login): only do krb4_get_afs_tokens if we have done - v4 authentication or done a 5to4 conversion of tickets. This is to - avoid delays on a realm that only support Kerberos 5 and drop - Kerberos 4 requests. - -2005-05-10 Dave Love - - * login.c: Include . - -2005-05-02 Dave Love - - * limits_conf.c: Check RLIMIT_MEMLOCK, not RLIMIT_LOCK. - -2005-04-28 Dave Love - - * limits_conf.c: Maybe include sys/resource.h. Use various - RLIMIT_ macros conditionally. For Solaris, Irix and Tru64. - -2005-04-22 Johan Danielsson - - * login.1: document limits.conf - - * Makefile.am: limits_conf.c - - * login_locl.h: template for limits.conf - - * login.c: read limits.conf (from /etc/security by default, - overridable in login.conf) - - * limits_conf.c: implement a parser for limits.conf - -2004-09-08 Johan Danielsson - - * login.c: use krb5_appdefault_boolean instead of - krb5_config_get_bool - -2003-09-03 Love Hörnquist Åstrand - - * login.c (krb5_to4): set client princ of the mcred - -2003-07-07 Love Hörnquist Åstrand - - * login.c (krb5_to4): use krb5_cc_clear_mcred - -2003-03-24 Johan Danielsson - - * Makefile.am: install man pages - - * login.1: manpage for login - - * login.c: allow "welcome" as well as "motd" in login.conf - - * login.access.5: login.access manual page - -2003-03-18 Love Hörnquist Åstrand - - * login.c: also need pag_set - * login.c: if there is kerberos 5, call krb5_afslog\* - -2002-08-23 Johan Danielsson - - * login.c: if motd is set in login.conf, output its contents - before starting the shell - -2002-02-27 Johan Danielsson - - * login.c: reset signals to default, needed on solaris 8 - -2002-02-19 Johan Danielsson - - * login_locl.h: include netgroup.h and rpcsvc/ypclnt.h - - * login.c: make this build without krb5 - -2001-09-22 Assar Westerlund - - * login_locl.h: kludge: use absolute path to find prot.h so we do - not get confused by athena's prot.h - -2001-09-17 Assar Westerlund - - * login.c (do_login): add setpcred - -2001-07-06 Assar Westerlund - - * login.c: move osf2c magic earlier. from Mark Davies - - -2001-06-19 Assar Westerlund - - * login.c (krb5_to4): dereference result from krb5_princ_realm. - noted by Thomas Nystrom - -2001-06-04 Assar Westerlund - - * update copyright messages on Wietse Venema's code. - -2001-05-31 Assar Westerlund - - * login.c (krb5_to4): look for [realms]krb4_get_tickets to - decide whether to get kerberos 4 tickets - -2001-02-08 Assar Westerlund - - * utmp_login.c, utmpx_login.c: try to write a useful string as - host in utmp, using the same algoritm as telnetd - -2001-01-29 Assar Westerlund - - * login.c: remove some krb5_free_context that might happen at - unappropriate times - -2000-12-31 Assar Westerlund - - * login.c (main): handle krb5_init_context failure consistently - -2000-12-11 Assar Westerlund - - * login.c (do_login): set the group on the tty. - (r_flag): comment out - * login.c (krb5_to4): always return a value - -2000-10-15 Assar Westerlund - - * login.c (krb5_to4): check another return code - -2000-08-22 Johan Danielsson - - * login.c (do_login): set PATH to something sane; - (start_logout_process): avoid getting signals sent to the parent - - * login_locl.h: _PATH_DEFPATH - -2000-07-01 Assar Westerlund - - * login.c (login_timeout): add back - -2000-06-28 Johan Danielsson - - * env.c: new file for environment related functions - - * login.c: move environment stuff to separate file, allow - specifying list of environment files via login.conf - -2000-06-21 Assar Westerlund - - * Makefile.am (LDADD): add otp - * login.c: add reading of /etc/environment. From Ake Sandgren - - add otp support. From Daniel Kouril - -2000-06-09 Assar Westerlund - - * login.c (do_login): work-around for setuid and capabilities bug - fixed in Linux 2.2.16 - -2000-04-09 Assar Westerlund - - * login.c: allow conversion of v5 -> v4 tickets when logging in - with forwarded tickets - -1999-11-09 Johan Danielsson - - * conf.c: remove case for not having cgetent, since it's in roken - -1999-11-05 Assar Westerlund - - * login.c (do_login): conditionalize shadow stuff on getspnam - -1999-10-30 Assar Westerlund - - * Makefile.am (login_DEPENDENCIES): remove, it's not entirely - correct and was causing problems with non-GNU make - -1999-10-28 Assar Westerlund - - * login.c (start_logout_proceess): don't examine `prog' before - setting it. - -1999-10-27 Assar Westerlund - - * login.c (do_login): chown and chmod the tty. some clean-up. - -1999-10-03 Assar Westerlund - - * login.c (krb5_start_session): correct the ccache to - krb524_convert_creds_kdc - -1999-09-28 Assar Westerlund - - * login.c (krb5_verify): use krb5_verify_user_lrealm - -1999-09-01 Johan Danielsson - - * login.c: SGI capability mumbo-jumbo - -1999-08-09 Johan Danielsson - - * login.c (start_logout_process): call setproctitle - - * login_locl.h: declare struct spwd - - * login.c: add support for starting extra processes at login and - logout; always preserve TERM and TZ - - * conf.c: add configuration file support - -1999-08-07 Assar Westerlund - - * shadow.c (check_shadow): check for a NULL sp - -1999-08-05 Assar Westerlund - - * login.c (main): move down login incorrect to disallow account - guessing - -1999-08-04 Assar Westerlund - - * utmpx_login.c (utmpx_login): fix for Solaris. From Miroslav - Ruda - - * login_locl.h: add and some prototypes - - * login.c: fixes with v4 and shadow support. From Miroslav Ruda - - - * shadow.c: new file with functions for handling shadow passwords - - * Makefile.am: add shadow - -1999-07-22 Assar Westerlund - - * login.c (main): generate a better tty name - -1999-05-25 Johan Danielsson - - * login.c (do_login): set $SHELL - -1999-05-18 Assar Westerlund - - * add login-access - -1999-05-11 Assar Westerlund - - * login.c: copy the v5 ccache to a file after having done setuid - -1999-05-09 Assar Westerlund - - * login.c (krb5_verify): check seteuid for errors - -Mon Apr 19 22:30:55 1999 Assar Westerlund - - * login.c: conditionalize the kafs calls on KRB4 - - * Makefile.am (LDADD): add kafs - - * login.c: add support for getting afs tokens with v4 and v5 - -Sun Apr 18 14:12:28 1999 Johan Danielsson - - * login.c: check _PATH_NOLOGIN - - * login_locl.h: _PATH_NOLOGIN - -1999-04-11 Assar Westerlund - - * login.c (main): use print_version - -Thu Apr 8 15:03:55 1999 Johan Danielsson - - * login.c: remove definition of KRB_VERIFY_USER et.al. (moved to - config.h) - - * login_locl.h: include udb.h, sys/resource.h, and sys/category.h - -Sat Mar 27 17:58:37 1999 Johan Danielsson - - * Makefile.am: osfc2.c - - * login.c: magic for OSF C2, and Crays - - * login_locl.h: do_osfc2_magic proto - - * osfc2.c: bsd_locl -> login_locl - - * osfc2.c: OSF C2 magic - -Tue Mar 23 14:17:40 1999 Johan Danielsson - - * login_locl.h: _PATH_UTMP - -Sun Mar 21 15:02:31 1999 Johan Danielsson - - * login.c: `-h' is host, not help - -Sat Mar 20 00:11:13 1999 Assar Westerlund - - * login_locl.h: krb.h: add - - * login.c: static-size - (krb4_verify): add - -Thu Mar 18 11:36:10 1999 Johan Danielsson - - * Makefile.am: include Makefile.am.common - -Thu Mar 11 17:53:36 1999 Johan Danielsson - - * utmpx_login.c: add some consts - - * utmp_login.c: add some consts - - * login.c: staticize - - * login_locl.h: add prototypes, and defaults for - _PATH_* - -Mon Mar 1 10:49:14 1999 Johan Danielsson - - * utmpx_login.c: HAVE_UT_* -> HAVE_STRUCT_UTMP*_UT_* - - * utmp_login.c: HAVE_UT_* -> HAVE_STRUCT_UTMP*_UT_* - diff --git a/appl/login/Makefile.am b/appl/login/Makefile.am deleted file mode 100644 index 3c412fe51..000000000 --- a/appl/login/Makefile.am +++ /dev/null @@ -1,40 +0,0 @@ -# $Id$ - -include $(top_srcdir)/Makefile.am.common - -man_MANS = login.1 login.access.5 - -bin_PROGRAMS = login - -login_SOURCES = \ - conf.c \ - env.c \ - login.c \ - login_access.c \ - login_locl.h \ - login-protos.h \ - loginpaths.h \ - limits_conf.c \ - osfc2.c \ - read_string.c \ - shadow.c \ - stty_default.c \ - tty.c \ - utmp_login.c \ - utmpx_login.c - -LDADD = $(LIB_otp) \ - $(LIB_kafs) \ - $(top_builddir)/lib/krb5/libkrb5.la \ - $(LIB_hcrypto) \ - $(top_builddir)/lib/asn1/libasn1.la \ - $(LIB_roken) \ - $(LIB_security) \ - $(DBLIB) - -$(srcdir)/login-protos.h: - cd $(srcdir); perl ../../cf/make-proto.pl -o login-protos.h -q -P comment $(login_SOURCES) || rm -f login-protos.h - -$(login_OBJECTS): $(srcdir)/login-protos.h - -EXTRA_DIST = $(man_MANS) diff --git a/appl/login/conf.c b/appl/login/conf.c deleted file mode 100644 index 2b141359c..000000000 --- a/appl/login/conf.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 1999 - 2000 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of KTH nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -#include "login_locl.h" - -RCSID("$Id$"); - -static char *confbuf; - -static int -login_conf_init(void) -{ - char *files[] = { _PATH_LOGIN_CONF, NULL }; - return cgetent(&confbuf, files, "default"); -} - -char * -login_conf_get_string(const char *str) -{ - char *value; - if(login_conf_init() != 0) - return NULL; - if(cgetstr(confbuf, (char *)str, &value) < 0) - return NULL; - return value; -} diff --git a/appl/login/limits_conf.c b/appl/login/limits_conf.c deleted file mode 100644 index 8420c3b82..000000000 --- a/appl/login/limits_conf.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2005 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "login_locl.h" - -RCSID("$Id$"); - -#include -#include -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif - -struct limit { - const char *name; - int resource; - int scale; - int has_limit; - struct rlimit limit; -} limits[] = { -#define LIM(X, S) { #X, RLIMIT_##X, S, 0 } - LIM(CORE, 1024), - LIM(CPU, 60), - LIM(DATA, 1024), - LIM(FSIZE, 1024), -#ifdef RLIMIT_MEMLOCK - LIM(MEMLOCK, 1024), -#endif - LIM(NOFILE, 1), -#ifdef RLIMIT_NPROC - LIM(NPROC, 1), -#endif -#ifdef RLIMIT_RSS - LIM(RSS, 1024), -#endif - LIM(STACK, 1024), - -#ifdef RLIMIT_AS - LIM(AS, 1024), -#endif -#ifdef RLIMIT_LOCKS - LIM(LOCKS, 1), -#endif - /* - maxlogins - priority - */ - { NULL, 0 } -}; - -static struct limit * -find_limit(const char *name) -{ - struct limit *l; - for(l = limits; l->name != NULL; l++) - if(strcasecmp(name, l->name) == 0) - return l; - return NULL; -} - -/* this function reads limits.conf files similar to pam_limits - unimplemented features include: - % maxlogins - "-" no limits, - priorities etc that are not set via setrlimit - XXX uses static storage, and clobbers getgr* -*/ - -int -read_limits_conf(const char *file, const struct passwd *pwd) -{ - FILE *f; - char *args[4]; - int lineno = 0; - char buf[1024]; - struct limit *l; - rlim_t value; - - f = fopen(file, "r"); - if(f == NULL) { - if(errno != ENOENT && errno != ENOTDIR) - syslog(LOG_ERR, "%s: %m", file); - return -1; - } - - while(fgets(buf, sizeof(buf), f) != NULL) { - char *last = NULL; - char *end = NULL; - int level; - - lineno++; - - if(buf[0] == '\0') { - syslog(LOG_ERR, "%s: line %d: NUL character", file, lineno); - continue; - } - if(buf[strlen(buf) - 1] != '\n') { - /* file did not end with a newline, figure out if we're at - the EOF, or if our buffer was too small */ - int eof = 1; - int c; - while((c = fgetc(f)) != EOF) { - eof = 0; - if(c == '\n') - break; - } - if(!eof) { - syslog(LOG_ERR, "%s: line %d: line too long", file, lineno); - continue; - } - } - buf[strcspn(buf, "#\r\n")] = '\0'; - if((args[0] = strtok_r(buf, " \t", &last)) == NULL || - (args[1] = strtok_r(NULL, " \t", &last)) == NULL || - (args[2] = strtok_r(NULL, " \t", &last)) == NULL || - (args[3] = strtok_r(NULL, " \t", &last)) == NULL) { - if(args[0] != NULL) /* this would include comment lines */ - syslog(LOG_ERR, "%s: line %d: malformed line", file, lineno); - continue; - } - - l = find_limit(args[2]); - if(l == NULL) { - syslog(LOG_ERR, "%s: line %d: unknown limit %s", file, lineno, args[2]); - continue; - } - if(strcmp(args[3], "-") == 0) { - value = RLIM_INFINITY; - } else { - errno = 0; - value = strtol(args[3], &end, 10); - if(*end != '\0') { - syslog(LOG_ERR, "%s: line %d: bad value %s", file, lineno, args[3]); - continue; - } - if((value == LONG_MIN || value == LONG_MAX) && errno == ERANGE) { - syslog(LOG_ERR, "%s: line %d: bad value %s", file, lineno, args[3]); - continue; - } - if(value * l->scale < value) - value = RLIM_INFINITY; - else - value *= l->scale; - } - level = 0; - /* XXX unclear: if you set group hard and user soft limit, - should the hard limit still apply? this code doesn't. */ - if(strcmp(args[0], pwd->pw_name) == 0) - level = 3; - if(*args[0] == '@') { - struct group *gr; - gr = getgrnam(args[0] + 1); - if(gr != NULL && gr->gr_gid == pwd->pw_gid) - level = 2; - } - if(strcmp(args[0], "*") == 0) - level = 1; - if(level == 0 || level < l->has_limit) /* not for us */ - continue; - if(l->has_limit < level) { - if(getrlimit(l->resource, &l->limit) < 0) - continue; - l->has_limit = level; - } - - /* XXX unclear: if you soft to more than default hard, should - we set hard to soft? this code doesn't. */ - if(strcasecmp(args[1], "soft") == 0 || strcmp(args[1], "-") == 0) - l->limit.rlim_cur = value; - if(strcasecmp(args[1], "hard") == 0 || strcmp(args[1], "-") == 0) - l->limit.rlim_max = value; - } - fclose(f); - for(l = limits; l->name != NULL; l++) { - if(l->has_limit) { - if(l->limit.rlim_cur > l->limit.rlim_max) - l->limit.rlim_cur = l->limit.rlim_max; - if(setrlimit(l->resource, &l->limit) != 0) - syslog(LOG_ERR, "setrlimit RLIM_%s failed: %m", l->name); - } - l->has_limit = 0; - } - return 0; -} diff --git a/appl/login/login.1 b/appl/login/login.1 deleted file mode 100644 index 29771c0cf..000000000 --- a/appl/login/login.1 +++ /dev/null @@ -1,253 +0,0 @@ -.\" $Id$ -.\" -.Dd April 22, 2005 -.Dt LOGIN 1 -.Os HEIMDAL -.Sh NAME -.Nm login -.Nd -authenticate a user and start new session -.Sh SYNOPSIS -.Nm -.Op Fl fp -.Op Fl a Ar level -.Op Fl h Ar hostname -.Ar [username] -.Sh DESCRIPTION -This manual page documents the -.Nm login -program distributed with the Heimdal Kerberos 5 implementation, it may -differ in important ways from your system version. -.Pp -The -.Nm login -programs logs users into the system. It is intended to be run by -system daemons like -.Xr getty 8 -or -.Xr telnetd 8 . -If you are already logged in, but want to change to another user, you -should use -.Xr su 1 . -.Pp -A username can be given on the command line, else one will be prompted -for. -.Pp -A password is required to login, unless the -.Fl f -option is given (indicating that the calling program has already done -proper authentication). With -.Fl f -the user will be logged in without further questions. -.Pp -For password authentication Kerberos 5, Kerberos 4 (if compiled in), -OTP (if compiled in) and local -.No ( Pa /etc/passwd ) -passwords are supported. OTP will be used if the the user is -registered to use it, and -.Nm login -is given the option -.Fl a Li otp . -When using OTP, a challenge is shown to the user. -.Pp -Further options are: -.Bl -tag -width Ds -.It Fl a Ar string -Which authentication mode to use, the only supported value is -currently -.Dq otp . -.It Fl f -Indicates that the user is already authenticated. This happens, for -instance, when login is started by telnetd, and the user has proved -authentic via Kerberos. -.It Fl h Ar hostname -Indicates which host the user is logging in from. This is passed from -telnetd, and is entered into the login database. -.It Fl p -This tells -.Nm login -to preserve all environment variables. If not given, only the -.Dv TERM -and -.Dv TZ -variables are preserved. It could be a security risk to pass random -variables to -.Nm login -or the user shell, so the calling daemon should make sure it only -passes -.Dq safe -variables. -.El -.Pp -The process of logging user in proceeds as follows. -.Pp -First a check is made that logins are allowed at all. This usually -means checking -.Pa /etc/nologin . -If it exists, and the user trying to login is not root, the contents -is printed, and then login exits. -.Pp -Then various system parameters are set up, like changing the owner of -the tty to the user, setting up signals, setting the group list, and -user and group id. Also various machine specific tasks are performed. -.Pp -Next -.Nm login -changes to the users home directory, or if that fails, to -.Pa / . -The environment is setup, by adding some required variables (such as -.Dv PATH ) , -and also authentication related ones (such as -.Dv KRB5CCNAME ) . -If an environment file exists -.No ( Pa /etc/environment ) , -variables are set according to -it. -.Pp -If one or more login message files are configured, their contents is -printed to the terminal. -.Pp -If a login time command is configured, it is executed. A logout time -command can also be configured, which makes -.Nm login -fork, and wait for the user shell to exit, and then run the command. -This can be used to clean up user credentials. -.Pp -Finally, the user's shell is executed. If the user logging in is root, -and root's login shell does not exist, a default shell (usually -.Pa /bin/sh ) -is also tried before giving up. -.Sh ENVIRONMENT -These environment variables are set by login (not including ones set by -.Pa /etc/environment ) : -.Pp -.Bl -tag -compact -width USERXXLOGNAME -.It Dv PATH -the default system path -.It Dv HOME -the user's home directory (or possibly -.Pa / ) -.It Dv USER , Dv LOGNAME -both set to the username -.It Dv SHELL -the user's shell -.It Dv TERM , Dv TZ -set to whatever is passed to -.Nm login -.It Dv KRB5CCNAME -if the password is verified via Kerberos 5, this will point to the -credentials cache file -.It Dv KRBTKFILE -if the password is verified via Kerberos 4, this will point to the -ticket file -.El -.Sh FILES -.Bl -tag -compact -width Ds -.It Pa /etc/environment -Contains a set of environment variables that should be set in addition -to the ones above. It should contain sh-style assignments like -.Dq VARIABLE=value . -Note that they are not parsed the way a shell would. No variable -expansion is performed, and all strings are literal, and quotation -marks should not be used. Everything after a hash mark is considered a -comment. The following are all different (the last will set the -variable -.Dv BAR , -not -.Dv FOO ) . -.Bd -literal -offset indent -FOO=this is a string -FOO="this is a string" -BAR= FOO='this is a string' -.Ed -.It Pa /etc/login.access -See -.Xr login.access 5 . -.It Pa /etc/login.conf -This is a termcap style configuration file, that contains various -settings used by -.Nm login . -Currently only the -.Dq default -capability record is used. The possible capability strings include: -.Pp -.Bl -tag -compact -width Ds -.It Li environment -This is a comma separated list of environment files that are read in -the order specified. If this is missing the default -.Pa /etc/environment -is used. -.It Li login_program -This program will be executed just before the user's shell is started. -It will be called without arguments. -.It Li logout_program -This program will be executed just after the user's shell has -terminated. It will be called without arguments. This program will be -the parent process of the spawned shell. -.It Li motd -A comma separated list of text files that will be printed to the -user's terminal before starting the shell. The string -.Li welcome -works similarly, but points to a single file. -.It Li limits -Points to a file containing ulimit settings for various users. Syntax -is inspired by what pam_limits uses, and the default is -.Pa /etc/security/limits.conf . -.El -.It Pa /etc/nologin -If it exists, login is denied to all but root. The contents of this -file is printed before login exits. -.El -.Pp -Other -.Nm login -programs typically print all sorts of information by default, such as -last time you logged in, if you have mail, and system message files. -This version of -.Nm login -does not, so there is no reason for -.Pa .hushlogin -files or similar. We feel that these tasks are best left to the user's -shell, but the -.Li login_program -facility allows for a shell independent solution, if that is desired. -.Sh EXAMPLES -A -.Pa login.conf -file could look like: -.Bd -literal -offset indent -default:\\ - :motd=/etc/motd,/etc/motd.local:\\ - :limits=/etc/limits.conf: -.Ed -.Pp -The -.Pa limits.conf -file consists of a table with four whitespace separated fields. First -field is a username or a groupname (prefixed with -.Sq @ ) , -or -.Sq * . -Second field is -.Sq soft , -.Sq hard , -or -.Sq - -(the last meaning both soft and hard). -Third field is a limit name (such as -.Sq cpu -or -.Sq core ) . -Last field is the limit value (a number or -.Sq - -for unlimited). In the case of data sizes, the value is in kilobytes, -and cputime is in minutes. -.Sh SEE ALSO -.Xr su 1 , -.Xr login.access 5 , -.Xr getty 8 , -.Xr telnetd 8 -.Sh AUTHORS -This login program was written for the Heimdal Kerberos 5 -implementation. The login.access code was written by Wietse Venema. -.\".Sh BUGS diff --git a/appl/login/login.access.5 b/appl/login/login.access.5 deleted file mode 100644 index df57e4413..000000000 --- a/appl/login/login.access.5 +++ /dev/null @@ -1,56 +0,0 @@ -.\" $Id$ -.\" -.Dd March 21, 2003 -.Dt LOGIN.ACCESS 5 -.Os HEIMDAL -.Sh NAME -.Nm login.access -.Nd -login access control table -.Sh DESCRIPTION -The -.Nm login.access -file specifies on which ttys or from which hosts certain users are -allowed to login. -.Pp -At login, the -.Pa /etc/login.access -file is checked for the first entry that matches a specific user/host -or user/tty combination. That entry can either allow or deny login -access to that user. -.Pp -Each entry have three fields separated by colon: -.Bl -bullet -.It -The first field indicates the permission given if the entry matches. -It can be either -.Dq + -(allow access) -or -.Dq - -(deny access) . -.It -The second field is a comma separated list of users or groups for -which the current entry applies. NIS netgroups can used (if -configured) if preceeded by @. The magic string ALL matches all users. -A group will match if the user is a member of that group, or it is the -user's primary group. -.It -The third field is a list of ttys, or network names. A network name -can be either a hostname, a domain (indicated by a starting period), -or a netgroup. As with the user list, ALL matches anything. LOCAL -matches a string not containing a period. -.El -.Pp -If the string EXCEPT is found in either the user or from list, the -rest of the list are exceptions to the list before EXCEPT. -.Sh BUGS -If there's a user and a group with the same name, there is no way to -make the group match if the user also matches. -.Sh SEE ALSO -.Xr login 1 -.Sh AUTHORS -The -.Fn login_access -function was written by -Wietse Venema. This manual page was written for Heimdal. diff --git a/appl/login/login.c b/appl/login/login.c deleted file mode 100644 index 6f0b62648..000000000 --- a/appl/login/login.c +++ /dev/null @@ -1,733 +0,0 @@ -/* - * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "login_locl.h" -#ifdef HAVE_CAPABILITY_H -#include -#endif -#ifdef HAVE_SYS_CAPABILITY_H -#include -#endif -#ifdef HAVE_CRYPT_H -#include -#endif - -RCSID("$Id$"); - -static int login_timeout = 60; - -static int -start_login_process(void) -{ - char *prog, *argv0; - prog = login_conf_get_string("login_program"); - if(prog == NULL) - return 0; - argv0 = strrchr(prog, '/'); - - if(argv0) - argv0++; - else - argv0 = prog; - - return simple_execle(prog, argv0, NULL, env); -} - -static int -start_logout_process(void) -{ - char *prog, *argv0; - pid_t pid; - - prog = login_conf_get_string("logout_program"); - if(prog == NULL) - return 0; - argv0 = strrchr(prog, '/'); - - if(argv0) - argv0++; - else - argv0 = prog; - - pid = fork(); - if(pid == 0) { - /* avoid getting signals sent to the shell */ - setpgid(0, getpid()); - return 0; - } - if(pid == -1) - err(1, "fork"); - /* wait for the real login process to exit */ -#ifdef HAVE_SETPROCTITLE - setproctitle("waitpid %d", pid); -#endif - while(1) { - int status; - int ret; - ret = waitpid(pid, &status, 0); - if(ret > 0) { - if(WIFEXITED(status) || WIFSIGNALED(status)) { - execle(prog, argv0, NULL, env); - err(1, "exec %s", prog); - } - } else if(ret < 0) - err(1, "waitpid"); - } -} - -static void -exec_shell(const char *shell, int fallback) -{ - char *sh; - const char *p; - - extend_env(NULL); - if(start_login_process() < 0) - warn("login process"); - start_logout_process(); - - p = strrchr(shell, '/'); - if(p) - p++; - else - p = shell; - if (asprintf(&sh, "-%s", p) == -1) - errx(1, "Out of memory"); - execle(shell, sh, NULL, env); - if(fallback){ - warnx("Can't exec %s, trying %s", - shell, _PATH_BSHELL); - execle(_PATH_BSHELL, "-sh", NULL, env); - err(1, "%s", _PATH_BSHELL); - } - err(1, "%s", shell); -} - -static enum { NONE = 0, AUTH_KRB5 = 2, AUTH_OTP = 3 } auth; - -#ifdef OTP -static OtpContext otp_ctx; - -static int -otp_verify(struct passwd *pwd, const char *password) -{ - return (otp_verify_user (&otp_ctx, password)); -} -#endif /* OTP */ - - -static int pag_set = 0; - -#ifdef KRB5 -static krb5_context context; -static krb5_ccache id, id2; - -static int -krb5_verify(struct passwd *pwd, const char *password) -{ - krb5_error_code ret; - krb5_principal princ; - - ret = krb5_parse_name(context, pwd->pw_name, &princ); - if(ret) - return 1; - ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id); - if(ret) { - krb5_free_principal(context, princ); - return 1; - } - ret = krb5_verify_user_lrealm(context, - princ, - id, - password, - 1, - NULL); - krb5_free_principal(context, princ); - return ret; -} - -static int -krb5_start_session (const struct passwd *pwd) -{ - krb5_error_code ret; - char residual[64]; - - /* copy credentials to file cache */ - snprintf(residual, sizeof(residual), "FILE:/tmp/krb5cc_%u", - (unsigned)pwd->pw_uid); - krb5_cc_resolve(context, residual, &id2); - ret = krb5_cc_copy_cache(context, id, id2); - if (ret == 0) - add_env("KRB5CCNAME", residual); - else { - krb5_cc_destroy (context, id2); - return ret; - } - krb5_cc_close(context, id2); - krb5_cc_destroy(context, id); - return 0; -} - -static void -krb5_finish (void) -{ - krb5_free_context(context); -} - -static void -krb5_get_afs_tokens (const struct passwd *pwd) -{ - char cell[64]; - char *pw_dir; - krb5_error_code ret; - - if (!k_hasafs ()) - return; - - ret = krb5_cc_default(context, &id2); - - if (ret == 0) { - pw_dir = pwd->pw_dir; - - if (!pag_set) { - k_setpag(); - pag_set = 1; - } - - if(k_afs_cell_of_file(pw_dir, cell, sizeof(cell)) == 0) - krb5_afslog_uid_home (context, id2, - cell, NULL, pwd->pw_uid, pwd->pw_dir); - krb5_afslog_uid_home (context, id2, NULL, NULL, - pwd->pw_uid, pwd->pw_dir); - krb5_cc_close (context, id2); - } -} - -#endif /* KRB5 */ - -static int f_flag; -static int p_flag; -#if 0 -static int r_flag; -#endif -static int version_flag; -static int help_flag; -static char *remote_host; -static char *auth_level = NULL; - -struct getargs args[] = { - { NULL, 'a', arg_string, &auth_level, "authentication mode" }, -#if 0 - { NULL, 'd' }, -#endif - { NULL, 'f', arg_flag, &f_flag, "pre-authenticated" }, - { NULL, 'h', arg_string, &remote_host, "remote host", "hostname" }, - { NULL, 'p', arg_flag, &p_flag, "don't purge environment" }, -#if 0 - { NULL, 'r', arg_flag, &r_flag, "rlogin protocol" }, -#endif - { "version", 0, arg_flag, &version_flag }, - { "help", 0, arg_flag,&help_flag, } -}; - -int nargs = sizeof(args) / sizeof(args[0]); - -static void -update_utmp(const char *username, const char *hostname, - char *tty, char *ttyn) -{ - /* - * Update the utmp files, both BSD and SYSV style. - */ - if (utmpx_login(tty, username, hostname) != 0 && !f_flag) { - printf("No utmpx entry. You must exec \"login\" from the " - "lowest level shell.\n"); - exit(1); - } - utmp_login(ttyn, username, hostname); -} - -static void -checknologin(void) -{ - FILE *f; - char buf[1024]; - - f = fopen(_PATH_NOLOGIN, "r"); - if(f == NULL) - return; - while(fgets(buf, sizeof(buf), f)) - fputs(buf, stdout); - fclose(f); - exit(0); -} - -/* print contents of a file */ -static void -show_file(const char *file) -{ - FILE *f; - char buf[BUFSIZ]; - if((f = fopen(file, "r")) == NULL) - return; - while (fgets(buf, sizeof(buf), f)) - fputs(buf, stdout); - fclose(f); -} - -/* - * Actually log in the user. `pwd' contains all the relevant - * information about the user. `ttyn' is the complete name of the tty - * and `tty' the short name. - */ - -static void -do_login(const struct passwd *pwd, char *tty, char *ttyn) -{ -#ifdef HAVE_GETSPNAM - struct spwd *sp; -#endif - int rootlogin = (pwd->pw_uid == 0); - gid_t tty_gid; - struct group *gr; - const char *home_dir; - int i; - - if(!rootlogin) - checknologin(); - -#ifdef HAVE_GETSPNAM - sp = getspnam(pwd->pw_name); -#endif - - update_utmp(pwd->pw_name, remote_host ? remote_host : "", - tty, ttyn); - - gr = getgrnam ("tty"); - if (gr != NULL) - tty_gid = gr->gr_gid; - else - tty_gid = pwd->pw_gid; - - if (chown (ttyn, pwd->pw_uid, tty_gid) < 0) { - warn("chown %s", ttyn); - if (rootlogin == 0) - exit (1); - } - - if (chmod (ttyn, S_IRUSR | S_IWUSR | S_IWGRP) < 0) { - warn("chmod %s", ttyn); - if (rootlogin == 0) - exit (1); - } - -#ifdef HAVE_SETLOGIN - if(setlogin(pwd->pw_name)){ - warn("setlogin(%s)", pwd->pw_name); - if(rootlogin == 0) - exit(1); - } -#endif - if(rootlogin == 0) { - const char *file = login_conf_get_string("limits"); - if(file == NULL) - file = _PATH_LIMITS_CONF; - - read_limits_conf(file, pwd); - } - -#ifdef HAVE_SETPCRED - if (setpcred (pwd->pw_name, NULL) == -1) - warn("setpcred(%s)", pwd->pw_name); -#endif /* HAVE_SETPCRED */ -#ifdef HAVE_INITGROUPS - if(initgroups(pwd->pw_name, pwd->pw_gid)){ - warn("initgroups(%s, %u)", pwd->pw_name, (unsigned)pwd->pw_gid); - if(rootlogin == 0) - exit(1); - } -#endif - if(do_osfc2_magic(pwd->pw_uid)) - exit(1); - if(setgid(pwd->pw_gid)){ - warn("setgid(%u)", (unsigned)pwd->pw_gid); - if(rootlogin == 0) - exit(1); - } - if(setuid(pwd->pw_uid) || (pwd->pw_uid != 0 && setuid(0) == 0)) { - warn("setuid(%u)", (unsigned)pwd->pw_uid); - if(rootlogin == 0) - exit(1); - } - - /* make sure signals are set to default actions, apparently some - OS:es like to ignore SIGINT, which is not very convenient */ - - for (i = 1; i < NSIG; ++i) - signal(i, SIG_DFL); - - /* all kinds of different magic */ - -#ifdef HAVE_GETSPNAM - check_shadow(pwd, sp); -#endif - -#if defined(HAVE_GETUDBNAM) && defined(HAVE_SETLIM) - { - struct udb *udb; - long t; - const long maxcpu = 46116860184; /* some random constant */ - udb = getudbnam(pwd->pw_name); - if(udb == UDB_NULL) - errx(1, "Failed to get UDB entry."); - t = udb->ue_pcpulim[UDBRC_INTER]; - if(t == 0 || t > maxcpu) - t = CPUUNLIM; - else - t *= 100 * CLOCKS_PER_SEC; - - if(limit(C_PROC, 0, L_CPU, t) < 0) - warn("limit C_PROC"); - - t = udb->ue_jcpulim[UDBRC_INTER]; - if(t == 0 || t > maxcpu) - t = CPUUNLIM; - else - t *= 100 * CLOCKS_PER_SEC; - - if(limit(C_JOBPROCS, 0, L_CPU, t) < 0) - warn("limit C_JOBPROCS"); - - nice(udb->ue_nice[UDBRC_INTER]); - } -#endif -#if defined(HAVE_SGI_GETCAPABILITYBYNAME) && defined(HAVE_CAP_SET_PROC) - /* XXX SGI capability hack IRIX 6.x (x >= 0?) has something - called capabilities, that allow you to give away - permissions (such as chown) to specific processes. From 6.5 - this is default on, and the default capability set seems to - not always be the empty set. The problem is that the - runtime linker refuses to do just about anything if the - process has *any* capabilities set, so we have to remove - them here (unless otherwise instructed by /etc/capability). - In IRIX < 6.5, these functions was called sgi_cap_setproc, - etc, but we ignore this fact (it works anyway). */ - { - struct user_cap *ucap = sgi_getcapabilitybyname(pwd->pw_name); - cap_t cap; - if(ucap == NULL) - cap = cap_from_text("all="); - else - cap = cap_from_text(ucap->ca_default); - if(cap == NULL) - err(1, "cap_from_text"); - if(cap_set_proc(cap) < 0) - err(1, "cap_set_proc"); - cap_free(cap); - free(ucap); - } -#endif - home_dir = pwd->pw_dir; - if (chdir(home_dir) < 0) { - fprintf(stderr, "No home directory \"%s\"!\n", pwd->pw_dir); - if (chdir("/")) - exit(0); - home_dir = "/"; - fprintf(stderr, "Logging in with home = \"/\".\n"); - } -#ifdef KRB5 - if (auth == AUTH_KRB5) { - krb5_start_session (pwd); - } - - krb5_get_afs_tokens (pwd); - - krb5_finish (); -#endif /* KRB5 */ - - add_env("PATH", _PATH_DEFPATH); - - { - const char *str = login_conf_get_string("environment"); - char buf[MAXPATHLEN]; - - if(str == NULL) { - login_read_env(_PATH_ETC_ENVIRONMENT); - } else { - while(strsep_copy(&str, ",", buf, sizeof(buf)) != -1) { - if(buf[0] == '\0') - continue; - login_read_env(buf); - } - } - } - { - const char *str = login_conf_get_string("motd"); - char buf[MAXPATHLEN]; - - if(str != NULL) { - while(strsep_copy(&str, ",", buf, sizeof(buf)) != -1) { - if(buf[0] == '\0') - continue; - show_file(buf); - } - } else { - str = login_conf_get_string("welcome"); - if(str != NULL) - show_file(str); - } - } - add_env("HOME", home_dir); - add_env("USER", pwd->pw_name); - add_env("LOGNAME", pwd->pw_name); - add_env("SHELL", pwd->pw_shell); - exec_shell(pwd->pw_shell, rootlogin); -} - -static int -check_password(struct passwd *pwd, const char *password) -{ - if(pwd->pw_passwd == NULL) - return 1; - if(pwd->pw_passwd[0] == '\0'){ -#ifdef ALLOW_NULL_PASSWORD - return password[0] != '\0'; -#else - return 1; -#endif - } - if(strcmp(pwd->pw_passwd, crypt(password, pwd->pw_passwd)) == 0) - return 0; -#ifdef KRB5 - if(krb5_verify(pwd, password) == 0) { - auth = AUTH_KRB5; - return 0; - } -#endif -#ifdef OTP - if (otp_verify (pwd, password) == 0) { - auth = AUTH_OTP; - return 0; - } -#endif - return 1; -} - -static void -usage(int status) -{ - arg_printusage(args, nargs, NULL, "[username]"); - exit(status); -} - -static RETSIGTYPE -sig_handler(int sig) -{ - if (sig == SIGALRM) - fprintf(stderr, "Login timed out after %d seconds\n", - login_timeout); - else - fprintf(stderr, "Login received signal, exiting\n"); - exit(0); -} - -int -main(int argc, char **argv) -{ - int max_tries = 5; - int try; - - char username[32]; - int optidx = 0; - - int ask = 1; - struct sigaction sa; - - setprogname(argv[0]); - -#ifdef KRB5 - { - krb5_error_code ret; - - ret = krb5_init_context(&context); - if (ret) - errx (1, "krb5_init_context failed: %d", ret); - } -#endif - - openlog("login", LOG_ODELAY | LOG_PID, LOG_AUTH); - - if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, - &optidx)) - usage (1); - argc -= optidx; - argv += optidx; - - if(help_flag) - usage(0); - if (version_flag) { - print_version (NULL); - return 0; - } - - if (geteuid() != 0) - errx(1, "only root may use login, use su"); - - /* Default tty settings. */ - stty_default(); - - if(p_flag) - copy_env(); - else { - /* this set of variables is always preserved by BSD login */ - if(getenv("TERM")) - add_env("TERM", getenv("TERM")); - if(getenv("TZ")) - add_env("TZ", getenv("TZ")); - } - - if(*argv){ - if(strchr(*argv, '=') == NULL && strcmp(*argv, "-") != 0){ - strlcpy (username, *argv, sizeof(username)); - ask = 0; - } - } - -#if defined(DCE) && defined(AIX) - esetenv("AUTHSTATE", "DCE", 1); -#endif - - /* XXX should we care about environment on the command line? */ - - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = sig_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sigaction(SIGALRM, &sa, NULL); - alarm(login_timeout); - - for(try = 0; try < max_tries; try++){ - struct passwd *pwd; - char password[128]; - int ret; - char ttname[32]; - char *tty, *ttyn; - char prompt[128]; -#ifdef OTP - char otp_str[256]; -#endif - - if(ask){ - f_flag = 0; -#if 0 - r_flag = 0; -#endif - ret = read_string("login: ", username, sizeof(username), 1); - if(ret == -3) - exit(0); - if(ret == -2) - sig_handler(0); /* exit */ - } - pwd = k_getpwnam(username); -#ifdef ALLOW_NULL_PASSWORD - if (pwd != NULL && (pwd->pw_passwd[0] == '\0')) { - strcpy(password,""); - } - else -#endif - - { -#ifdef OTP - if(auth_level && strcmp(auth_level, "otp") == 0 && - otp_challenge(&otp_ctx, username, - otp_str, sizeof(otp_str)) == 0) - snprintf (prompt, sizeof(prompt), "%s's %s Password: ", - username, otp_str); - else -#endif - strncpy(prompt, "Password: ", sizeof(prompt)); - - if (f_flag == 0) { - ret = read_string(prompt, password, sizeof(password), 0); - if (ret == -3) { - ask = 1; - continue; - } - if (ret == -2) - sig_handler(0); - } - } - - if(pwd == NULL){ - fprintf(stderr, "Login incorrect.\n"); - ask = 1; - continue; - } - - if(f_flag == 0 && check_password(pwd, password)){ - fprintf(stderr, "Login incorrect.\n"); - ask = 1; - continue; - } - ttyn = ttyname(STDIN_FILENO); - if(ttyn == NULL){ - snprintf(ttname, sizeof(ttname), "%s??", _PATH_TTY); - ttyn = ttname; - } - if (strncmp (ttyn, _PATH_DEV, strlen(_PATH_DEV)) == 0) - tty = ttyn + strlen(_PATH_DEV); - else - tty = ttyn; - - if (login_access (pwd, remote_host ? remote_host : tty) == 0) { - fprintf(stderr, "Permission denied\n"); - if (remote_host) - syslog(LOG_NOTICE, "%s LOGIN REFUSED FROM %s", - pwd->pw_name, remote_host); - else - syslog(LOG_NOTICE, "%s LOGIN REFUSED ON %s", - pwd->pw_name, tty); - exit (1); - } else { - if (remote_host) - syslog(LOG_NOTICE, "%s LOGIN ACCEPTED FROM %s ppid=%d", - pwd->pw_name, remote_host, (int) getppid()); - else - syslog(LOG_NOTICE, "%s LOGIN ACCEPTED ON %s ppid=%d", - pwd->pw_name, tty, (int) getppid()); - } - alarm(0); - do_login(pwd, tty, ttyn); - } - exit(1); -} diff --git a/appl/login/login_access.c b/appl/login/login_access.c deleted file mode 100644 index 71b1fb1aa..000000000 --- a/appl/login/login_access.c +++ /dev/null @@ -1,277 +0,0 @@ -/************************************************************************ -* Copyright 1995 by Wietse Venema. All rights reserved. Some individual -* files may be covered by other copyrights. -* -* This material was originally written and compiled by Wietse Venema at -* Eindhoven University of Technology, The Netherlands, in 1990, 1991, -* 1992, 1993, 1994 and 1995. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that this entire copyright notice -* is duplicated in all such copies. -* -* This software is provided "as is" and without any expressed or implied -* warranties, including, without limitation, the implied warranties of -* merchantibility and fitness for any particular purpose. -************************************************************************/ - /* - * This module implements a simple but effective form of login access - * control based on login names and on host (or domain) names, internet - * addresses (or network numbers), or on terminal line names in case of - * non-networked logins. Diagnostics are reported through syslog(3). - * - * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. - */ - -#include "login_locl.h" - -RCSID("$Id$"); - - /* Delimiters for fields and for lists of users, ttys or hosts. */ - -static char fs[] = ":"; /* field separator */ -static char sep[] = ", \t"; /* list-element separator */ - - /* Constants to be used in assignments only, not in comparisons... */ - -#define YES 1 -#define NO 0 - - /* - * A structure to bundle up all login-related information to keep the - * functional interfaces as generic as possible. - */ -struct login_info { - struct passwd *user; - char *from; -}; - -static int list_match(char *list, struct login_info *item, - int (*match_fn)(char *, struct login_info *)); -static int user_match(char *tok, struct login_info *item); -static int from_match(char *tok, struct login_info *item); -static int string_match(char *tok, char *string); - -/* login_access - match username/group and host/tty with access control file */ - -int login_access(struct passwd *user, char *from) -{ - struct login_info item; - FILE *fp; - char line[BUFSIZ]; - char *perm; /* becomes permission field */ - char *users; /* becomes list of login names */ - char *froms; /* becomes list of terminals or hosts */ - int match = NO; - int end; - int lineno = 0; /* for diagnostics */ - char *foo; - - /* - * Bundle up the arguments to avoid unnecessary clumsiness lateron. - */ - item.user = user; - item.from = from; - - /* - * Process the table one line at a time and stop at the first match. - * Blank lines and lines that begin with a '#' character are ignored. - * Non-comment lines are broken at the ':' character. All fields are - * mandatory. The first field should be a "+" or "-" character. A - * non-existing table means no access control. - */ - - if ((fp = fopen(_PATH_LOGACCESS, "r")) != 0) { - while (!match && fgets(line, sizeof(line), fp)) { - lineno++; - if (line[end = strlen(line) - 1] != '\n') { - syslog(LOG_ERR, "%s: line %d: missing newline or line too long", - _PATH_LOGACCESS, lineno); - continue; - } - if (line[0] == '#') - continue; /* comment line */ - while (end > 0 && isspace((unsigned char)line[end - 1])) - end--; - line[end] = 0; /* strip trailing whitespace */ - if (line[0] == 0) /* skip blank lines */ - continue; - foo = NULL; - if (!(perm = strtok_r(line, fs, &foo)) - || !(users = strtok_r(NULL, fs, &foo)) - || !(froms = strtok_r(NULL, fs, &foo)) - || strtok_r(NULL, fs, &foo)) { - syslog(LOG_ERR, "%s: line %d: bad field count", - _PATH_LOGACCESS, - lineno); - continue; - } - if (perm[0] != '+' && perm[0] != '-') { - syslog(LOG_ERR, "%s: line %d: bad first field", - _PATH_LOGACCESS, - lineno); - continue; - } - match = (list_match(froms, &item, from_match) - && list_match(users, &item, user_match)); - } - fclose(fp); - } else if (errno != ENOENT) { - syslog(LOG_ERR, "cannot open %s: %m", _PATH_LOGACCESS); - } - return (match == 0 || (line[0] == '+')); -} - -/* list_match - match an item against a list of tokens with exceptions */ - -static int -list_match(char *list, - struct login_info *item, - int (*match_fn)(char *, struct login_info *)) -{ - char *tok; - int match = NO; - char *foo = NULL; - - /* - * Process tokens one at a time. We have exhausted all possible matches - * when we reach an "EXCEPT" token or the end of the list. If we do find - * a match, look for an "EXCEPT" list and recurse to determine whether - * the match is affected by any exceptions. - */ - - for (tok = strtok_r(list, sep, &foo); - tok != NULL; - tok = strtok_r(NULL, sep, &foo)) { - if (strcasecmp(tok, "EXCEPT") == 0) /* EXCEPT: give up */ - break; - if ((match = (*match_fn) (tok, item)) != 0) /* YES */ - break; - } - /* Process exceptions to matches. */ - - if (match != NO) { - while ((tok = strtok_r(NULL, sep, &foo)) && strcasecmp(tok, "EXCEPT")) - /* VOID */ ; - if (tok == 0 || list_match(NULL, item, match_fn) == NO) - return (match); - } - return (NO); -} - -/* myhostname - figure out local machine name */ - -static char *myhostname(void) -{ - static char name[MAXHOSTNAMELEN + 1] = ""; - - if (name[0] == 0) { - gethostname(name, sizeof(name)); - name[MAXHOSTNAMELEN] = 0; - } - return (name); -} - -/* netgroup_match - match group against machine or user */ - -static int netgroup_match(char *group, char *machine, char *user) -{ -#ifdef HAVE_YP_GET_DEFAULT_DOMAIN - static char *mydomain = 0; - - if (mydomain == 0) - yp_get_default_domain(&mydomain); - return (innetgr(group, machine, user, mydomain)); -#else - syslog(LOG_ERR, "NIS netgroup support not configured"); - return 0; -#endif -} - -/* user_match - match a username against one token */ - -static int user_match(char *tok, struct login_info *item) -{ - char *string = item->user->pw_name; - struct login_info fake_item; - struct group *group; - int i; - char *at; - - /* - * If a token has the magic value "ALL" the match always succeeds. - * Otherwise, return YES if the token fully matches the username, if the - * token is a group that contains the username, or if the token is the - * name of the user's primary group. - */ - - if ((at = strchr(tok + 1, '@')) != 0) { /* split user@host pattern */ - *at = 0; - fake_item.from = myhostname(); - return (user_match(tok, item) && from_match(at + 1, &fake_item)); - } else if (tok[0] == '@') { /* netgroup */ - return (netgroup_match(tok + 1, (char *) 0, string)); - } else if (string_match(tok, string)) { /* ALL or exact match */ - return (YES); - } else if ((group = getgrnam(tok)) != 0) { /* try group membership */ - if (item->user->pw_gid == group->gr_gid) - return (YES); - for (i = 0; group->gr_mem[i]; i++) - if (strcasecmp(string, group->gr_mem[i]) == 0) - return (YES); - } - return (NO); -} - -/* from_match - match a host or tty against a list of tokens */ - -static int from_match(char *tok, struct login_info *item) -{ - char *string = item->from; - int tok_len; - int str_len; - - /* - * If a token has the magic value "ALL" the match always succeeds. Return - * YES if the token fully matches the string. If the token is a domain - * name, return YES if it matches the last fields of the string. If the - * token has the magic value "LOCAL", return YES if the string does not - * contain a "." character. If the token is a network number, return YES - * if it matches the head of the string. - */ - - if (tok[0] == '@') { /* netgroup */ - return (netgroup_match(tok + 1, string, (char *) 0)); - } else if (string_match(tok, string)) { /* ALL or exact match */ - return (YES); - } else if (tok[0] == '.') { /* domain: match last fields */ - if ((str_len = strlen(string)) > (tok_len = strlen(tok)) - && strcasecmp(tok, string + str_len - tok_len) == 0) - return (YES); - } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no dots */ - if (strchr(string, '.') == 0) - return (YES); - } else if (tok[(tok_len = strlen(tok)) - 1] == '.' /* network */ - && strncmp(tok, string, tok_len) == 0) { - return (YES); - } - return (NO); -} - -/* string_match - match a string against one token */ - -static int string_match(char *tok, char *string) -{ - - /* - * If the token has the magic value "ALL" the match always succeeds. - * Otherwise, return YES if the token fully matches the string. - */ - - if (strcasecmp(tok, "ALL") == 0) { /* all: always matches */ - return (YES); - } else if (strcasecmp(tok, string) == 0) { /* try exact match */ - return (YES); - } - return (NO); -} diff --git a/appl/login/login_locl.h b/appl/login/login_locl.h deleted file mode 100644 index 020eac889..000000000 --- a/appl/login/login_locl.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* $Id$ */ - -#ifndef __LOGIN_LOCL_H__ -#define __LOGIN_LOCL_H__ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_PATHS_H -#include -#endif -#ifdef HAVE_UTMP_H -#include -#endif -#ifdef HAVE_UTMPX_H -#include -#endif -#ifdef HAVE_UDB_H -#include -#endif -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif -#ifdef HAVE_SYS_CATEGORY_H -#include -#endif -#ifdef HAVE_SYS_WAIT_H -#include -#endif -#ifdef HAVE_SHADOW_H -#include -#endif -#ifdef HAVE_NETGROUP_H -#include -#endif -#ifdef HAVE_RPCSVC_YPCLNT_H -#include -#endif -#ifdef KRB5 -#include -#endif -#include - -#ifdef OTP -#include -#endif - -#ifdef HAVE_OSFC2 -#define getargs OSFgetargs -#include "/usr/include/prot.h" -#undef getargs -#endif - -#ifndef _PATH_BSHELL -#define _PATH_BSHELL "/bin/sh" -#endif -#ifndef _PATH_TTY -#define _PATH_TTY "/dev/tty" -#endif -#ifndef _PATH_DEV -#define _PATH_DEV "/dev/" -#endif -#ifndef _PATH_WTMP -#ifdef WTMP_FILE -#define _PATH_WTMP WTMP_FILE -#else -#define _PATH_WTMP "/var/adm/wtmp" -#endif -#endif -#ifndef _PATH_UTMP -#ifdef UTMP_FILE -#define _PATH_UTMP UTMP_FILE -#else -#define _PATH_UTMP "/var/adm/utmp" -#endif -#endif - -/* if cygwin doesnt have WTMPX_FILE, it uses wtmp for wtmpx - * http://www.cygwin.com/ml/cygwin/2006-12/msg00630.html */ -#ifdef __CYGWIN__ -#ifndef WTMPX_FILE -#define WTMPX_FILE WTMP_FILE -#endif -#endif - -#ifndef _PATH_LOGACCESS -#define _PATH_LOGACCESS SYSCONFDIR "/login.access" -#endif /* _PATH_LOGACCESS */ - -#ifndef _PATH_LOGIN_CONF -#define _PATH_LOGIN_CONF SYSCONFDIR "/login.conf" -#endif /* _PATH_LOGIN_CONF */ - -#ifndef _PATH_DEFPATH -#define _PATH_DEFPATH "/usr/bin:/bin" -#endif - -#include "loginpaths.h" - -struct spwd; - -extern char **env; -extern int num_env; - -#include "login-protos.h" - -#endif /* __LOGIN_LOCL_H__ */ diff --git a/appl/login/read_string.c b/appl/login/read_string.c deleted file mode 100644 index eb61621a3..000000000 --- a/appl/login/read_string.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "login_locl.h" - -RCSID("$Id$"); - -static sig_atomic_t intr_flag; - -static void -intr(int sig) -{ - intr_flag++; -} - -#ifndef NSIG -#define NSIG 47 -#endif - -int -read_string(const char *prompt, char *buf, size_t len, int echo) -{ - struct sigaction sigs[NSIG]; - int oksigs[NSIG]; - struct sigaction sa; - FILE *tty; - int ret = 0; - int of = 0; - int i; - int c; - char *p; - - struct termios t_new, t_old; - - memset(&oksigs, 0, sizeof(oksigs)); - - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = intr; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - for(i = 1; i < sizeof(sigs) / sizeof(sigs[0]); i++) - if (i != SIGALRM) - if (sigaction(i, &sa, &sigs[i]) == 0) - oksigs[i] = 1; - - if((tty = fopen("/dev/tty", "r")) == NULL) - tty = stdin; - - fprintf(stderr, "%s", prompt); - fflush(stderr); - - if(echo == 0){ - tcgetattr(fileno(tty), &t_old); - memcpy(&t_new, &t_old, sizeof(t_new)); - t_new.c_lflag &= ~ECHO; - tcsetattr(fileno(tty), TCSANOW, &t_new); - } - intr_flag = 0; - p = buf; - while(intr_flag == 0){ - c = getc(tty); - if(c == EOF){ - if(!ferror(tty)) - ret = 1; - break; - } - if(c == '\n') - break; - if(of == 0) - *p++ = c; - of = (p == buf + len); - } - if(of) - p--; - *p = 0; - - if(echo == 0){ - printf("\n"); - tcsetattr(fileno(tty), TCSANOW, &t_old); - } - - if(tty != stdin) - fclose(tty); - - for(i = 1; i < sizeof(sigs) / sizeof(sigs[0]); i++) - if (oksigs[i]) - sigaction(i, &sigs[i], NULL); - - if(ret) - return -3; - if(intr_flag) - return -2; - if(of) - return -1; - return 0; -} - - -#if 0 -int main() -{ - char s[128]; - int ret; - ret = read_string("foo: ", s, sizeof(s), 0); - printf("%d ->%s<-\n", ret, s); -} -#endif diff --git a/appl/login/shadow.c b/appl/login/shadow.c deleted file mode 100644 index f8fb892ee..000000000 --- a/appl/login/shadow.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "login_locl.h" - -RCSID("$Id$"); - -#ifdef HAVE_SHADOW_H - -#ifndef _PATH_CHPASS -#define _PATH_CHPASS "/usr/bin/passwd" -#endif - -static int -change_passwd(const struct passwd *who) -{ - int status; - pid_t pid; - - switch (pid = fork()) { - case -1: - printf("fork /bin/passwd"); - exit(1); - case 0: - execlp(_PATH_CHPASS, "passwd", who->pw_name, (char *) 0); - exit(1); - default: - waitpid(pid, &status, 0); - return (status); - } -} - -void -check_shadow(const struct passwd *pw, const struct spwd *sp) -{ - long today; - - today = time(0)/(24L * 60 * 60); - - if (sp == NULL) - return; - - if (sp->sp_expire > 0) { - if (today >= sp->sp_expire) { - printf("Your account has expired.\n"); - sleep(1); - exit(0); - } else if (sp->sp_expire - today < 14) { - printf("Your account will expire in %d days.\n", - (int)(sp->sp_expire - today)); - } - } - - if (sp->sp_max > 0) { - if (today >= (sp->sp_lstchg + sp->sp_max)) { - printf("Your password has expired. Choose a new one.\n"); - change_passwd(pw); - } else if (sp->sp_warn > 0 - && (today > (sp->sp_lstchg + sp->sp_max - sp->sp_warn))) { - printf("Your password will expire in %d days.\n", - (int)(sp->sp_lstchg + sp->sp_max - today)); - } - } -} -#endif /* HAVE_SHADOW_H */ diff --git a/appl/login/utmp_login.c b/appl/login/utmp_login.c deleted file mode 100644 index da3d726da..000000000 --- a/appl/login/utmp_login.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "login_locl.h" - -RCSID("$Id$"); - -/* try to put something useful from hostname into dst, dst_sz: - * full name, first component or address */ - -void -shrink_hostname (const char *hostname, - char *dst, size_t dst_sz) -{ - char local_hostname[MaxHostNameLen]; - char *ld, *hd; - int ret; - struct addrinfo *ai; - - if (strlen(hostname) < dst_sz) { - strlcpy (dst, hostname, dst_sz); - return; - } - gethostname (local_hostname, sizeof(local_hostname)); - hd = strchr (hostname, '.'); - ld = strchr (local_hostname, '.'); - if (hd != NULL && ld != NULL && strcmp(hd, ld) == 0 - && hd - hostname < dst_sz) { - strlcpy (dst, hostname, dst_sz); - dst[hd - hostname] = '\0'; - return; - } - - ret = getaddrinfo (hostname, NULL, NULL, &ai); - if (ret) { - strncpy (dst, hostname, dst_sz); - return; - } - ret = getnameinfo (ai->ai_addr, ai->ai_addrlen, - dst, dst_sz, - NULL, 0, - NI_NUMERICHOST); - freeaddrinfo (ai); - if (ret) { - strncpy (dst, hostname, dst_sz); - return; - } -} - -/* update utmp and wtmp - the BSD way */ - -#if !defined(HAVE_UTMPX_H) || (defined(WTMP_FILE) && !defined(WTMPX_FILE)) - -void -prepare_utmp (struct utmp *utmp, char *tty, - const char *username, const char *hostname) -{ - char *ttyx = clean_ttyname (tty); - - memset(utmp, 0, sizeof(*utmp)); - utmp->ut_time = time(NULL); - strncpy(utmp->ut_line, ttyx, sizeof(utmp->ut_line)); - strncpy(utmp->ut_name, username, sizeof(utmp->ut_name)); - -# ifdef HAVE_STRUCT_UTMP_UT_USER - strncpy(utmp->ut_user, username, sizeof(utmp->ut_user)); -# endif - -# ifdef HAVE_STRUCT_UTMP_UT_ADDR - if (hostname[0]) { - struct hostent *he; - if ((he = gethostbyname(hostname))) - memcpy(&utmp->ut_addr, he->h_addr_list[0], - sizeof(utmp->ut_addr)); - } -# endif - -# ifdef HAVE_STRUCT_UTMP_UT_HOST - shrink_hostname (hostname, utmp->ut_host, sizeof(utmp->ut_host)); -# endif - -# ifdef HAVE_STRUCT_UTMP_UT_TYPE - utmp->ut_type = USER_PROCESS; -# endif - -# ifdef HAVE_STRUCT_UTMP_UT_PID - utmp->ut_pid = getpid(); -# endif - -# ifdef HAVE_STRUCT_UTMP_UT_ID - strncpy(utmp->ut_id, make_id(ttyx), sizeof(utmp->ut_id)); -# endif -} -#endif - -#ifdef HAVE_UTMPX_H -void utmp_login(char *tty, const char *username, const char *hostname) -{ - return; -} -#else - -void utmp_login(char *tty, const char *username, const char *hostname) -{ - struct utmp utmp; - int fd; - - prepare_utmp (&utmp, tty, username, hostname); - -#ifdef HAVE_SETUTENT - utmpname(_PATH_UTMP); - setutent(); - pututline(&utmp); - endutent(); -#else - -#ifdef HAVE_TTYSLOT - { - int ttyno; - ttyno = ttyslot(); - if (ttyno > 0 && (fd = open(_PATH_UTMP, O_WRONLY, 0)) >= 0) { - lseek(fd, (long)(ttyno * sizeof(struct utmp)), SEEK_SET); - write(fd, &utmp, sizeof(struct utmp)); - close(fd); - } - } -#endif /* HAVE_TTYSLOT */ -#endif /* HAVE_SETUTENT */ - - if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) >= 0) { - write(fd, &utmp, sizeof(struct utmp)); - close(fd); - } -} - -#endif /* !HAVE_UTMPX_H */ diff --git a/appl/login/utmpx_login.c b/appl/login/utmpx_login.c deleted file mode 100644 index 8a3f88b60..000000000 --- a/appl/login/utmpx_login.c +++ /dev/null @@ -1,105 +0,0 @@ -/************************************************************************ -* Copyright 1995 by Wietse Venema. All rights reserved. Some individual -* files may be covered by other copyrights. -* -* This material was originally written and compiled by Wietse Venema at -* Eindhoven University of Technology, The Netherlands, in 1990, 1991, -* 1992, 1993, 1994 and 1995. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that this entire copyright notice -* is duplicated in all such copies. -* -* This software is provided "as is" and without any expressed or implied -* warranties, including, without limitation, the implied warranties of -* merchantibility and fitness for any particular purpose. -************************************************************************/ -/* Author: Wietse Venema */ - -#include "login_locl.h" - -RCSID("$Id$"); - -/* utmpx_login - update utmp and wtmp after login */ - -#ifndef HAVE_UTMPX_H -int utmpx_login(char *line, const char *user, const char *host) { return 0; } -#else - -static void -utmpx_update(struct utmpx *ut, char *line, const char *user, const char *host) -{ - struct timeval tmp; - char *clean_tty = clean_ttyname(line); - - strncpy(ut->ut_line, clean_tty, sizeof(ut->ut_line)); -#ifdef HAVE_STRUCT_UTMPX_UT_ID - strncpy(ut->ut_id, make_id(clean_tty), sizeof(ut->ut_id)); -#endif - strncpy(ut->ut_user, user, sizeof(ut->ut_user)); - shrink_hostname (host, ut->ut_host, sizeof(ut->ut_host)); -#ifdef HAVE_STRUCT_UTMPX_UT_SYSLEN - ut->ut_syslen = strlen(host) + 1; - if (ut->ut_syslen > sizeof(ut->ut_host)) - ut->ut_syslen = sizeof(ut->ut_host); -#endif - ut->ut_type = USER_PROCESS; - gettimeofday (&tmp, 0); - ut->ut_tv.tv_sec = tmp.tv_sec; - ut->ut_tv.tv_usec = tmp.tv_usec; - pututxline(ut); -#ifdef WTMPX_FILE - updwtmpx(WTMPX_FILE, ut); -#elif defined(WTMP_FILE) - { /* XXX should be removed, just drop wtmp support */ - struct utmp utmp; - int fd; - - prepare_utmp (&utmp, line, user, host); - if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) >= 0) { - write(fd, &utmp, sizeof(struct utmp)); - close(fd); - } - } -#endif -} - -int -utmpx_login(char *line, const char *user, const char *host) -{ - struct utmpx *ut, save_ut; - pid_t mypid = getpid(); - int ret = (-1); - - /* - * SYSV4 ttymon and login use tty port names with the "/dev/" prefix - * stripped off. Rlogind and telnetd, on the other hand, make utmpx - * entries with device names like /dev/pts/nnn. We therefore cannot use - * getutxline(). Return nonzero if no utmp entry was found with our own - * process ID for a login or user process. - */ - - while ((ut = getutxent())) { - /* Try to find a reusable entry */ - if (ut->ut_pid == mypid - && ( ut->ut_type == INIT_PROCESS - || ut->ut_type == LOGIN_PROCESS - || ut->ut_type == USER_PROCESS)) { - save_ut = *ut; - utmpx_update(&save_ut, line, user, host); - ret = 0; - break; - } - } - if (ret == -1) { - /* Grow utmpx file by one record. */ - struct utmpx newut; - memset(&newut, 0, sizeof(newut)); - newut.ut_pid = mypid; - utmpx_update(&newut, line, user, host); - ret = 0; - } - endutxent(); - return (ret); -} -#endif /* HAVE_UTMPX_H */ diff --git a/appl/otp/Makefile.am b/appl/otp/Makefile.am index e5d7246d9..d8e5d51dd 100644 --- a/appl/otp/Makefile.am +++ b/appl/otp/Makefile.am @@ -2,17 +2,14 @@ include $(top_srcdir)/Makefile.am.common -AM_CPPFLAGS += $(INCLUDE_hcrypto) - bin_PROGRAMS = otp otpprint bin_SUIDS = otp otp_SOURCES = otp.c otp_locl.h +otp_LDADD = $(LIB_hcrypto) $(LIB_roken) $(top_builddir)/lib/otp/libotp.la otpprint_SOURCES = otpprint.c otp_locl.h +otpprint_LDADD = $(LIB_hcrypto) $(LIB_roken) $(top_builddir)/lib/otp/libotp.la + man_MANS = otp.1 otpprint.1 -LDADD = \ - $(top_builddir)/lib/otp/libotp.la \ - $(LIB_roken) - -EXTRA_DIST = $(man_MANS) +EXTRA_DIST = NTMakefile $(man_MANS) diff --git a/appl/otp/NTMakefile b/appl/otp/NTMakefile new file mode 100644 index 000000000..625630993 --- /dev/null +++ b/appl/otp/NTMakefile @@ -0,0 +1,35 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=appl\otp + +!include ../../windows/NTMakefile.w32 + diff --git a/appl/otp/otp.1 b/appl/otp/otp.1 index e96243edd..86769486e 100644 --- a/appl/otp/otp.1 +++ b/appl/otp/otp.1 @@ -1,34 +1,34 @@ .\" Copyright (c) 1996, 2000 Kungliga Tekniska Högskolan -.\" (Royal Institute of Technology, Stockholm, Sweden). -.\" All rights reserved. +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. .\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: .\" -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. .\" -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. .\" -.\" 3. Neither the name of the Institute nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. .\" -.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" .\" $Id$ .\" .Dd November 17, 1996 @@ -36,8 +36,7 @@ .Os KTH-KRB .Sh NAME .Nm otp -.Nd -manages one-time passwords +.Nd manages one-time passwords .Sh SYNOPSIS .Nm otp .Op Fl dhlor diff --git a/appl/otp/otp.c b/appl/otp/otp.c index ef3e4ab15..deb7d303c 100644 --- a/appl/otp/otp.c +++ b/appl/otp/otp.c @@ -46,16 +46,16 @@ static int version_flag; static int help_flag; struct getargs args[] = { - { "list", 'l', arg_flag, &listp, "list OTP status" }, - { "delete", 'd', arg_flag, &deletep, "delete OTP" }, - { "open", 'o', arg_flag, &openp, "open a locked OTP" }, - { "renew", 'r', arg_flag, &renewp, "securely renew OTP" }, + { "list", 'l', arg_flag, &listp, "list OTP status", NULL }, + { "delete", 'd', arg_flag, &deletep, "delete OTP", NULL }, + { "open", 'o', arg_flag, &openp, "open a locked OTP", NULL }, + { "renew", 'r', arg_flag, &renewp, "securely renew OTP", NULL }, { "hash", 'f', arg_string, &alg_string, "hash algorithm (md4, md5, or sha)", "algorithm"}, { "user", 'u', arg_string, &user, "user other than current user (root only)", "user" }, - { "version", 0, arg_flag, &version_flag }, - { "help", 'h', arg_flag, &help_flag } + { "version", 0, arg_flag, &version_flag, NULL, NULL }, + { "help", 'h', arg_flag, &help_flag, NULL, NULL } }; int num_args = sizeof(args) / sizeof(args[0]); @@ -73,7 +73,7 @@ usage(int code) */ static int -renew (int argc, char **argv, OtpAlgorithm *alg, char *user) +renew (int argc, char **argv, OtpAlgorithm *alg, char *inuser) { OtpContext newctx, *ctx; char prompt[128]; @@ -82,7 +82,7 @@ renew (int argc, char **argv, OtpAlgorithm *alg, char *user) int ret; newctx.alg = alg; - newctx.user = user; + newctx.user = inuser; newctx.n = atoi (argv[0]); strlcpy (newctx.seed, argv[1], sizeof(newctx.seed)); strlwr(newctx.seed); @@ -118,16 +118,22 @@ verify_user_otp(char *username) { OtpContext ctx; char passwd[OTP_MAX_PASSPHRASE + 1]; - char prompt[128], ss[256]; + char ss[256]; + char *prompt = NULL; if (otp_challenge (&ctx, username, ss, sizeof(ss)) != 0) { warnx("no otp challenge found for %s", username); return 1; } - snprintf (prompt, sizeof(prompt), "%s's %s Password: ", username, ss); - if(UI_UTIL_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)) + if (asprintf(&prompt, "%s's %s Password: ", username, ss) == -1 || + prompt == NULL) + err(1, "out of memory"); + if (UI_UTIL_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)) { + free(prompt); return 1; + } + free(prompt); return otp_verify_user (&ctx, passwd); } @@ -136,7 +142,7 @@ verify_user_otp(char *username) */ static int -set (int argc, char **argv, OtpAlgorithm *alg, char *user) +set (int argc, char **argv, OtpAlgorithm *alg, char *inuser) { void *db; OtpContext ctx; @@ -145,7 +151,7 @@ set (int argc, char **argv, OtpAlgorithm *alg, char *user) int i; ctx.alg = alg; - ctx.user = strdup (user); + ctx.user = strdup (inuser); if (ctx.user == NULL) err (1, "out of memory"); @@ -153,7 +159,8 @@ set (int argc, char **argv, OtpAlgorithm *alg, char *user) strlcpy (ctx.seed, argv[1], sizeof(ctx.seed)); strlwr(ctx.seed); do { - if (UI_UTIL_read_pw_string (pw, sizeof(pw), "Pass-phrase: ", 1)) + if (UI_UTIL_read_pw_string (pw, sizeof(pw), "Pass-phrase: ", + UI_UTIL_FLAG_VERIFY)) return 1; if (strlen (pw) < OTP_MIN_PASSPHRASE) printf ("Too short pass-phrase. Use at least %d characters\n", @@ -178,7 +185,7 @@ set (int argc, char **argv, OtpAlgorithm *alg, char *user) */ static int -delete_otp (int argc, char **argv, char *user) +delete_otp (int argc, char **argv, char *inuser) { void *db; OtpContext ctx; @@ -188,7 +195,7 @@ delete_otp (int argc, char **argv, char *user) if(db == NULL) errx (1, "otp_db_open failed"); - ctx.user = user; + ctx.user = inuser; ret = otp_delete(db, &ctx); otp_db_close (db); return ret; @@ -199,7 +206,7 @@ delete_otp (int argc, char **argv, char *user) */ static int -has_an_otp(char *user) +has_an_otp(char *inuser) { void *db; OtpContext ctx; @@ -211,7 +218,7 @@ has_an_otp(char *user) return 0; /* if no db no otp! */ } - ctx.user = user; + ctx.user = inuser; ret = otp_simple_get(db, &ctx); otp_db_close (db); @@ -223,11 +230,11 @@ has_an_otp(char *user) */ static void -print_otp_entry_for_name (void *db, char *user) +print_otp_entry_for_name (void *db, char *inuser) { OtpContext ctx; - ctx.user = user; + ctx.user = inuser; if (!otp_simple_get(db, &ctx)) { fprintf(stdout, "%s\totp-%s %d %s", @@ -242,7 +249,7 @@ print_otp_entry_for_name (void *db, char *user) } static int -open_otp (int argc, char **argv, char *user) +open_otp (int argc, char **argv, char *inuser) { void *db; OtpContext ctx; @@ -252,7 +259,7 @@ open_otp (int argc, char **argv, char *user) if (db == NULL) errx (1, "otp_db_open failed"); - ctx.user = user; + ctx.user = inuser; ret = otp_simple_get (db, &ctx); if (ret == 0) ret = otp_put (db, &ctx); @@ -265,7 +272,7 @@ open_otp (int argc, char **argv, char *user) */ static int -list_otps (int argc, char **argv, char *user) +list_otps (int argc, char **argv, char *inuser) { void *db; struct passwd *pw; @@ -274,8 +281,8 @@ list_otps (int argc, char **argv, char *user) if(db == NULL) errx (1, "otp_db_open failed"); - if (user) - print_otp_entry_for_name(db, user); + if (inuser) + print_otp_entry_for_name(db, inuser); else /* scans all users... so as to get a deterministic order */ while ((pw = getpwent())) @@ -291,10 +298,11 @@ main (int argc, char **argv) int defaultp = 0; int uid = getuid(); OtpAlgorithm *alg = otp_find_alg (OTP_ALG_DEFAULT); - int optind = 0; + int optidx = 0; + char userbuf[128]; setprogname (argv[0]); - if(getarg(args, num_args, argc, argv, &optind)) + if(getarg(args, num_args, argc, argv, &optidx)) usage(1); if(help_flag) usage(0); @@ -312,8 +320,8 @@ main (int argc, char **argv) } if (user && uid != 0) errx (1, "Only root can use `-u'"); - argc -= optind; - argv += optind; + argc -= optidx; + argv += optidx; if (!(listp || deletep || renewp || openp)) defaultp = 1; @@ -332,12 +340,9 @@ main (int argc, char **argv) return list_otps (argc, argv, user); if (user == NULL) { - struct passwd *pwd; - - pwd = k_getpwuid(uid); - if (pwd == NULL) + user = roken_get_username(userbuf, sizeof(userbuf)); + if (user == NULL) err (1, "You don't exist"); - user = pwd->pw_name; } /* @@ -350,7 +355,7 @@ main (int argc, char **argv) errx (1, "Only root can set an initial OTP"); } else { /* Check the next OTP (RFC 1938/8.0: SHOULD) */ if (verify_user_otp(user) != 0) { - errx (1, "User authentification failed"); + errx (1, "User authentication failed"); } } } diff --git a/appl/otp/otpprint.1 b/appl/otp/otpprint.1 index 1cf6cd049..804593398 100644 --- a/appl/otp/otpprint.1 +++ b/appl/otp/otpprint.1 @@ -1,34 +1,34 @@ .\" Copyright (c) 1996, 2000 - 2001 Kungliga Tekniska Högskolan -.\" (Royal Institute of Technology, Stockholm, Sweden). -.\" All rights reserved. +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. .\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: .\" -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. .\" -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. .\" -.\" 3. Neither the name of the Institute nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. .\" -.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" .\" $Id$ .\" .Dd November 17, 1996 @@ -36,8 +36,7 @@ .Os KTH-KRB .Sh NAME .Nm otpprint -.Nd -print lists of one-time passwords +.Nd print lists of one-time passwords .Sh SYNOPSIS .Nm otp .Op Fl n Ar count diff --git a/appl/otp/otpprint.c b/appl/otp/otpprint.c index 662afeb46..1c9c33930 100644 --- a/appl/otp/otpprint.c +++ b/appl/otp/otpprint.c @@ -44,13 +44,14 @@ static int version_flag; static int help_flag; struct getargs args[] = { - { "extended", 'e', arg_flag, &extendedp, "print keys in extended format" }, - { "count", 'n', arg_integer, &count, "number of keys to print" }, - { "hexadecimal", 'h', arg_flag, &hexp, "output in hexadecimal" }, + { "extended", 'e', arg_flag, &extendedp, "print keys in extended format", + NULL }, + { "count", 'n', arg_integer, &count, "number of keys to print", NULL }, + { "hexadecimal", 'h', arg_flag, &hexp, "output in hexadecimal", NULL }, { "hash", 'f', arg_string, &alg_string, "hash algorithm (md4, md5, or sha)", "algorithm"}, - { "version", 0, arg_flag, &version_flag }, - { "help", 0, arg_flag, &help_flag } + { "version", 0, arg_flag, &version_flag, NULL, NULL }, + { "help", 0, arg_flag, &help_flag, NULL, NULL } }; int num_args = sizeof(args) / sizeof(args[0]); @@ -65,7 +66,7 @@ usage(int code) static int print (int argc, char **argv, - int count, + int incount, OtpAlgorithm *alg, void (*print_fn)(OtpKey, char *, size_t)) { @@ -86,7 +87,7 @@ print (int argc, char s[64]; alg->next (key); - if (i >= n - count) { + if (i >= n - incount) { (*print_fn)(key, s, sizeof(s)); printf ("%d: %s\n", i + 1, s); } @@ -97,12 +98,12 @@ print (int argc, int main (int argc, char **argv) { - int optind = 0; + int optidx = 0; void (*fn)(OtpKey, char *, size_t); OtpAlgorithm *alg = otp_find_alg (OTP_ALG_DEFAULT); setprogname (argv[0]); - if(getarg(args, num_args, argc, argv, &optind)) + if(getarg(args, num_args, argc, argv, &optidx)) usage(1); if(help_flag) usage(0); @@ -116,8 +117,8 @@ main (int argc, char **argv) if (alg == NULL) errx(1, "Unknown algorithm: %s", alg_string); } - argc -= optind; - argv += optind; + argc -= optidx; + argv += optidx; if (hexp) { if (extendedp) diff --git a/appl/popper/ChangeLog b/appl/popper/ChangeLog deleted file mode 100644 index b5d2d7571..000000000 --- a/appl/popper/ChangeLog +++ /dev/null @@ -1,269 +0,0 @@ -2006-11-20 Love Hörnquist Åstrand - - * pop_pass.c: Make krb5_get_init_creds_opt_free take a context - argument. - -2006-10-07 Love Hörnquist Åstrand - - * Makefile.am: Add man_MANS to EXTRA_DIST - -2006-05-05 Love Hörnquist Åstrand - - * Rename u_intXX_t to uintXX_t - -2005-10-22 Love Hörnquist Åstrand - - * pop_dropinfo.c: Check return value from asprintf instead of - string != NULL since it undefined behavior on Linux. From Björn - Sandell - -2005-05-29 Love Hörnquist Åstrand - - * pop_user.c: avoid 'unused variable' warnings - -2005-05-10 Dave Love - - * pop_pass.c: Include . - -2004-08-27 Johan Danielsson - - * popper.c: add message to NOOP result to appease gcc - -2004-06-14 Johan Danielsson - - * Makefile.am: SASL - - * pop_auth.[ch], auth_gssapi.c, auth_krb4.c : improved SASL - support - - * pop_get_command.c: add SASL hooks - - * pop_user.c: if using SASL, don't allow plaintext USER/PASS - - * pop_init.c: recognise sasl auth level - - * popper.h: add AUTH_SASL flag - -2003-12-20 Love Hörnquist Åstrand - - * popper.c (main): avoid warning by sending empty string as - formatstring instead of NULL (even though pop_msg handles that - too) - -2003-10-10 Johan Danielsson - - * pop_init.c (pop_init): change call to authentication function, - from a ?: construct (which toubles some versions of gcc) to if; - from Björn Grönvall - -2003-09-03 Love Hörnquist Åstrand - - * pop_pass.c: use - krb5_get_init_creds_opt_alloc/krb5_get_init_creds_opt_free - -2003-09-02 Love Hörnquist Åstrand - - * popper.c (tgets): avoid be clobbered by `longjmp' or `vfork' - warning - -2003-04-16 Love Hörnquist Åstrand - - * popper.8: spelling, from jmc - -2002-07-04 Johan Danielsson - - * pop_dropcopy.c: use RESP-CODES - - * pop_get_command.c: implement CAPA - - * popper.c: don't print our version in the greeting string - - * popper.h: add a flags parameter to the pop context - -2002-05-02 Johan Danielsson - - * pop_debug.c: revert some accidentally commited code in previous - -2002-02-07 Johan Danielsson - - * pop_debug.c: only claim krb5 support if really present - -2001-09-10 Johan Danielsson - - * maildir.c: replace MAXDROPLEN with MAXPATHLEN - - * popper.h: replace MAXDROPLEN with MAXPATHLEN - -2001-08-13 Johan Danielsson - - * popper.8: rewritten man page - -2000-12-31 Assar Westerlund - - * pop_init.c (pop_init): handle krb5_init_context failure - consistently - * pop_debug.c (doit_v5): handle krb5_init_context failure - consistently - -2000-06-10 Assar Westerlund - - * pop_init.c (krb4_authenticate): do not exit on failure, just - return - (krb5_authenticate): log errors from krb5_recvauth - -2000-04-12 Assar Westerlund - - * *.c: replace all erroneous calls to pop_log with POP_FAILURE - with POP_PRIORITY. reported by Janne Johansson ' - -2000-01-27 Assar Westerlund - - * pop_debug.c (main): figure out port number - -1999-12-20 Assar Westerlund - - * pop_init.c (pop_init): use getnameinfo_verified - - * pop_debug.c (get_socket): use getaddrinfo - -1999-12-03 Johan Danielsson - - * pop_init.c: optionally trace connected addresses to a file - -1999-11-02 Assar Westerlund - - * pop_debug.c (main): redo the v4/v5 selection for consistency. - -4 -> try only v4 -5 -> try only v5 none, -45 -> try v5, v4 - -1999-10-16 Johan Danielsson - - * pop_init.c (krb5_authenticate): don't use the principal - associated with the socket for authentication, instead let - krb5_rd_req pick the correct one from the ticket; just check that - it actually was a pop-ticket - -1999-08-12 Johan Danielsson - - * pop_init.c (pop_init): don't freehostent if ch == NULL - - * pop_dele.c: implement XDELE to delete a range of messages - -1999-08-05 Assar Westerlund - - * pop_init.c: v6-ify - - * pop_debug.c: v6-ify - -1999-05-10 Assar Westerlund - - * pop_debug.c (doit_v5): call krb5_sendauth with ccache == NULL - -1999-04-11 Assar Westerlund - - * pop_debug.c (main): use print_version - -Thu Apr 8 15:07:11 1999 Johan Danielsson - - * pop_pass.c: remove definition of KRB_VERIFY_USER (moved to - config.h) - -Thu Mar 18 12:55:42 1999 Johan Danielsson - - * pop_pass.c: define KRB_VERIFY_SECURE if not defined - - * Makefile.am: include Makefile.am.common - -Wed Mar 17 23:36:21 1999 Assar Westerlund - - * pop_pass.c (krb4_verify_password): use KRB_VERIFY_SECURE instead - of 1 - -Tue Mar 16 22:28:52 1999 Assar Westerlund - - * pop_pass.c: krb_verify_user_multiple -> krb_verify_user - -Sat Mar 13 22:17:29 1999 Assar Westerlund - - * pop_parse.c (pop_parse): cast when calling is* to get rid of a - warning - -Mon Mar 8 11:50:06 1999 Johan Danielsson - - * pop_init.c: use print_version - -Fri Mar 5 15:14:29 1999 Johan Danielsson - - * pop_send.c: fix handling of messages w/o body - -Sun Nov 22 10:33:29 1998 Assar Westerlund - - * pop_pass.c (pop_pass): try to always log - - * Makefile.in (WFLAGS): set - -Fri Jul 10 01:14:25 1998 Assar Westerlund - - * pop_init.c: s/net_read/pop_net_read/ - -Tue Jun 2 17:33:54 1998 Johan Danielsson - - * pop_send.c: add missing newlines - -Sun May 24 20:59:45 1998 Johan Danielsson - - * maildir.c (make_path): fix reversed args - -Sat May 16 00:02:18 1998 Assar Westerlund - - * Makefile.am: link with DBLIB - -Sun Apr 26 11:47:58 1998 Assar Westerlund - - * pop_pass.c (pop_pass): check return value from changeuser - - * pop_dropcopy.c (changeuser): check that `setuid' and `setgid' - succeeded. - - * popper.h: changeuser now returns int - -Thu Apr 23 00:54:38 1998 Johan Danielsson - - * Add support for maildir spoolfiles. - - * popper.h (MsgInfoList): replace `del_flag' and `retr_flag' with - single `flags' - - * pop_dropcopy.c: Fix mismatched parenthesis. - -Sat Apr 4 15:13:56 1998 Assar Westerlund - - * pop_dropcopy.c (pop_dropcopy): first do mkstemp and then fdopen. - Originally from - - * popper.h: include - -Sat Feb 7 10:07:39 1998 Assar Westerlund - - * pop_pass.c(krb4_verify_password: Don't use REALM_SZ + 1, just - REALM_SZ - -Mon Dec 29 16:37:26 1997 Assar Westerlund - - * pop_updt.c (pop_updt): lseek before ftruncating the file. From - - -Sat Nov 22 13:46:39 1997 Johan Danielsson - - * pop_pass.c: Destroy tickets after verification. - -Sun Nov 9 09:11:14 1997 Assar Westerlund - - * pop_dropinfo.c: be careful with mails without msg-id, subject, - or from - -Wed Oct 29 02:09:24 1997 Assar Westerlund - - * pop_pass.c: conditionalize OTP-support - - * pop_init.c: conditionalize OTP-support - diff --git a/appl/popper/Makefile.am b/appl/popper/Makefile.am deleted file mode 100644 index 10075a2bd..000000000 --- a/appl/popper/Makefile.am +++ /dev/null @@ -1,49 +0,0 @@ -# $Id$ - -include $(top_srcdir)/Makefile.am.common - -noinst_PROGRAMS = pop_debug - -libexec_PROGRAMS = popper - -popper_SOURCES = \ - pop_auth.c \ - pop_auth.h \ - pop_dele.c \ - pop_dropcopy.c \ - pop_dropinfo.c \ - pop_get_command.c \ - pop_init.c \ - pop_last.c \ - pop_list.c \ - pop_log.c \ - pop_msg.c \ - pop_parse.c \ - pop_pass.c \ - pop_quit.c \ - pop_rset.c \ - pop_send.c \ - pop_stat.c \ - pop_uidl.c \ - pop_updt.c \ - pop_user.c \ - pop_xover.c \ - popper.c \ - maildir.c \ - auth_gssapi.c \ - popper.h \ - version.h - -LDADD = \ - $(LIB_otp) \ - $(top_builddir)/lib/gssapi/libgssapi.la \ - $(LIB_krb5) \ - $(LIB_hcrypto) \ - $(LIB_roken) \ - $(DBLIB) - -man_MANS = popper.8 - -EXTRA_DIST = pop3.rfc1081 pop3e.rfc1082 \ - popper.README.release README-FIRST \ - $(man_MANS) diff --git a/appl/popper/README b/appl/popper/README deleted file mode 100644 index 0735fdd56..000000000 --- a/appl/popper/README +++ /dev/null @@ -1,381 +0,0 @@ -@(#)@(#)README 2.6 2.6 4/2/91 - - -The Post Office Protocol Server: Installation Guide - - - -Introduction - -The Post Office Protocol server runs on a variety of Unix[1] computers -to manage electronic mail for Macintosh and MS-DOS computers. The -server was developed at the University of California at Berkeley and -conforms fully to the specifications in RFC 1081[2] and RFC 1082[3]. -The Berkeley server also has extensions to send electronic mail on -behalf of a client. - -This guide explains how to install the POP server on your Unix -computer. It assumes that you are not only familiar with Unix but also -capable of performing Unix system administration. - - -How to Obtain the Server - -The POP server is available via anonymous ftp from ftp.CC.Berkeley.EDU -(128.32.136.9, 128.32.206.12). It is in two files in the pub directory: -a compressed tar file popper-version.tar.Z and a Macintosh StuffIt archive -in BinHex format called MacPOP.sit.hqx. - - -Contents of the Distribution - -The distribution contains the following: - -+ All of the C source necessary to create the server program. - -+ A visual representation of how the POP system works. - -+ Reprints of RFC 1081 and RFC 1082. - -+ A HyperCard stack POP client implementation using MacTCP. - -+ A man page for the popper daemon. - -+ This guide. - - -Compatibility - -The Berkeley POP server has been successfully tested on the following -Unix operating systems: - -+ Berkeley Systems Distribution 4.3 - -+ Sun Microsystems Operating System versions 3.5 and 4.0 - -+ Ultrix version 2.3 - -The following POP clients operate correctly with the Berkeley POP server: - -+ The Berkeley HyperMail HyperCard stack for the Apple Macintosh - (distributed with the server). - -+ The Stanford University Macintosh Internet Protocol MacMH program. - -+ The Stanford University Personal Computer Internet Protocol MH - program. - -+ The mh version 6.0 programs for Unix. - - -Support - -The Berkeley POP server is not officially supported and is without any -warranty, explicit or implied. However, we are interested in your -experiences using the server. Bugs, comments and suggestions should be -sent electronically to netinfo@garnet.Berkeley.EDU. - - -Operational Characteristics - -The POP Transaction Cycle - -The Berkeley POP server is a single program (called popper) that is -launched by inetd when it gets a service request on the POP TCP port. -(The official port number specified in RFC 1081 for POP version 3 is -port 110. However, some POP3 clients attempt to contact the server at -port 109, the POP version 2 port. Unless you are running both POP2 and -POP3 servers, you can simply define both ports for use by the POP3 -server. This is explained in the installation instructions later on.) -The popper program initializes and verifies that the peer IP address is -registered in the local domain, logging a warning message when a -connection is made to a client whose IP address does not have a -canonical name. For systems using BSD 4.3 bind, it also checks to see -if a cannonical name lookup for the client returns the same peer IP -address, logging a warning message if it does not. The the server -enters the authorization state, during which the client must correctly -identify itself by providing a valid Unix userid and password on the -server's host machine. No other exchanges are allowed during this -state (other than a request to quit.) If authentication fails, a -warning message is logged and the session ends. Once the user is -identified, popper changes its user and group ids to match that of the -user and enters the transaction state. The server makes a temporary -copy of the user's maildrop (ordinarily in /usr/spool/mail) which is -used for all subsequent transactions. These include the bulk of POP -commands to retrieve mail, delete mail, undelete mail, and so forth. A -Berkeley extension also allows the user to submit a mail parcel to the -server who mails it using the sendmail program (this extension is -supported in the HyperMail client distributed with the server). When -the client quits, the server enters the final update state during which -the network connection is terminated and the user's maildrop is updated -with the (possibly) modified temporary maildrop. - - -Logging - -The POP server uses syslog to keep a record of its activities. On -systems with BSD 4.3 syslogging, the server logs (by default) to the -"local0" facility at priority "notice" for all messages except -debugging which is logged at priority "debug". The default log file is -/usr/spool/mqueue/POPlog. These can be changed, if desired. On -systems with 4.2 syslogging all messages are logged to the local log -file, usually /usr/spool/mqueue/syslog. - -Problems - -If the filesystem which holds the /usr/spool/mail fills up users will -experience difficulties. The filesystem must have enough space to hold -(approximately) two copies of the largest mail box. Popper (v1.81 and -above) is designed to be robust in the face of this problem, but you may -end up with a situation where some of the user's mail is in - - /usr/spool/mail/.userid.pop - -and some of the mail is in - - /usr/spool/mail/userid - -If this happens the System Administrator should clear enough disk space -so that the filesystem has at least as much free disk as both mailboxes -hold and probably a little more. Then the user should initiate a POP -session, and do nothing but quit. If the POP session ends without an -error the user can then use POP or another mail program to clean up his/her -mailbox. - -Alternatively, the System Administrator can combine the two files (but -popper will do this for you if there is enough disk space). - - -Debugging - -The popper program will log debugging information when the -d parameter -is specified after its invocation in the inetd.conf file. Care should -be exercised in using this option since it generates considerable -output in the syslog file. Alternatively, the "-t " option -will place debugging information into file "" using fprintf -instead of syslog. (To enable debugging, you must edit the Makefile -to add -DDEBUG to the compiler options.) - -For SunOS version 3.5, the popper program is launched by inetd from -/etc/servers. This file does not allow you to specify command line -arguments. Therefore, if you want to enable debugging, you can specify -a shell script in /etc/servers to be launched instead of popper and in -this script call popper with the desired arguments. - - -Installation - -1. Examine this file for the latest information, warnings, etc. - -2. Check the Makefile for conformity with your system. - -3. Issue the make command in the directory containing the popper - source. - -4. Issue the make install command in the directory containing the - popper source to copy the program to /usr/etc. - -5. Enable syslogging: - - + For systems with 4.3 syslogging: - - Add the following line to the /etc/syslog.conf file: - - local0.notice;local0.debug /usr/spool/mqueue/POPlog - - Create the empty file /usr/spool/mqueue/POPlog. - - Kill and restart the syslogd daemon. - - + For systems with 4.2 syslogging: - - Be sure that you are logging messages of priority 7 and higher. - For example: - - 7/usr/spool/mqueue/syslog - 9/dev/null - -6. Update /etc/services: - - Add the following line to the /etc/services file: - - pop 110/tcp - - Note: This is the official port number for version 3 of the - Post Office Protocol as defined in RFC 1081. However, some - POP3 clients use port 109, the port number for the previous - version (2) of POP. Therefore you may also want to add the - following line to the /etc/services file: - - pop2 109/tcp - - For Sun systems running yp, also do the following: - - + Change to the /var/yp directory. - - + Issue the make services command. - -7. Update the inetd daemon configuration. Include the second line ONLY if you - are running the server at both ports. - - + On BSD 4.3 and SunOS 4.0 systems, add the following line to the - /etc/inetd.conf file: - - pop stream tcp nowait root /usr/etc/popper popper - pop2 stream tcp nowait root /usr/etc/popper popper - - + On Ultrix systems, add the following line to the - /etc/inetd.conf file: - - pop stream tcp nowait /usr/etc/popper popper - pop2 stream tcp nowait /usr/etc/popper popper - - + On SunOS 3.5 systems, add the following line to the - /etc/servers file: - - pop tcp /usr/etc/popper - pop2 tcp /usr/etc/popper - - Kill and restart the inetd daemon. - -You can confirm that the POP server is running on Unix by telneting to -port 110 (or 109 if you set it up that way). For example: - -%telnet myhost 110 -Trying... -Connected to myhost.berkeley.edu. -Escape character is '^]'. -+OK UCB Pop server (version 1.6) at myhost starting. -quit -Connection closed by foreign host. - - -Release Notes - -1.83 Make sure that everything we do as root is non-destructive. - -1.82 Make the /usr/spool/mail/.userid.pop file owned by the user rather - than owned by root. - -1.81 There were two versions of 1.7 floating around, 1.7b4 and 1.7b5. - The difference is that 1.7b5 attempted to save disk space on - /usr/spool/mail by deleting the users permanent maildrop after - making the temporary copy. Unfortunately, if compiled with - -DDEBUG, this version could easily wipe out a users' mail file. - This is now fixed. - - This version also fixes a security hole for systems that have - /usr/spool/mail writeable by all users. - - With this version we go to all new SCCS IDs for all files. This - is unfortunate, and we hope it is not too much of a problem. - - Thanks to Steve Dorner of UIUC for pointing out the major problem. - -1.7 Extensive re-write of the maildrop processing code contributed by - Viktor Dukhovni that greatly reduces the - possibility that the maildrop can be corrupted as the result of - simultaneous access by two or more processes. - - Added "pop_dropcopy" module to create a temporary maildrop from - the existing, standard maildrop as root before the setuid and - setgid for the user is done. This allows the temporary maildrop - to be created in a mail spool area that is not world read-writable. - - This version does *not* send the sendmail "From " delimiter line - in response to a TOP or RETR command. - - Encased all debugging code in #ifdef DEBUG constructs. This code can - be included by specifying the DEGUG compiler flag. Note: You still - need to use the -d or -t option to obtain debugging output. - -1.6 Corrects a bug that causes the server to crash on SunOS - 4.0 systems. - - Uses varargs and vsprintf (if available) in pop_log and - pop_msg. This is enabled by the "HAVE_VSPRINTF" - compiler flag. - - For systems with BSD 4.3 bind, performs a cannonical - name lookup and searches the returned address(es) for - the client's address, logging a warning message if it - is not located. This is enabled by the "BIND43" - comiler flag. - - Removed all the includes from popper.h and distributed - them throughout the porgrams files, as needed. - - Reformatted the source to convert tabs to spaces and - shorten lines for display on 80-column terminals. - -1.5 Creates the temporary maildrop with mode "600" and - immediately unlinks it. - - Uses client's IP address in lieu of a canonical name if - the latter cannot be obtained. - - Added "-t " option. The presence of this - option causes debugging output to be placed in the file - "file-name" using fprintf instead of the system log - file using syslog. - - Corrected maildrop parsing problem. - -1.4 Copies user's mail into a temporary maildrop on which - all subsequent activity is performed. - - Added "pop_log" function and replaced "syslog" calls - throughout the code with it. - -1.3 Corrected updating of Status: header line. - - Added strncasecmp for systems that do not have one. - Used strncasecmp in all appropriate places. This is - enabled by the STRNCASECMP compiler flag. - -1.2 Support for version 4.2 syslogging added. This is - enabled by the SYSLOG42 compiler flag. - -1.1 Several bugs fixed. - -1.0 Original version. - - -Limitations - -+ The POP server copies the user's entire maildrop to /tmp and - then operates on that copy. If the maildrop is particularly - large, or inadequate space is available in /tmp, then the - server will refuse to continue and terminate the connection. - -+ Simultaneous modification of a single maildrop can result in - confusing results. For example, manipulating messages in a - maildrop using the Unix /usr/ucb/mail command while a copy of - it is being processed by the POP server can cause the changes - made by one program to be lost when the other terminates. This - problem is being worked on and will be fixed in a later - release. - - -Credits - -The POP server was written by Edward Moy and Austin Shelton with -contributions from Robert Campbell (U.C. Berkeley) and Viktor Dukhovni -(Princeton University). Edward Moy wrote the HyperMail stack and drew -the POP operation diagram. This installation guide was written by -Austin Shelton. - - -Footnotes - -[1] Copyright (c) 1990 Regents of the University of California. - All rights reserved. The Berkeley software License Agreement - specifies the terms and conditions for redistribution. Unix is - a registered trademark of AT&T corporation. HyperCard and - Macintosh are registered trademarks of Apple Corporation. - -[2] M. Rose, Post Office Protocol - Version 3. RFC 1081, NIC, - November 1988. - -[3] M. Rose, Post Office Protocol - Version 3 Extended Service - Offerings. RFC 1082, NIC, November 1988. diff --git a/appl/popper/README-FIRST b/appl/popper/README-FIRST deleted file mode 100644 index 3d78fb644..000000000 --- a/appl/popper/README-FIRST +++ /dev/null @@ -1,11 +0,0 @@ -This kerberized popper was based on popper-1.831beta -which was later announced as "offical" and not beta. - -This program is able to talk both the pop3 and the kpop3 protocol. - -Please note that the server principal is pop.hostname and not -rcmd.hostname. I.e an additional entry is needed in your mailhub's -/etc/srvtab. Use ksrvutil to add the extra prinicpal. - -The server is usually started from inetd and there is already an entry -for that in inetd.conf.changes. diff --git a/appl/popper/auth_gssapi.c b/appl/popper/auth_gssapi.c deleted file mode 100644 index 032efe7ee..000000000 --- a/appl/popper/auth_gssapi.c +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (c) 2004 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -RCSID("$Id$"); - - -#if defined(SASL) && defined(KRB5) -#include - -extern krb5_context gssapi_krb5_context; - -struct gss_state { - gss_ctx_id_t context_hdl; - gss_OID mech_oid; - gss_name_t client_name; - int stage; -}; - -static void -gss_set_error (struct gss_state *gs, int min_stat) -{ - OM_uint32 new_stat; - OM_uint32 msg_ctx = 0; - gss_buffer_desc status_string; - OM_uint32 ret; - - do { - char * cstr; - - ret = gss_display_status (&new_stat, - min_stat, - GSS_C_MECH_CODE, - gs->mech_oid, - &msg_ctx, - &status_string); - if (asprintf(&cstr, "%.*s", (int)status_string.length, - (const char *)status_string.value) >= 0) { - pop_auth_set_error(cstr); - free(cstr); - } else { - pop_auth_set_error("unknown error"); - } - gss_release_buffer (&new_stat, &status_string); - } while (!GSS_ERROR(ret) && msg_ctx != 0); -} - -static int -gss_loop(POP *p, void *state, - /* const */ void *input, size_t input_length, - void **output, size_t *output_length) -{ - struct gss_state *gs = state; - gss_buffer_desc real_input_token, real_output_token; - gss_buffer_t input_token = &real_input_token, - output_token = &real_output_token; - OM_uint32 maj_stat, min_stat; - gss_channel_bindings_t bindings = GSS_C_NO_CHANNEL_BINDINGS; - - if(gs->stage == 0) { - /* we require an initial response, so ask for one if not - present */ - gs->stage++; - if(input == NULL && input_length == 0) { - /* XXX this could be done better */ - fputs("+ \r\n", p->output); - fflush(p->output); - return POP_AUTH_CONTINUE; - } - } - if(gs->stage == 1) { - input_token->value = input; - input_token->length = input_length; - maj_stat = - gss_accept_sec_context (&min_stat, - &gs->context_hdl, - GSS_C_NO_CREDENTIAL, - input_token, - bindings, - &gs->client_name, - &gs->mech_oid, - output_token, - NULL, - NULL, - NULL); - if (GSS_ERROR(maj_stat)) { - gss_set_error(gs, min_stat); - return POP_AUTH_FAILURE; - } - if (output_token->length != 0) { - *output = output_token->value; - *output_length = output_token->length; - } - if(maj_stat == GSS_S_COMPLETE) - gs->stage++; - - return POP_AUTH_CONTINUE; - } - - if(gs->stage == 2) { - /* send wanted protection levels */ - unsigned char x[4] = { 1, 0, 0, 0 }; - - input_token->value = x; - input_token->length = 4; - - maj_stat = gss_wrap(&min_stat, - gs->context_hdl, - FALSE, - GSS_C_QOP_DEFAULT, - input_token, - NULL, - output_token); - if (GSS_ERROR(maj_stat)) { - gss_set_error(gs, min_stat); - return POP_AUTH_FAILURE; - } - *output = output_token->value; - *output_length = output_token->length; - gs->stage++; - return POP_AUTH_CONTINUE; - } - if(gs->stage == 3) { - /* receive protection levels and username */ - char *name; - krb5_principal principal; - gss_buffer_desc export_name; - gss_OID oid; - unsigned char *ptr; - - input_token->value = input; - input_token->length = input_length; - - maj_stat = gss_unwrap (&min_stat, - gs->context_hdl, - input_token, - output_token, - NULL, - NULL); - if (GSS_ERROR(maj_stat)) { - gss_set_error(gs, min_stat); - return POP_AUTH_FAILURE; - } - if(output_token->length < 5) { - pop_auth_set_error("response too short"); - return POP_AUTH_FAILURE; - } - ptr = output_token->value; - if(ptr[0] != 1) { - pop_auth_set_error("must use clear text"); - return POP_AUTH_FAILURE; - } - memmove(output_token->value, ptr + 4, output_token->length - 4); - ptr[output_token->length - 4] = '\0'; - - maj_stat = gss_display_name(&min_stat, gs->client_name, - &export_name, &oid); - if(maj_stat != GSS_S_COMPLETE) { - gss_set_error(gs, min_stat); - return POP_AUTH_FAILURE; - } - /* XXX kerberos */ - if(oid != GSS_KRB5_NT_PRINCIPAL_NAME) { - pop_auth_set_error("unexpected gss name type"); - gss_release_buffer(&min_stat, &export_name); - return POP_AUTH_FAILURE; - } - name = malloc(export_name.length + 1); - if(name == NULL) { - pop_auth_set_error("out of memory"); - gss_release_buffer(&min_stat, &export_name); - return POP_AUTH_FAILURE; - } - memcpy(name, export_name.value, export_name.length); - name[export_name.length] = '\0'; - gss_release_buffer(&min_stat, &export_name); - krb5_parse_name(gssapi_krb5_context, name, &principal); - - if(!krb5_kuserok(gssapi_krb5_context, principal, ptr)) { - pop_auth_set_error("Permission denied"); - return POP_AUTH_FAILURE; - } - - - strlcpy(p->user, ptr, sizeof(p->user)); - return POP_AUTH_COMPLETE; - } - return POP_AUTH_FAILURE; -} - - -static int -gss_init(POP *p, void **state) -{ - struct gss_state *gs = malloc(sizeof(*gs)); - if(gs == NULL) { - pop_auth_set_error("out of memory"); - return POP_AUTH_FAILURE; - } - gs->context_hdl = GSS_C_NO_CONTEXT; - gs->stage = 0; - *state = gs; - return POP_AUTH_CONTINUE; -} - -static int -gss_cleanup(POP *p, void *state) -{ - OM_uint32 min_stat; - struct gss_state *gs = state; - if(gs->context_hdl != GSS_C_NO_CONTEXT) - gss_delete_sec_context(&min_stat, &gs->context_hdl, GSS_C_NO_BUFFER); - free(state); - return POP_AUTH_CONTINUE; -} - -struct auth_mech gssapi_mech = { - "GSSAPI", gss_init, gss_loop, gss_cleanup -}; - -#endif /* KRB5 */ diff --git a/appl/popper/maildir.c b/appl/popper/maildir.c deleted file mode 100644 index c82e4a873..000000000 --- a/appl/popper/maildir.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (c) 1998 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -RCSID("$Id$"); - -static void -make_path(POP *p, MsgInfoList *mp, int new, char *buf, size_t len) -{ - snprintf(buf, len, "%s/%s%s%s", p->drop_name, - new ? "new" : "cur", mp ? "/" : "", mp ? mp->name : ""); -} - -static int -scan_file(POP *p, MsgInfoList *mp) -{ - char path[MAXPATHLEN]; - FILE *f; - char buf[1024]; - int eoh = 0; - - make_path(p, mp, mp->flags & NEW_FLAG, path, sizeof(path)); - f = fopen(path, "r"); - - if(f == NULL) { -#ifdef DEBUG - if(p->debug) - pop_log(p, POP_DEBUG, - "Failed to open message file `%s': %s", - path, strerror(errno)); -#endif - return pop_msg (p, POP_FAILURE, - "Failed to open message file `%s'", path); - } - while(fgets(buf, sizeof(buf), f)) { - if(buf[strlen(buf) - 1] == '\n') - mp->lines++; - mp->length += strlen(buf); - if(eoh) - continue; - if(strcmp(buf, "\n") == 0) - eoh = 1; - parse_header(mp, buf); - } - fclose(f); - return add_missing_headers(p, mp); -} - -static int -scan_dir(POP *p, int new) -{ - char tmp[MAXPATHLEN]; - DIR *dir; - struct dirent *dent; - MsgInfoList *mp = p->mlp; - int n_mp = p->msg_count; - int e; - - make_path(p, NULL, new, tmp, sizeof(tmp)); - mkdir(tmp, 0700); - dir = opendir(tmp); - while((dent = readdir(dir)) != NULL) { - if(strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) - continue; - mp = realloc(mp, (n_mp + 1) * sizeof(*mp)); - if(mp == NULL) { - p->msg_count = 0; - return pop_msg (p, POP_FAILURE, - "Can't build message list for '%s': Out of memory", - p->user); - } - memset(mp + n_mp, 0, sizeof(*mp)); - mp[n_mp].name = strdup(dent->d_name); - if(mp[n_mp].name == NULL) { - p->msg_count = 0; - return pop_msg (p, POP_FAILURE, - "Can't build message list for '%s': Out of memory", - p->user); - } - mp[n_mp].number = n_mp + 1; - mp[n_mp].flags = 0; - if(new) - mp[n_mp].flags |= NEW_FLAG; - e = scan_file(p, &mp[n_mp]); - if(e != POP_SUCCESS) - return e; - p->drop_size += mp[n_mp].length; - n_mp++; - } - closedir(dir); - p->mlp = mp; - p->msg_count = n_mp; - return POP_SUCCESS; -} - -int -pop_maildir_info(POP *p) -{ - int e; - - p->temp_drop[0] = '\0'; - p->mlp = NULL; - p->msg_count = 0; - - e = scan_dir(p, 0); - if(e != POP_SUCCESS) return e; - - e = scan_dir(p, 1); - if(e != POP_SUCCESS) return e; - return POP_SUCCESS; -} - -int -pop_maildir_update(POP *p) -{ - int i; - char tmp1[MAXPATHLEN], tmp2[MAXPATHLEN]; - for(i = 0; i < p->msg_count; i++) { - make_path(p, &p->mlp[i], p->mlp[i].flags & NEW_FLAG, - tmp1, sizeof(tmp1)); - if(p->mlp[i].flags & DEL_FLAG) { -#ifdef DEBUG - if(p->debug) - pop_log(p, POP_DEBUG, "Removing `%s'", tmp1); -#endif - if(unlink(tmp1) < 0) { -#ifdef DEBUG - if(p->debug) - pop_log(p, POP_DEBUG, "Failed to remove `%s': %s", - tmp1, strerror(errno)); -#endif - /* return failure? */ - } - } else if((p->mlp[i].flags & NEW_FLAG) && - (p->mlp[i].flags & RETR_FLAG)) { - make_path(p, &p->mlp[i], 0, tmp2, sizeof(tmp2)); -#ifdef DEBUG - if(p->debug) - pop_log(p, POP_DEBUG, "Linking `%s' to `%s'", tmp1, tmp2); -#endif - if(link(tmp1, tmp2) == 0) { -#ifdef DEBUG - if(p->debug) - pop_log(p, POP_DEBUG, "Removing `%s'", tmp1); -#endif - if(unlink(tmp1) < 0) { -#ifdef DEBUG - if(p->debug) - pop_log(p, POP_DEBUG, "Failed to remove `%s'", tmp1); -#endif - /* return failure? */ - } - } else { - if(errno == EXDEV) { -#ifdef DEBUG - if(p->debug) - pop_log(p, POP_DEBUG, "Trying to rename `%s' to `%s'", - tmp1, tmp2); -#endif - if(rename(tmp1, tmp2) < 0) { -#ifdef DEBUG - if(p->debug) - pop_log(p, POP_DEBUG, "Failed to rename `%s' to `%s'", - tmp1, tmp2); -#endif - } - } - } - } - } - return(pop_quit(p)); -} - -int -pop_maildir_open(POP *p, MsgInfoList *mp) -{ - char tmp[MAXPATHLEN]; - make_path(p, mp, mp->flags & NEW_FLAG, tmp, sizeof(tmp)); - if(p->drop) - fclose(p->drop); - p->drop = fopen(tmp, "r"); - if(p->drop == NULL) - return pop_msg(p, POP_FAILURE, "Failed to open message file"); - return POP_SUCCESS; -} diff --git a/appl/popper/pop3.rfc1081 b/appl/popper/pop3.rfc1081 deleted file mode 100644 index 08ea6dd14..000000000 --- a/appl/popper/pop3.rfc1081 +++ /dev/null @@ -1,898 +0,0 @@ - - - - - - -Network Working Group M. Rose -Request for Comments: 1081 TWG - November 1988 - - Post Office Protocol - Version 3 - - -Status of this Memo - - This memo suggests a simple method for workstations to dynamically - access mail from a mailbox server. This RFC specifies a proposed - protocol for the Internet community, and requests discussion and - suggestions for improvements. Distribution of this memo is - unlimited. - - This memo is based on RFC 918 (since revised as RFC 937). Although - similar in form to the original Post Office Protocol (POP) proposed - for the Internet community, the protocol discussed in this memo is - similar in spirit to the ideas investigated by the MZnet project at - the University of California, Irvine. - - Further, substantial work was done on examining POP in a PC-based - environment. This work, which resulted in additional functionality - in this protocol, was performed by the ACIS Networking Systems Group - at Stanford University. The author gratefully acknowledges their - interest. - -Introduction - - On certain types of smaller nodes in the Internet it is often - impractical to maintain a message transport system (MTS). For - example, a workstation may not have sufficient resources (cycles, - disk space) in order to permit a SMTP server and associated local - mail delivery system to be kept resident and continuously running. - Similarly, it may be expensive (or impossible) to keep a personal - computer interconnected to an IP-style network for long amounts of - time (the node is lacking the resource known as "connectivity"). - - Despite this, it is often very useful to be able to manage mail on - these smaller nodes, and they often support a user agent (UA) to aid - the tasks of mail handling. To solve this problem, a node which can - support an MTS entity offers a maildrop service to these less endowed - nodes. The Post Office Protocol - Version 3 (POP3) is intended to - permit a workstation to dynamically access a maildrop on a server - host in a useful fashion. Usually, this means that the POP3 is used - to allow a workstation to retrieve mail that the server is holding - for it. - - - - -Rose [Page 1] - -RFC 1081 POP3 November 1988 - - - For the remainder of this memo, the term "client host" refers to a - host making use of the POP3 service, while the term "server host" - refers to a host which offers the POP3 service. - -A Short Digression - - This memo does not specify how a client host enters mail into the - transport system, although a method consistent with the philosophy of - this memo is presented here: - - When the user agent on a client host wishes to enter a message - into the transport system, it establishes an SMTP connection to - its relay host (this relay host could be, but need not be, the - POP3 server host for the client host). - - If this method is followed, then the client host appears to the MTS - as a user agent, and should NOT be regarded as a "trusted" MTS entity - in any sense whatsoever. This concept, along with the role of the - POP3 as a part of a split-UA model is discussed later in this memo. - - Initially, the server host starts the POP3 service by listening on - TCP port 110. When a client host wishes to make use of the service, - it establishes a TCP connection with the server host. When the - connection is established, the POP3 server sends a greeting. The - client and POP3 server then exchange commands and responses - (respectively) until the connection is closed or aborted. - - Commands in the POP3 consist of a keyword possibly followed by an - argument. All commands are terminated by a CRLF pair. - - Responses in the POP3 consist of a success indicator and a keyword - possibly followed by additional information. All responses are - terminated by a CRLF pair. There are currently two success - indicators: positive ("+OK") and negative ("-ERR"). - - Responses to certain commands are multi-line. In these cases, which - are clearly indicated below, after sending the first line of the - response and a CRLF, any additional lines are sent, each terminated - by a CRLF pair. When all lines of the response have been sent, a - final line is sent, consisting of a termination octet (decimal code - 046, ".") and a CRLF pair. If any line of the multi-line response - begins with the termination octet, the line is "byte-stuffed" by - pre-pending the termination octet to that line of the response. - Hence a multi-line response is terminated with the five octets - "CRLF.CRLF". When examining a multi-line response, the client checks - to see if the line begins with the termination octet. If so and if - octets other than CRLF follow, the the first octet of the line (the - termination octet) is stripped away. If so and if CRLF immediately - - - -Rose [Page 2] - -RFC 1081 POP3 November 1988 - - - follows the termination character, then the response from the POP - server is ended and the line containing ".CRLF" is not considered - part of the multi-line response. - - A POP3 session progresses through a number of states during its - lifetime. Once the TCP connection has been opened and the POP3 - server has sent the greeting, the session enters the AUTHORIZATION - state. In this state, the client must identify itself to the POP3 - server. Once the client has successfully done this, the server - acquires resources associated with the client's maildrop, and the - session enters the TRANSACTION state. In this state, the client - requests actions on the part of the POP3 server. When the client has - finished its transactions, the session enters the UPDATE state. In - this state, the POP3 server releases any resources acquired during - the TRANSACTION state and says goodbye. The TCP connection is then - closed. - -The AUTHORIZATION State - - Once the TCP connection has been opened by a POP3 client, the POP3 - server issues a one line greeting. This can be any string terminated - by CRLF. An example might be: - - S. +OK dewey POP3 server ready (Comments to: PostMaster@UDEL.EDU) - - Note that this greeting is a POP3 reply. The POP3 server should - always give a positive response as the greeting. - - The POP3 session is now in the AUTHORIZATION state. The client must - now issue the USER command. If the POP3 server responds with a - positive success indicator ("+OK"), then the client may issue either - the PASS command to complete the authorization, or the QUIT command - to terminate the POP3 session. If the POP3 server responds with a - negative success indicator ("-ERR") to the USER command, then the - client may either issue a new USER command or may issue the QUIT - command. - - When the client issues the PASS command, the POP3 server uses the - argument pair from the USER and PASS commands to determine if the - client should be given access to the appropriate maildrop. If so, - the POP3 server then acquires an exclusive-access lock on the - maildrop. If the lock is successfully acquired, the POP3 server - parses the maildrop into individual messages (read note below), - determines the last message (if any) present in the maildrop that was - referenced by the RETR command, and responds with a positive success - indicator. The POP3 session now enters the TRANSACTION state. If - the lock can not be acquired or the client should is denied access to - the appropriate maildrop or the maildrop can't be parsed for some - - - -Rose [Page 3] - -RFC 1081 POP3 November 1988 - - - reason, the POP3 server responds with a negative success indicator. - (If a lock was acquired but the POP3 server intends to respond with a - negative success indicator, the POP3 server must release the lock - prior to rejecting the command.) At this point, the client may - either issue a new USER command and start again, or the client may - issue the QUIT command. - - NOTE: Minimal implementations of the POP3 need only be - able to break a maildrop into its component messages; - they need NOT be able to parse individual messages. - More advanced implementations may wish to have this - capability, for reasons discussed later. - - After the POP3 server has parsed the maildrop into individual - messages, it assigns a message-id to each message, and notes the size - of the message in octets. The first message in the maildrop is - assigned a message-id of "1", the second is assigned "2", and so on, - so that the n'th message in a maildrop is assigned a message-id of - "n". In POP3 commands and responses, all message-id's and message - sizes are expressed in base-10 (i.e., decimal). - - It sets the "highest number accessed" to be that of the last message - referenced by the RETR command. - - Here are summaries for the three POP3 commands discussed thus far: - - USER name - Arguments: a server specific user-id (required) - Restrictions: may only be given in the AUTHORIZATION - state after the POP3 greeting or after an - unsuccessful USER or PASS command - Possible Responses: - +OK name is welcome here - -ERR never heard of name - Examples: - C: USER mrose - S: +OK mrose is a real hoopy frood - ... - C: USER frated - S: -ERR sorry, frated doesn't get his mail here - - PASS string - Arguments: a server/user-id specific password (required) - Restrictions: may only be given in the AUTHORIZATION - state after a successful USER command - Possible Responses: - +OK maildrop locked and ready - -ERR invalid password - - - -Rose [Page 4] - -RFC 1081 POP3 November 1988 - - - -ERR unable to lock maildrop - Examples: - C: USER mrose - S: +OK mrose is a real hoopy frood - C: PASS secret - S: +OK mrose's maildrop has 2 messages - (320 octets) - ... - C: USER mrose - S: +OK mrose is a real hoopy frood - C: PASS secret - S: -ERR unable to lock mrose's maildrop, file - already locked - - QUIT - Arguments: none - Restrictions: none - Possible Responses: - +OK - Examples: - C: QUIT - S: +OK dewey POP3 server signing off - - -The TRANSACTION State - - Once the client has successfully identified itself to the POP3 server - and the POP3 server has locked and burst the appropriate maildrop, - the POP3 session is now in the TRANSACTION state. The client may now - issue any of the following POP3 commands repeatedly. After each - command, the POP3 server issues a response. Eventually, the client - issues the QUIT command and the POP3 session enters the UPDATE state. - - Here are the POP3 commands valid in the TRANSACTION state: - - STAT - Arguments: none - Restrictions: may only be given in the TRANSACTION state. - Discussion: - - The POP3 server issues a positive response with a line - containing information for the maildrop. This line is - called a "drop listing" for that maildrop. - - In order to simplify parsing, all POP3 servers are - required to use a certain format for drop listings. - The first octets present must indicate the number of - messages in the maildrop. Following this is the size - - - -Rose [Page 5] - -RFC 1081 POP3 November 1988 - - - of the maildrop in octets. This memo makes no - requirement on what follows the maildrop size. - Minimal implementations should just end that line of - the response with a CRLF pair. More advanced - implementations may include other information. - - NOTE: This memo STRONGLY discourages - implementations from supplying additional - information in the drop listing. Other, - optional, facilities are discussed later on - which permit the client to parse the messages - in the maildrop. - - Note that messages marked as deleted are not counted in - either total. - - Possible Responses: - +OK nn mm - Examples: - C: STAT - S: +OK 2 320 - - LIST [msg] - Arguments: a message-id (optionally) If a message-id is - given, it may NOT refer to a message marked as - deleted. - Restrictions: may only be given in the TRANSACTION state. - Discussion: - - If an argument was given and the POP3 server issues a - positive response with a line containing information - for that message. This line is called a "scan listing" - for that message. - - If no argument was given and the POP3 server issues a - positive response, then the response given is - multi-line. After the initial +OK, for each message - in the maildrop, the POP3 server responds with a line - containing information for that message. This line - is called a "scan listing" for that message. - - In order to simplify parsing, all POP3 servers are - required to use a certain format for scan listings. - The first octets present must be the message-id of - the message. Following the message-id is the size of - the message in octets. This memo makes no requirement - on what follows the message size in the scan listing. - Minimal implementations should just end that line of - - - -Rose [Page 6] - -RFC 1081 POP3 November 1988 - - - the response with a CRLF pair. More advanced - implementations may include other information, as - parsed from the message. - - NOTE: This memo STRONGLY discourages - implementations from supplying additional - information in the scan listing. Other, optional, - facilities are discussed later on which permit - the client to parse the messages in the maildrop. - - Note that messages marked as deleted are not listed. - - Possible Responses: - +OK scan listing follows - -ERR no such message - Examples: - C: LIST - S: +OK 2 messages (320 octets) - S: 1 120 - S: 2 200 - S: . - ... - C: LIST 2 - S: +OK 2 200 - ... - C: LIST 3 - S: -ERR no such message, only 2 messages in - maildrop - - RETR msg - Arguments: a message-id (required) This message-id may - NOT refer to a message marked as deleted. - Restrictions: may only be given in the TRANSACTION state. - Discussion: - - If the POP3 server issues a positive response, then the - response given is multi-line. After the initial +OK, - the POP3 server sends the message corresponding to the - given message-id, being careful to byte-stuff the - termination character (as with all multi-line - responses). - - If the number associated with this message is higher - than the "highest number accessed" in the maildrop, the - POP3 server updates the "highest number accessed" to - the number associated with this message. - - - - - -Rose [Page 7] - -RFC 1081 POP3 November 1988 - - - Possible Responses: - +OK message follows - -ERR no such message - Examples: - C: RETR 1 - S: +OK 120 octets - S: - S: . - - DELE msg - Arguments: a message-id (required) This message-id - may NOT refer to a message marked as deleted. - Restrictions: may only be given in the TRANSACTION state. - Discussion: - - The POP3 server marks the message as deleted. Any - future reference to the message-id associated with the - message in a POP3 command generates an error. The POP3 - server does not actually delete the message until the - POP3 session enters the UPDATE state. - - If the number associated with this message is higher - than the "highest number accessed" in the maildrop, - the POP3 server updates the "highest number accessed" - to the number associated with this message. - - Possible Responses: - +OK message deleted - -ERR no such message - Examples: - C: DELE 1 - S: +OK message 1 deleted - ... - C: DELE 2 - S: -ERR message 2 already deleted - - NOOP - Arguments: none - Restrictions: may only be given in the TRANSACTION state. - Discussion: - - The POP3 server does nothing, it merely replies with a - positive response. - - Possible Responses: - +OK - - - - - -Rose [Page 8] - -RFC 1081 POP3 November 1988 - - - Examples: - C: NOOP - S: +OK - - LAST - Arguments: none - Restrictions: may only be issued in the TRANSACTION state. - Discussion: - - The POP3 server issues a positive response with a line - containing the highest message number which accessed. - Zero is returned in case no message in the maildrop has - been accessed during previous transactions. A client - may thereafter infer that messages, if any, numbered - greater than the response to the LAST command are - messages not yet accessed by the client. - - Possible Response: - +OK nn - - Examples: - C: STAT - S: +OK 4 320 - C: LAST - S: +OK 1 - C: RETR 3 - S: +OK 120 octets - S: - S: . - C: LAST - S: +OK 3 - C: DELE 2 - S: +OK message 2 deleted - C: LAST - S: +OK 3 - C: RSET - S: +OK - C: LAST - S: +OK 1 - - RSET - Arguments: none - Restrictions: may only be given in the TRANSACTION - state. - Discussion: - - If any messages have been marked as deleted by the POP3 - - - -Rose [Page 9] - -RFC 1081 POP3 November 1988 - - - server, they are unmarked. The POP3 server then - replies with a positive response. In addition, the - "highest number accessed" is also reset to the value - determined at the beginning of the POP3 session. - - Possible Responses: - +OK - Examples: - C: RSET - S: +OK maildrop has 2 messages (320 octets) - - - -The UPDATE State - - When the client issues the QUIT command from the TRANSACTION state, - the POP3 session enters the UPDATE state. (Note that if the client - issues the QUIT command from the AUTHORIZATION state, the POP3 - session terminates but does NOT enter the UPDATE state.) - - QUIT - Arguments: none - Restrictions: none - Discussion: - - The POP3 server removes all messages marked as deleted - from the maildrop. It then releases the - exclusive-access lock on the maildrop and replies as - to the success of - these operations. The TCP connection is then closed. - - Possible Responses: - +OK - Examples: - C: QUIT - S: +OK dewey POP3 server signing off (maildrop - empty) - ... - C: QUIT - S: +OK dewey POP3 server signing off (2 messages - left) - ... - - -Optional POP3 Commands - - The POP3 commands discussed above must be supported by all minimal - implementations of POP3 servers. - - - -Rose [Page 10] - -RFC 1081 POP3 November 1988 - - - The optional POP3 commands described below permit a POP3 client - greater freedom in message handling, while preserving a simple POP3 - server implementation. - - NOTE: This memo STRONGLY encourages implementations to - support these commands in lieu of developing augmented - drop and scan listings. In short, the philosophy of - this memo is to put intelligence in the part of the - POP3 client and not the POP3 server. - - TOP msg n - Arguments: a message-id (required) and a number. This - message-id may NOT refer to a message marked as - deleted. - Restrictions: may only be given in the TRANSACTION state. - Discussion: - - If the POP3 server issues a positive response, then - the response given is multi-line. After the initial - +OK, the POP3 server sends the headers of the message, - the blank line separating the headers from the body, - and then the number of lines indicated message's body, - being careful to byte-stuff the termination character - (as with all multi-line responses). - - Note that if the number of lines requested by the POP3 - client is greater than than the number of lines in the - body, then the POP3 server sends the entire message. - - Possible Responses: - +OK top of message follows - -ERR no such message - Examples: - C: TOP 10 - S: +OK - S: - S: . - ... - C: TOP 100 - S: -ERR no such message - - RPOP user - Arguments: a client specific user-id (required) - Restrictions: may only be given in the AUTHORIZATION - state after a successful USER command; in addition, - may only be given if the client used a reserved - - - -Rose [Page 11] - -RFC 1081 POP3 November 1988 - - - (privileged) TCP port to connect to the server. - Discussion: - - The RPOP command may be used instead of the PASS - command to authenticate access to the maildrop. In - order for this command to be successful, the POP3 - client must use a reserved TCP port (port < 1024) to - connect tothe server. The POP3 server uses the - argument pair from the USER and RPOP commands to - determine if the client should be given access to - the appropriate maildrop. Unlike the PASS command - however, the POP3 server considers if the remote user - specified by the RPOP command who resides on the POP3 - client host is allowed to access the maildrop for the - user specified by the USER command (e.g., on Berkeley - UNIX, the .rhosts mechanism is used). With the - exception of this differing in authentication, this - command is identical to the PASS command. - - Note that the use of this feature has allowed much wider - penetration into numerous hosts on local networks (and - sometimes remote networks) by those who gain illegal - access to computers by guessing passwords or otherwise - breaking into the system. - - Possible Responses: - +OK maildrop locked and ready - -ERR permission denied - Examples: - C: USER mrose - S: +OK mrose is a real hoopy frood - C: RPOP mrose - S: +OK mrose's maildrop has 2 messages (320 - octets) - - Minimal POP3 Commands: - USER name valid in the AUTHORIZATION state - PASS string - QUIT - - STAT valid in the TRANSACTION state - LIST [msg] - RETR msg - DELE msg - NOOP - LAST - RSET - - - - -Rose [Page 12] - -RFC 1081 POP3 November 1988 - - - QUIT valid in the UPDATE state - - Optional POP3 Commands: - RPOP user valid in the AUTHORIZATION state - - TOP msg n valid in the TRANSACTION state - - POP3 Replies: - +OK - -ERR - - Note that with the exception of the STAT command, the reply given - by the POP3 server to any command is significant only to "+OK" - and "-ERR". Any text occurring after this reply may be ignored - by the client. - -Example POP3 Session - - S: - ... - C: - S: +OK dewey POP3 server ready (Comments to: PostMaster@UDEL.EDU) - C: USER mrose - S: +OK mrose is a real hoopy frood - C: PASS secret - S: +OK mrose's maildrop has 2 messages (320 octets) - C: STAT - S: +OK 2 320 - C: LIST - S: +OK 2 messages (320 octets) - S: 1 120 - S: 2 200 - S: . - C: RETR 1 - S: +OK 120 octets - S: - S: . - C: DELE 1 - S: +OK message 1 deleted - C: RETR 2 - S: +OK 200 octets - S: - S: . - C: DELE 2 - S: +OK message 2 deleted - C: QUIT - - - - - -Rose [Page 13] - -RFC 1081 POP3 November 1988 - - - S: +OK dewey POP3 server signing off (maildrop empty) - C: - S: - -Message Format - - All messages transmitted during a POP3 session are assumed to conform - to the standard for the format of Internet text messages [RFC822]. - - It is important to note that the byte count for a message on the - server host may differ from the octet count assigned to that message - due to local conventions for designating end-of-line. Usually, - during the AUTHORIZATION state of the POP3 session, the POP3 client - can calculate the size of each message in octets when it parses the - maildrop into messages. For example, if the POP3 server host - internally represents end-of-line as a single character, then the - POP3 server simply counts each occurrence of this character in a - message as two octets. Note that lines in the message which start - with the termination octet need not be counted twice, since the POP3 - client will remove all byte-stuffed termination characters when it - receives a multi-line response. - -The POP and the Split-UA model - - The underlying paradigm in which the POP3 functions is that of a - split-UA model. The POP3 client host, being a remote PC based - workstation, acts solely as a client to the message transport system. - It does not provide delivery/authentication services to others. - Hence, it is acting as a UA, on behalf of the person using the - workstation. Furthermore, the workstation uses SMTP to enter mail - into the MTS. - - In this sense, we have two UA functions which interface to the - message transport system: Posting (SMTP) and Retrieval (POP3). The - entity which supports this type of environment is called a split-UA - (since the user agent is split between two hosts which must - interoperate to provide these functions). - - ASIDE: Others might term this a remote-UA instead. - There are arguments supporting the use of both terms. - - This memo has explicitly referenced TCP as the underlying transport - agent for the POP3. This need not be the case. In the MZnet split- - UA, for example, personal micro-computer systems are used which do - not have IP-style networking capability. To connect to the POP3 - server host, a PC establishes a terminal connection using some simple - protocol (PhoneNet). A program on the PC drives the connection, - first establishing a login session as a normal user. The login shell - - - -Rose [Page 14] - -RFC 1081 POP3 November 1988 - - - for this pseudo-user is a program which drives the other half of the - terminal protocol and communicates with one of two servers. Although - MZnet can support several PCs, a single pseudo-user login is present - on the server host. The user-id and password for this pseudo-user - login is known to all members of MZnet. Hence, the first action of - the login shell, after starting the terminal protocol, is to demand a - USER/PASS authorization pair from the PC. This second level of - authorization is used to ascertain who is interacting with the MTS. - Although the server host is deemed to support a "trusted" MTS entity, - PCs in MZnet are not. Naturally, the USER/PASS authorization pair - for a PC is known only to the owner of the PC (in theory, at least). - - After successfully verifying the identity of the client, a modified - SMTP server is started, and the PC posts mail with the server host. - After the QUIT command is given to the SMTP server and it terminates, - a modified POP3 server is started, and the PC retrieves mail from the - server host. After the QUIT command is given to the POP3 server and - it terminates, the login shell for the pseudo-user terminates the - terminal protocol and logs the job out. The PC then closes the - terminal connection to the server host. - - The SMTP server used by MZnet is modified in the sense that it knows - that it's talking to a user agent and not a "trusted" entity in the - message transport system. Hence, it does performs the validation - activities normally performed by an entity in the MTS when it accepts - a message from a UA. - - The POP3 server used by MZnet is modified in the sense that it does - not require a USER/PASS combination before entering the TRANSACTION - state. The reason for this (of course) is that the PC has already - identified itself during the second-level authorization step - described above. - - NOTE: Truth in advertising laws require that the author - of this memo state that MZnet has not actually been - fully implemented. The concepts presented and proven - by the project led to the notion of the MZnet - split-slot model. This notion has inspired the - split-UA concept described in this memo, led to the - author's interest in the POP, and heavily influenced - the the description of the POP3 herein. - - In fact, some UAs present in the Internet already support the notion - of posting directly to an SMTP server and retrieving mail directly - from a POP server, even if the POP server and client resided on the - same host! - - ASIDE: this discussion raises an issue which this memo - - - -Rose [Page 15] - -RFC 1081 POP3 November 1988 - - - purposedly avoids: how does SMTP know that it's talking - to a "trusted" MTS entity? - -References - - [MZnet] Stefferud, E., J. Sweet, and T. Domae, "MZnet: Mail - Service for Personal Micro-Computer Systems", - Proceedings, IFIP 6.5 International Conference on - Computer Message Systems, Nottingham, U.K., May 1984. - - [RFC821] Postel, J., "Simple Mail Transfer Protocol", - USC/Information Sciences Institute, August 1982. - - [RFC822] Crocker, D., "Standard for the Format of ARPA-Internet - Text Messages", University of Delaware, August 1982. - - [RFC937] Butler, M., J. Postel, D. Chase, J. Goldberger, and J. - Reynolds, "Post Office Protocol - Version 2", RFC 937, - USC/Information Sciences Institute, February 1985. - - [RFC1010] Reynolds, J., and J. Postel, "Assigned Numbers", RFC - 1010, USC/Information Sciences Institute, May 1987. - -Author's Address: - - - Marshall Rose - The Wollongong Group - 1129 San Antonio Rd. - Palo Alto, California 94303 - - Phone: (415) 962-7100 - - Email: MRose@TWG.COM - - - - - - - - - - - - - - - - - -Rose [Page 16] diff --git a/appl/popper/pop3e.rfc1082 b/appl/popper/pop3e.rfc1082 deleted file mode 100644 index ac49448b5..000000000 --- a/appl/popper/pop3e.rfc1082 +++ /dev/null @@ -1,619 +0,0 @@ - - - - - - -Network Working Group M. Rose -Request for Comments: 1082 TWG - November 1988 - - - - Post Office Protocol - Version 3 - Extended Service Offerings - -Status of This Memo - - This memo suggests a simple method for workstations to dynamically - access mail from a discussion group server, as an extension to an - earlier memo which dealt with dynamically accessing mail from a - mailbox server using the Post Office Protocol - Version 3 (POP3). - This RFC specifies a proposed protocol for the Internet community, - and requests discussion and suggestions for improvements. All of the - extensions described in this memo to the POP3 are OPTIONAL. - Distribution of this memo is unlimited. - -Introduction and Motivation - - It is assumed that the reader is familiar with RFC 1081 that - discusses the Post Office Protocol - Version 3 (POP3) [RFC1081]. - This memo describes extensions to the POP3 which enhance the service - it offers to clients. This additional service permits a client host - to access discussion group mail, which is often kept in a separate - spool area, using the general POP3 facilities. - - The next section describes the evolution of discussion groups and the - technologies currently used to implement them. To summarize: - - o An exploder is used to map from a single address to - a list of addresses which subscribe to the list, and redirects - any subsequent error reports associated with the delivery of - each message. This has two primary advantages: - - Subscribers need know only a single address - - Responsible parties get the error reports and not - the subscribers - - - - - - - - - - - - -Rose [Page 1] - -RFC 1082 POP3 Extended Service November 1988 - - - o Typically, each subscription address is not a person's private - maildrop, but a system-wide maildrop, which can be accessed - by more than one user. This has several advantages: - - Only a single copy of each message need traverse the - net for a given site (which may contain several local - hosts). This conserves bandwidth and cycles. - - Only a single copy of each message need reside on each - subscribing host. This conserves disk space. - - The private maildrop for each user is not cluttered - with discussion group mail. - - Despite this optimization of resources, further economy can be - achieved at sites with more than one host. Typically, sites with - more than one host either: - - 1. Replicate discussion group mail on each host. This - results in literally gigabytes of disk space committed to - unnecessarily store redundant information. - - 2. Keep discussion group mail on one host and give all users a - login on that host (in addition to any other logins they may - have). This is usually a gross inconvenience for users who - work on other hosts, or a burden to users who are forced to - work on that host. - - As discussed in [RFC1081], the problem of giving workstations dynamic - access to mail from a mailbox server has been explored in great - detail (originally there was [RFC918], this prompted the author to - write [RFC1081], independently of this [RFC918] was upgraded to - [RFC937]). A natural solution to the problem outlined above is to - keep discussion group mail on a mailbox server at each site and - permit different hosts at that site to employ the POP3 to access - discussion group mail. If implemented properly, this avoids the - problems of both strategies outlined above. - - ASIDE: It might be noted that a good distributed filesystem - could also solve this problem. Sadly, "good" - distributed filesystems, which do not suffer - unacceptable response time for interactive use, are - few and far between these days! - - Given this motivation, now let's consider discussion groups, both in - general and from the point of view of a user agent. Following this, - extensions to the POP3 defined in [RFC1081] are presented. Finally, - some additional policy details are discussed along with some initial - experiences. - - - - - -Rose [Page 2] - -RFC 1082 POP3 Extended Service November 1988 - - -What's in a Discussion Group - - Since mailers and user agents first crawled out of the primordial - ARPAnet, the value of discussion groups have been appreciated, - (though their implementation has not always been well-understood). - - Described simply, a discussion group is composed of a number of - subscribers with a common interest. These subscribers post mail to a - single address, known as a distribution address. From this - distribution address, a copy of the message is sent to each - subscriber. Each group has a moderator, which is the person that - administrates the group. The moderator can usually be reached at a - special address, known as a request address. Usually, the - responsibilities of the moderator are quite simple, since the mail - system handles the distribution to subscribers automatically. In - some cases, the interest group, instead of being distributed directly - to its subscribers, is put into a digest format by the moderator and - then sent to the subscribers. Although this requires more work on - the part of the moderator, such groups tend to be better organized. - - Unfortunately, there are a few problems with the scheme outlined - above. First, if two users on the same host subscribe to the same - interest group, two copies of the message get delivered. This is - wasteful of both processor and disk resources. - - Second, some of these groups carry a lot of traffic. Although - subscription to an group does indicate interest on the part of a - subscriber, it is usually not interesting to get 50 messages or so - delivered to the user's private maildrop each day, interspersed with - personal mail, that is likely to be of a much more important and - timely nature. - - Third, if a subscriber on the distribution list for a group becomes - "bad" somehow, the originator of the message and not the moderator of - the group is notified. It is not uncommon for a large list to have - 10 or so bogus addresses present. This results in the originator - being flooded with "error messages" from mailers across the Internet - stating that a given address on the list was bad. Needless to say, - the originator usually could not care less if the bogus addresses got - a copy of the message or not. The originator is merely interested in - posting a message to the group at large. Furthermore, the moderator - of the group does care if there are bogus addresses on the list, but - ironically does not receive notification. - - There are various approaches which can be used to solve some or all - of these problems. Usually these involve placing an exploder agent - at the distribution source of the discussion group, which expands the - name of the group into the list of subscription addresses for the - - - -Rose [Page 3] - -RFC 1082 POP3 Extended Service November 1988 - - - group. In the process, the exploder will also change the address - that receives error notifications to be the request address or other - responsible party. - - A complementary approach, used in order to cut down on resource - utilization of all kinds, replaces all the subscribers at a single - host (or group of hosts under a single administration) with a single - address at that host. This address maps to a file on the host, - usually in a spool area, which all users can access. (Advanced - implementations can also implement private discussion groups this - way, in which a single copy of each message is kept, but is - accessible to only a select number of users on the host.) - - The two approaches can be combined to avoid all of the problems - described above. - - Finally, a third approach can be taken, which can be used to aid user - agents processing mail for the discussion group: In order to speed - querying of the maildrop which contains the local host's copy of the - discussion group, two other items are usually associated with the - discussion group, on a local basis. These are the maxima and the - last-date. Each time a message is received for the group on the - local host, the maxima is increased by at least one. Furthermore, - when a new maxima is generated, the current date is determined. This - is called the last date. As the message is entered into the local - maildrop, it is given the current maxima and last-date. This permits - the user agent to quickly determine if new messages are present in - the maildrop. - - NOTE: The maxima may be characterized as a monotonically - increasing quanity. Although sucessive values of the - maxima need not be consecutive, any maxima assigned - is always greater than any previously assigned value. - -Definition of Terms - - To formalize these notions somewhat, consider the following 7 - parameters which describe a given discussion group from the - perspective of the user agent (the syntax given is from [RFC822]): - - - - - - - - - - - - -Rose [Page 4] - -RFC 1082 POP3 Extended Service November 1988 - - - NAME Meaning: the name of the discussion group - Syntax: TOKEN (ALPHA *[ ALPHA / DIGIT / "-" ]) - (case-insensitive recognition) - Example: unix-wizards - - ALIASES Meaning: alternates names for the group, which - are locally meaningful; these are - typically used to shorten user typein - Syntax: TOKEN (case-insensitive recognition) - Example: uwiz - - ADDRESS Meaning: the primary source of the group - Syntax: 822 address - Example: Unix-Wizards@BRL.MIL - - REQUEST Meaning: the primary moderator of the group - Syntax: 822 address - Example: Unix-Wizards-Request@BRL.MIL - - FLAGS Meaning: locally meaningful flags associated - with the discussion group; this memo - leaves interpretation of this - parameter to each POP3 implementation - Syntax: octal number - Example: 01 - - MAXIMA Meaning: the magic cookie associated with the - last message locally received for the - group; it is the property of the magic - cookie that it's value NEVER - decreases, and increases by at least - one each time a message is locally - received - Syntax: decimal number - Example: 1004 - - LASTDATE Meaning: the date that the last message was - locally received - Syntax: 822 date - Example: Thu, 19 Dec 85 10:26:48 -0800 - - Note that the last two values are locally determined for the maildrop - associated with the discussion group and with each message in that - maildrop. Note however that the last message in the maildrop have a - different MAXIMA and LASTDATE than the discussion group. This often - occurs when the maildrop has been archived. - - - - - -Rose [Page 5] - -RFC 1082 POP3 Extended Service November 1988 - - - Finally, some local systems provide mechanisms for automatically - archiving discussion group mail. In some cases, a two-level archive - scheme is used: current mail is kept in the standard maildrop, - recent mail is kept in an archive maildrop, and older mail is kept - off-line. With this scheme, in addition to having a "standard" - maildrop for each discussion group, an "archive" maildrop may also be - available. This permits a user agent to examine the most recent - archive using the same mechanisms as those used on the current mail. - -The XTND Command - - The following commands are valid only in the TRANSACTION state of the - POP3. This implies that the POP3 server has already opened the - user's maildrop (which may be empty). This maildrop is called the - "default maildrop". The phrase "closes the current maildrop" has two - meanings, depending on whether the current maildrop is the default - maildrop or is a maildrop associated with a discussion group. - - In the former context, when the current maildrop is closed any - messages marked as deleted are removed from the maildrop currently in - use. The exclusive-access lock on the maildrop is then released - along with any implementation-specific resources (e.g., file- - descriptors). - - In the latter context, a maildrop associated with a discussion group - is considered to be read-only to the POP3 client. In this case, the - phrase "closes the current maildrop" merely means that any - implementation-specific resources are released. (Hence, the POP3 - command DELE is a no-op.) - - All the new facilities are introduced via a single POP3 command, - XTND. All positive reponses to the XTND command are multi-line. - - The most common multi-line response to the commands contains a - "discussion group listing" which presents the name of the discussion - group along with it's maxima. In order to simplify parsing all POP3 - servers are required to use a certain format for discussion group - listings: - - NAME SP MAXIMA - - This memo makes no requirement on what follows the maxima in the - listing. Minimal implementations should just end that line of the - response with a CRLF pair. More advanced implementations may include - other information, as parsed from the message. - - NOTE: This memo STRONGLY discourages implementations from - supplying additional information in the listing. - - - -Rose [Page 6] - -RFC 1082 POP3 Extended Service November 1988 - - - XTND BBOARDS [name] - Arguments: the name of a discussion group (optionally) - Restrictions: may only be given in the TRANSACTION state. - Discussion: - - If an argument was given, the POP3 server closes the current - maildrop. The POP3 server then validates the argument as the name of - a discussion group. If this is successful, it opens the maildrop - associated with the group, and returns a multi-line response - containing the discussion group listing. If the discussion group - named is not valid, or the associated archive maildrop is not - readable by the user, then an error response is returned. - - If no argument was given, the POP3 server issues a multi-line - response. After the initial +OK, for each discussion group known, - the POP3 server responds with a line containing the listing for that - discussion group. Note that only world-readable discussion groups - are included in the multi-line response. - - In order to aid user agents, this memo requires an extension to the - scan listing when an "XTND BBOARDS" command has been given. - Normally, a scan listing, as generated by the LIST, takes the form: - - MSGNO SIZE - - where MSGNO is the number of the message being listed and SIZE is the - size of the message in octets. When reading a maildrop accessed via - "XTND BBOARDS", the scan listing takes the form - - MSGNO SIZE MAXIMA - - where MAXIMA is the maxima that was assigned to the message when it - was placed in the BBoard. - - Possible Responses: - +OK XTND - -ERR no such bboard - Examples: - C: XTND BBOARDS - S: +OK XTND - S: system 10 - S: mh-users 100 - S: . - C: XTND BBOARDS system - S: + OK XTND - S: system 10 - S: . - - - - -Rose [Page 7] - -RFC 1082 POP3 Extended Service November 1988 - - - XTND ARCHIVE name - Arguments: the name of a discussion group (required) - Restrictions: may only be given in the TRANSACTION state. - Discussion: - - The POP3 server closes the current maildrop. The POP3 server then - validates the argument as the name of a discussion group. If this is - successful, it opens the archive maildrop associated with the group, - and returns a multi-line response containing the discussion group - listing. If the discussion group named is not valid, or the - associated archive maildrop is not readable by the user, then an - error response is returned. - - In addition, the scan listing generated by the LIST command is - augmented (as described above). - - Possible Responses: - +OK XTND - -ERR no such bboard Examples: - C: XTND ARCHIVE system - S: + OK XTND - S: system 3 - S: . - - XTND X-BBOARDS name - Arguments: the name of a discussion group (required) - Restrictions: may only be given in the TRANSACTION state. - Discussion: - - The POP3 server validates the argument as the name of a - discussion group. If this is unsuccessful, then an error - response is returned. Otherwise a multi-line response is - returned. The first 14 lines of this response (after the - initial +OK) are defined in this memo. Minimal implementations - need not include other information (and may omit certain - information, outputing a bare CRLF pair). More advanced - implementations may include other information. - - Line Information (refer to "Definition of Terms") - ---- ----------- - 1 NAME - 2 ALIASES, separated by SP - 3 system-specific: maildrop - 4 system-specific: archive maildrop - 5 system-specific: information - 6 system-specific: maildrop map - 7 system-specific: encrypted password - 8 system-specific: local leaders, separated by SP - - - -Rose [Page 8] - -RFC 1082 POP3 Extended Service November 1988 - - - 9 ADDRESS - 10 REQUEST - 11 system-specific: incoming feed - 12 system-specific: outgoing feeds - 13 FLAGS SP MAXIMA - 14 LASTDATE - - Most of this information is entirely too specific to the UCI Version - of the Rand MH Message Handling System [MRose85]. Nevertheless, - lines 1, 2, 9, 10, 13, and 14 are of general interest, regardless of - the implementation. - - Possible Responses: - +OK XTND - -ERR no such bboard - Examples: - C: XTND X-BBOARDS system - S: + OK XTND - S: system - S: local general - S: /usr/bboards/system.mbox - S: /usr/bboards/archive/system.mbox - S: /usr/bboards/.system.cnt - S: /usr/bboards/.system.map - S: * - S: mother - S: system@nrtc.northrop.com - S: system-request@nrtc.northrop.com - S: - S: dist-system@nrtc-gremlin.northrop.com - S: 01 10 - S: Thu, 19 Dec 85 00:08:49 -0800 - S: . - -Policy Notes - - Depending on the particular entity administrating the POP3 service - host, two additional policies might be implemented: - - 1. Private Discussion Groups - - In the general case, discussion groups are world-readable, any user, - once logged in (via a terminal, terminal server, or POP3, etc.), is - able to read the maildrop for each discussion group known to the POP3 - service host. Nevertheless, it is desirable, usually for privacy - reasons, to implement private discussion groups as well. - - Support of this is consistent with the extensions outlined in this - - - -Rose [Page 9] - -RFC 1082 POP3 Extended Service November 1988 - - - memo. Once the AUTHORIZATION state has successfully concluded, the - POP3 server grants the user access to exactly those discussion groups - the POP3 service host permits the authenticated user to access. As a - "security" feature, discussion groups associated with unreadable - maildrops should not be listed in a positive response to the XTND - BBOARDS command. - - 2. Anonymous POP3 Users - - In order to minimize the authentication problem, a policy permitting - "anonymous" access to the world-readable maildrops for discussion - groups on the POP3 server may be implemented. - - Support of this is consistent with the extensions outlined in this - memo. The POP3 server can be modified to accept a USER command for a - well-known pseudonym (i.e., "anonymous") which is valid with any PASS - command. As a "security" feature, it is advisable to limit this kind - of access to only hosts at the local site, or to hosts named in an - access list. - -Experiences and Conclusions - - All of the facilities described in this memo and in [RFC1081] have - been implemented in MH #6.1. Initial experiences have been, on the - whole, very positive. - - After the first implementation, some performance tuning was required. - This consisted primarily of caching the datastructures which describe - discussion groups in the POP3 server. A second optimization - pertained to the client: the program most commonly used to read - BBoards in MH was modified to retrieve messages only when needed. - Two schemes are used: - - o If only the headers (and the first few lines of the body) of - the message are required (e.g., for a scan listing), then only - these are retrieved. The resulting output is then cached, on - a per-message basis. - - o If the entire message is required, then it is retrieved intact, - and cached locally. - - With these optimizations, response time is quite adequate when the - POP3 server and client are connected via a high-speed local area - network. In fact, the author uses this mechanism to access certain - private discussion groups over the Internet. In this case, response - is still good. When a 9.6Kbps modem is inserted in the path, - response went from good to almost tolerable (fortunately the author - only reads a few discussion groups in this fashion). - - - -Rose [Page 10] - -RFC 1082 POP3 Extended Service November 1988 - - - To conclude: the POP3 is a good thing, not only for personal mail but - for discussion group mail as well. - - -References - - [RFC1081] Rose, M., "Post Office Protocol - Verison 3 (POP3)", RFC - 1081, TWG, November 1988. - - [MRose85] Rose, M., and J. Romine, "The Rand MH Message Handling - System: User's Manual", University of California, Irvine, - November 1985. - - [RFC822] Crocker, D., "Standard for the Format of ARPA-Internet - Text Messages", RFC 822, University of Delaware, August - 1982. - - [RFC918] Reynolds, J., "Post Office Protocol", RFC 918, - USC/Information Sciences Institute, October 1984. - - [RFC937] Butler, M., J. Postel, D. Chase, J. Goldberger, and J. - Reynolds, "Post Office Protocol - Version 2", RFC 937, - USC/Information Sciences Institute, February 1985. - -Author's Address: - - - Marshall Rose - The Wollongong Group - 1129 San Antonio Rd. - Palo Alto, California 94303 - - Phone: (415) 962-7100 - - Email: MRose@TWG.COM - - - - - - - - - - - - - - - - -Rose [Page 11] - diff --git a/appl/popper/pop_auth.c b/appl/popper/pop_auth.c deleted file mode 100644 index 2c352b1a9..000000000 --- a/appl/popper/pop_auth.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2004 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#ifdef SASL -#include -#include -RCSID("$Id$"); - -/* - * auth: RFC1734 - */ - -static char * -getline(POP *p) -{ - char *buf = NULL; - size_t size = 1024; - buf = malloc(size); - if(buf == NULL) - return NULL; - *buf = '\0'; - while(fgets(buf + strlen(buf), size - strlen(buf), p->input) != NULL) { - char *p; - if((p = strchr(buf, '\n')) != NULL) { - while(p > buf && p[-1] == '\r') - p--; - *p = '\0'; - return buf; - } - /* just assume we ran out of buffer space, we'll catch eof - next round */ - size += 1024; - p = realloc(buf, size); - if(p == NULL) - break; - buf = p; - } - free(buf); - return NULL; -} - -static char auth_msg[128]; -void -pop_auth_set_error(const char *message) -{ - strlcpy(auth_msg, message, sizeof(auth_msg)); -} - -static struct auth_mech *methods[] = { -#ifdef KRB5 - &gssapi_mech, -#endif - NULL -}; - -static int -auth_execute(POP *p, struct auth_mech *m, void *state, const char *line) -{ - void *input, *output; - size_t input_length, output_length; - int status; - - if(line == NULL) { - input = NULL; - input_length = 0; - } else { - input = strdup(line); - if(input == NULL) { - pop_auth_set_error("out of memory"); - return POP_AUTH_FAILURE; - } - input_length = base64_decode(line, input); - if(input_length == (size_t)-1) { - pop_auth_set_error("base64 decode error"); - return POP_AUTH_FAILURE; - } - } - output = NULL; output_length = 0; - status = (*m->loop)(p, state, input, input_length, &output, &output_length); - if(output_length > 0) { - char *s; - base64_encode(output, output_length, &s); - fprintf(p->output, "+ %s\r\n", s); - fflush(p->output); - free(output); - free(s); - } - return status; -} - -static int -auth_loop(POP *p, struct auth_mech *m) -{ - int status; - void *state = NULL; - char *line; - - status = (*m->init)(p, &state); - - status = auth_execute(p, m, state, p->pop_parm[2]); - - while(status == POP_AUTH_CONTINUE) { - line = getline(p); - if(line == NULL) { - (*m->cleanup)(p, state); - return pop_msg(p, POP_FAILURE, "error reading data"); - } - if(strcmp(line, "*") == 0) { - (*m->cleanup)(p, state); - return pop_msg(p, POP_FAILURE, "terminated by client"); - } - status = auth_execute(p, m, state, line); - free(line); - } - - - (*m->cleanup)(p, state); - if(status == POP_AUTH_FAILURE) - return pop_msg(p, POP_FAILURE, "%s", auth_msg); - - status = login_user(p); - if(status != POP_SUCCESS) - return status; - return pop_msg(p, POP_SUCCESS, "authentication complete"); -} - -int -pop_auth (POP *p) -{ - int i; - - for (i = 0; methods[i] != NULL; ++i) - if (strcasecmp(p->pop_parm[1], methods[i]->name) == 0) - return auth_loop(p, methods[i]); - return pop_msg(p, POP_FAILURE, - "Authentication method %s unknown", p->pop_parm[1]); -} - -void -pop_capa_sasl(POP *p) -{ - int i; - - if(methods[0] == NULL) - return; - - fprintf(p->output, "SASL"); - for (i = 0; methods[i] != NULL; ++i) - fprintf(p->output, " %s", methods[i]->name); - fprintf(p->output, "\r\n"); -} -#endif diff --git a/appl/popper/pop_debug.c b/appl/popper/pop_debug.c deleted file mode 100644 index bca03e66e..000000000 --- a/appl/popper/pop_debug.c +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (c) 1995 - 2002 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* Tiny program to help debug popper */ - -#include "popper.h" -RCSID("$Id$"); - -static void -loop(int s) -{ - char cmd[1024]; - char buf[1024]; - fd_set fds; - while(1){ - FD_ZERO(&fds); - FD_SET(0, &fds); - FD_SET(s, &fds); - if(select(s+1, &fds, 0, 0, 0) < 0) - err(1, "select"); - if(FD_ISSET(0, &fds)){ - fgets(cmd, sizeof(cmd), stdin); - cmd[strlen(cmd) - 1] = '\0'; - strlcat (cmd, "\r\n", sizeof(cmd)); - write(s, cmd, strlen(cmd)); - } - if(FD_ISSET(s, &fds)){ - int n = read(s, buf, sizeof(buf)); - if(n == 0) - exit(0); - fwrite(buf, n, 1, stdout); - } - } -} - -static int -get_socket (const char *hostname, int port) -{ - int ret; - struct addrinfo *ai, *a; - struct addrinfo hints; - char portstr[NI_MAXSERV]; - - memset (&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_STREAM; - snprintf (portstr, sizeof(portstr), "%d", ntohs(port)); - ret = getaddrinfo (hostname, portstr, &hints, &ai); - if (ret) - errx (1, "getaddrinfo %s: %s", hostname, gai_strerror (ret)); - - for (a = ai; a != NULL; a = a->ai_next) { - int s; - - s = socket (a->ai_family, a->ai_socktype, a->ai_protocol); - if (s < 0) - continue; - if (connect (s, a->ai_addr, a->ai_addrlen) < 0) { - close (s); - continue; - } - freeaddrinfo (ai); - return s; - } - err (1, "failed to connect to %s", hostname); -} - -#ifdef KRB5 -static int -doit_v5 (char *host, int port) -{ - krb5_error_code ret; - krb5_context context; - krb5_auth_context auth_context = NULL; - krb5_principal server; - int s = get_socket (host, port); - - ret = krb5_init_context (&context); - if (ret) - errx (1, "krb5_init_context failed: %d", ret); - - ret = krb5_sname_to_principal (context, - host, - "pop", - KRB5_NT_SRV_HST, - &server); - if (ret) { - warnx ("krb5_sname_to_principal: %s", - krb5_get_err_text (context, ret)); - return 1; - } - ret = krb5_sendauth (context, - &auth_context, - &s, - "KPOPV1.0", - NULL, - server, - 0, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); - if (ret) { - warnx ("krb5_sendauth: %s", - krb5_get_err_text (context, ret)); - return 1; - } - loop (s); - return 0; -} -#endif - - -#ifdef KRB5 -static int use_v5 = -1; -#endif -static char *port_str; -static int do_version; -static int do_help; - -struct getargs args[] = { -#ifdef KRB5 - { "krb5", '5', arg_flag, &use_v5, "Use Kerberos V5", - NULL }, -#endif - { "port", 'p', arg_string, &port_str, "Use this port", - "number-or-service" }, - { "version", 0, arg_flag, &do_version, "Print version", - NULL }, - { "help", 0, arg_flag, &do_help, NULL, - NULL } -}; - -static void -usage (int ret) -{ - arg_printusage (args, - sizeof(args) / sizeof(args[0]), - NULL, - "hostname"); - exit (ret); -} - -int -main(int argc, char **argv) -{ - int port = 0; - int ret = 1; - int optind = 0; - - setprogname(argv[0]); - - if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, - &optind)) - usage (1); - - argc -= optind; - argv += optind; - - if (do_help) - usage (0); - - if (do_version) { - print_version (NULL); - return 0; - } - - if (argc < 1) - usage (1); - - if (port_str) { - struct servent *s = roken_getservbyname (port_str, "tcp"); - - if (s) - port = s->s_port; - else { - char *ptr; - - port = strtol (port_str, &ptr, 10); - if (port == 0 && ptr == port_str) - errx (1, "Bad port `%s'", port_str); - port = htons(port); - } - } - if (port == 0) { -#ifdef KRB5 - port = krb5_getportbyname (NULL, "kpop", "tcp", 1109); -#else -#error must define KRB5 -#endif - } - -#ifdef KRB5 - if (ret && use_v5) { - ret = doit_v5 (argv[0], port); - } -#endif - return ret; -} diff --git a/appl/popper/pop_dele.c b/appl/popper/pop_dele.c deleted file mode 100644 index 2328d5a22..000000000 --- a/appl/popper/pop_dele.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - */ - -#include -RCSID("$Id$"); - -/* - * dele: Delete a message from the POP maildrop - */ -int -pop_dele (POP *p) -{ - MsgInfoList * mp; /* Pointer to message info list */ - int msg_num; - - /* Convert the message number parameter to an integer */ - msg_num = atoi(p->pop_parm[1]); - - /* Is requested message out of range? */ - if ((msg_num < 1) || (msg_num > p->msg_count)) - return (pop_msg (p,POP_FAILURE,"Message %d does not exist.",msg_num)); - - /* Get a pointer to the message in the message list */ - mp = &(p->mlp[msg_num-1]); - - /* Is the message already flagged for deletion? */ - if (mp->flags & DEL_FLAG) - return (pop_msg (p,POP_FAILURE,"Message %d has already been deleted.", - msg_num)); - - /* Flag the message for deletion */ - mp->flags |= DEL_FLAG; - -#ifdef DEBUG - if(p->debug) - pop_log(p, POP_DEBUG, - "Deleting message %u at offset %ld of length %ld\n", - mp->number, mp->offset, mp->length); -#endif /* DEBUG */ - - /* Update the messages_deleted and bytes_deleted counters */ - p->msgs_deleted++; - p->bytes_deleted += mp->length; - - /* Update the last-message-accessed number if it is lower than - the deleted message */ - if (p->last_msg < msg_num) p->last_msg = msg_num; - - return (pop_msg (p,POP_SUCCESS,"Message %d has been deleted.",msg_num)); -} - -#ifdef XDELE -/* delete a range of messages */ -int -pop_xdele(POP *p) -{ - MsgInfoList * mp; /* Pointer to message info list */ - - int msg_min, msg_max; - int i; - - - msg_min = atoi(p->pop_parm[1]); - if(p->parm_count == 1) - msg_max = msg_min; - else - msg_max = atoi(p->pop_parm[2]); - - if (msg_min < 1) - return (pop_msg (p,POP_FAILURE,"Message %d does not exist.",msg_min)); - if(msg_max > p->msg_count) - return (pop_msg (p,POP_FAILURE,"Message %d does not exist.",msg_max)); - for(i = msg_min; i <= msg_max; i++) { - - /* Get a pointer to the message in the message list */ - mp = &(p->mlp[i - 1]); - - /* Is the message already flagged for deletion? */ - if (mp->flags & DEL_FLAG) - continue; /* no point in returning error */ - /* Flag the message for deletion */ - mp->flags |= DEL_FLAG; - -#ifdef DEBUG - if(p->debug) - pop_log(p, POP_DEBUG, - "Deleting message %u at offset %ld of length %ld\n", - mp->number, mp->offset, mp->length); -#endif /* DEBUG */ - - /* Update the messages_deleted and bytes_deleted counters */ - p->msgs_deleted++; - p->bytes_deleted += mp->length; - } - - /* Update the last-message-accessed number if it is lower than - the deleted message */ - if (p->last_msg < msg_max) p->last_msg = msg_max; - - return (pop_msg (p,POP_SUCCESS,"Messages %d-%d has been deleted.", - msg_min, msg_max)); - -} -#endif /* XDELE */ diff --git a/appl/popper/pop_dropcopy.c b/appl/popper/pop_dropcopy.c deleted file mode 100644 index a9939bb30..000000000 --- a/appl/popper/pop_dropcopy.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - */ - -#include -RCSID("$Id$"); - -/* - * Run as the user in `pwd' - */ - -int -changeuser(POP *p, struct passwd *pwd) -{ - if(setgid(pwd->pw_gid) < 0) { - pop_log (p, POP_PRIORITY, - "Unable to change to gid %u: %s", - (unsigned)pwd->pw_gid, - strerror(errno)); - return pop_msg (p, POP_FAILURE, - "Unable to change gid"); - } - if(setuid(pwd->pw_uid) < 0) { - pop_log (p, POP_PRIORITY, - "Unable to change to uid %u: %s", - (unsigned)pwd->pw_uid, - strerror(errno)); - return pop_msg (p, POP_FAILURE, - "Unable to change uid"); - } -#ifdef DEBUG - if(p->debug) - pop_log(p, POP_DEBUG,"uid = %u, gid = %u", - (unsigned)getuid(), - (unsigned)getgid()); -#endif /* DEBUG */ - return POP_SUCCESS; -} - -/* - * dropcopy: Make a temporary copy of the user's mail drop and - * save a stream pointer for it. - */ - -int -pop_dropcopy(POP *p, struct passwd *pwp) -{ - int mfd; /* File descriptor for - the user's maildrop */ - int dfd; /* File descriptor for - the SERVER maildrop */ - FILE *tf; /* The temp file */ - char template[POP_TMPSIZE]; /* Temp name holder */ - char buffer[BUFSIZ]; /* Read buffer */ - long offset; /* Old/New boundary */ - int nchar; /* Bytes written/read */ - int tf_fd; /* fd for temp file */ - int ret; - - /* Create a temporary maildrop into which to copy the updated maildrop */ - snprintf(p->temp_drop, sizeof(p->temp_drop), POP_DROP,p->user); - -#ifdef DEBUG - if(p->debug) - pop_log(p,POP_DEBUG,"Creating temporary maildrop '%s'", - p->temp_drop); -#endif /* DEBUG */ - - /* Here we work to make sure the user doesn't cause us to remove or - * write over existing files by limiting how much work we do while - * running as root. - */ - - strlcpy(template, POP_TMPDROP, sizeof(template)); - if ((tf_fd = mkstemp(template)) < 0 || - (tf = fdopen(tf_fd, "w+")) == NULL) { - pop_log(p,POP_PRIORITY, - "Unable to create temporary temporary maildrop '%s': %s",template, - strerror(errno)); - return pop_msg(p,POP_FAILURE, - "System error, can't create temporary file."); - } - - /* Now give this file to the user */ - chown(template, pwp->pw_uid, pwp->pw_gid); - chmod(template, 0600); - - /* Now link this file to the temporary maildrop. If this fails it - * is probably because the temporary maildrop already exists. If so, - * this is ok. We can just go on our way, because by the time we try - * to write into the file we will be running as the user. - */ - link(template,p->temp_drop); - fclose(tf); - unlink(template); - - ret = changeuser(p, pwp); - if (ret != POP_SUCCESS) - return ret; - - /* Open for append, this solves the crash recovery problem */ - if ((dfd = open(p->temp_drop,O_RDWR|O_APPEND|O_CREAT,0600)) == -1){ - pop_log(p,POP_PRIORITY, - "Unable to open temporary maildrop '%s': %s",p->temp_drop, - strerror(errno)); - return pop_msg(p,POP_FAILURE, - "System error, can't open temporary file, do you own it?"); - } - - /* Lock the temporary maildrop */ - if ( flock (dfd, (LOCK_EX | LOCK_NB)) == -1 ) - switch(errno) { - case EWOULDBLOCK: - return pop_msg(p,POP_FAILURE, - "%sMaildrop lock busy! Is another session active?", - (p->flags & POP_FLAG_CAPA) ? "[IN-USE] " : ""); - /* NOTREACHED */ - default: - return pop_msg(p,POP_FAILURE,"flock: '%s': %s", p->temp_drop, - strerror(errno)); - /* NOTREACHED */ - } - - /* May have grown or shrunk between open and lock! */ - offset = lseek(dfd,0, SEEK_END); - - /* Open the user's maildrop, If this fails, no harm in assuming empty */ - if ((mfd = open(p->drop_name,O_RDWR)) > 0) { - - /* Lock the maildrop */ - if (flock (mfd, LOCK_EX) == -1) { - close(mfd) ; - return pop_msg(p,POP_FAILURE, "flock: '%s': %s", p->temp_drop, - strerror(errno)); - } - - /* Copy the actual mail drop into the temporary mail drop */ - while ( (nchar=read(mfd,buffer,BUFSIZ)) > 0 ) - if ( nchar != write(dfd,buffer,nchar) ) { - nchar = -1 ; - break ; - } - - if ( nchar != 0 ) { - /* Error adding new mail. Truncate to original size, - and leave the maildrop as is. The user will not - see the new mail until the error goes away. - Should let them process the current backlog, in case - the error is a quota problem requiring deletions! */ - ftruncate(dfd,(int)offset) ; - } else { - /* Mail transferred! Zero the mail drop NOW, that we - do not have to do gymnastics to figure out what's new - and what is old later */ - ftruncate(mfd,0) ; - } - - /* Close the actual mail drop */ - close (mfd); - } - - /* Acquire a stream pointer for the temporary maildrop */ - if ( (p->drop = fdopen(dfd,"a+")) == NULL ) { - close(dfd) ; - return pop_msg(p,POP_FAILURE,"Cannot assign stream for %s", - p->temp_drop); - } - - rewind (p->drop); - - return(POP_SUCCESS); -} diff --git a/appl/popper/pop_dropinfo.c b/appl/popper/pop_dropinfo.c deleted file mode 100644 index b5e57b398..000000000 --- a/appl/popper/pop_dropinfo.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - */ - -#include -RCSID("$Id$"); - -#if defined(UIDL) || defined(XOVER) - -/* - * Copy the string found after after : into a malloced buffer. Stop - * copying at end of string or end of line. End of line delimiter is - * not part of the resulting copy. - */ -static -char * -find_value_after_colon(char *p) -{ - char *t, *tmp; - - for (; *p != 0 && *p != ':'; p++) /* Find : */ - ; - - if (*p == 0) - goto error; - - p++; /* Skip over : */ - - for(; *p == ' ' || *p == '\t'; p++) /* Remove white space */ - ; - - for (t = p; *t != 0 && *t != '\n' && *t != '\r'; t++) /* Find end of str */ - ; - - tmp = t = malloc(t - p + 1); - if (tmp == 0) - goto error; - - for (; *p != 0 && *p != '\n' && *p != '\r'; p++, t++) /* Copy characters */ - *t = *p; - *t = 0; /* Terminate string */ - return tmp; - -error: - return "ErrorUIDL"; -} -#endif - -void -parse_header(MsgInfoList *mp, char *buffer) -{ -#if defined(UIDL) || defined(XOVER) - if (strncasecmp("Message-Id:",buffer, 11) == 0) { - if (mp->msg_id == NULL) - mp->msg_id = find_value_after_colon(buffer); - } -#ifdef UIDL - else if (strncasecmp(buffer, "X-UIDL:", 7) == 0) { - /* Courtesy to Qualcomm, there really is no such - thing as X-UIDL */ - mp->msg_id = find_value_after_colon(buffer); - } -#endif -#endif -#ifdef XOVER - else if (strncasecmp("Subject:", buffer, 8) == 0) { - if(mp->subject == NULL){ - char *p; - mp->subject = find_value_after_colon(buffer); - for(p = mp->subject; *p; p++) - if(*p == '\t') *p = ' '; - } - } - else if (strncasecmp("From:", buffer, 5) == 0) { - if(mp->from == NULL){ - char *p; - mp->from = find_value_after_colon(buffer); - for(p = mp->from; *p; p++) - if(*p == '\t') *p = ' '; - } - } - else if (strncasecmp("Date:", buffer, 5) == 0) { - if(mp->date == NULL){ - char *p; - mp->date = find_value_after_colon(buffer); - for(p = mp->date; *p; p++) - if(*p == '\t') *p = ' '; - } - } -#endif -} - -int -add_missing_headers(POP *p, MsgInfoList *mp) -{ -#if defined(UIDL) || defined(XOVER) - if (mp->msg_id == NULL) { - if (asprintf(&mp->msg_id, "no-message-id-%d", mp->number) == -1) { - fclose (p->drop); - p->msg_count = 0; - return pop_msg (p,POP_FAILURE, - "Can't build message list for '%s': Out of memory", - p->user); - } - } -#endif -#ifdef XOVER - if (mp->subject == NULL) - mp->subject = ""; - if (mp->from == NULL) - mp->from = ""; - if (mp->date == NULL) - mp->date = ""; -#endif - return POP_SUCCESS; -} - -/* - * dropinfo: Extract information about the POP maildrop and store - * it for use by the other POP routines. - */ - -int -pop_dropinfo(POP *p) -{ - char buffer[BUFSIZ]; /* Read buffer */ - MsgInfoList * mp; /* Pointer to message - info list */ - int msg_num; /* Current message - counter */ - int nchar; /* Bytes written/read */ - int blank_line = 1; /* previous line was blank */ - int in_header = 0; /* if we are in a header block */ - - /* Initialize maildrop status variables in the POP parameter block */ - p->msg_count = 0; - p->msgs_deleted = 0; - p->last_msg = 0; - p->bytes_deleted = 0; - p->drop_size = 0; - - /* Allocate memory for message information structures */ - p->msg_count = ALLOC_MSGS; - p->mlp = (MsgInfoList *)calloc((unsigned)p->msg_count,sizeof(MsgInfoList)); - if (p->mlp == NULL){ - fclose (p->drop); - p->msg_count = 0; - return pop_msg (p,POP_FAILURE, - "Can't build message list for '%s': Out of memory", p->user); - } - - rewind (p->drop); - - /* Scan the file, loading the message information list with - information about each message */ - - for (msg_num = p->drop_size = 0, mp = p->mlp - 1; - fgets(buffer,MAXMSGLINELEN,p->drop);) { - - nchar = strlen(buffer); - - if (blank_line && strncmp(buffer,"From ",5) == 0) { - in_header = 1; - if (++msg_num > p->msg_count) { - p->mlp=(MsgInfoList *) realloc(p->mlp, - (p->msg_count+=ALLOC_MSGS)*sizeof(MsgInfoList)); - if (p->mlp == NULL){ - fclose (p->drop); - p->msg_count = 0; - return pop_msg (p,POP_FAILURE, - "Can't build message list for '%s': Out of memory", - p->user); - } - mp = p->mlp + msg_num - 2; - } - ++mp; - mp->number = msg_num; - mp->length = 0; - mp->lines = 0; - mp->offset = ftell(p->drop) - nchar; - mp->flags = 0; -#if defined(UIDL) || defined(XOVER) - mp->msg_id = 0; -#endif -#ifdef XOVER - mp->subject = 0; - mp->from = 0; - mp->date = 0; -#endif -#ifdef DEBUG - if(p->debug) - pop_log(p, POP_DEBUG, - "Msg %d at offset %ld being added to list", - mp->number, mp->offset); -#endif /* DEBUG */ - } else if(in_header) - parse_header(mp, buffer); - blank_line = (strncmp(buffer, "\n", nchar) == 0); - if(blank_line) { - int e; - in_header = 0; - e = add_missing_headers(p, mp); - if(e != POP_SUCCESS) - return e; - } - mp->length += nchar; - p->drop_size += nchar; - mp->lines++; - } - p->msg_count = msg_num; - -#ifdef DEBUG - if(p->debug && msg_num > 0) { - int i; - for (i = 0, mp = p->mlp; i < p->msg_count; i++, mp++) -#ifdef UIDL - pop_log(p,POP_DEBUG, - "Msg %d at offset %ld is %ld octets long and has %u lines and id %s.", - mp->number,mp->offset,mp->length,mp->lines, mp->msg_id); -#else - pop_log(p,POP_DEBUG, - "Msg %d at offset %d is %d octets long and has %u lines.", - mp->number,mp->offset,mp->length,mp->lines); -#endif - } -#endif /* DEBUG */ - - return(POP_SUCCESS); -} diff --git a/appl/popper/pop_get_command.c b/appl/popper/pop_get_command.c deleted file mode 100644 index df197f642..000000000 --- a/appl/popper/pop_get_command.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - */ - -#include -RCSID("$Id$"); - -/* - * get_command: Extract the command from an input line form a POP client - */ - -int pop_capa (POP *p); -static state_table states[] = { - {auth1, "user", 1, 1, pop_user, {auth1, auth2}}, - {auth2, "pass", 1, 99, pop_pass, {auth1, trans}}, -#ifdef RPOP - {auth2, "rpop", 1, 1, pop_rpop, {auth1, trans}}, -#endif /* RPOP */ -#ifdef SASL - {auth1, "auth", 1, 2, pop_auth, {auth1, trans}}, -#endif - {auth1, "quit", 0, 0, pop_quit, {halt, halt}}, - {auth2, "quit", 0, 0, pop_quit, {halt, halt}}, -#ifdef CAPA - {auth1, "capa", 0, 0, pop_capa, {auth1, auth1}}, - {auth2, "capa", 0, 0, pop_capa, {auth2, auth2}}, - {trans, "capa", 0, 0, pop_capa, {trans, trans}}, -#endif - {trans, "stat", 0, 0, pop_stat, {trans, trans}}, - {trans, "list", 0, 1, pop_list, {trans, trans}}, - {trans, "retr", 1, 1, pop_send, {trans, trans}}, - {trans, "dele", 1, 1, pop_dele, {trans, trans}}, - {trans, "noop", 0, 0, NULL, {trans, trans}}, - {trans, "rset", 0, 0, pop_rset, {trans, trans}}, - {trans, "top", 2, 2, pop_send, {trans, trans}}, - {trans, "last", 0, 0, pop_last, {trans, trans}}, - {trans, "quit", 0, 0, pop_updt, {halt, halt}}, - {trans, "help", 0, 0, pop_help, {trans, trans}}, -#ifdef UIDL - {trans, "uidl", 0, 1, pop_uidl, {trans, trans}}, -#endif -#ifdef XOVER - {trans, "xover", 0, 0, pop_xover, {trans, trans}}, -#endif -#ifdef XDELE - {trans, "xdele", 1, 2, pop_xdele, {trans, trans}}, -#endif - {(state) 0, NULL, 0, 0, NULL, {halt, halt}}, -}; - -int -pop_capa (POP *p) -{ - /* Search for the POP command in the command/state table */ - pop_msg (p,POP_SUCCESS, "Capability list follows"); - if(p->auth_level == AUTH_NONE || p->auth_level == AUTH_OTP) - fprintf(p->output, "USER\r\n"); - fprintf(p->output, "TOP\r\n"); - fprintf(p->output, "PIPELINING\r\n"); - fprintf(p->output, "EXPIRE NEVER\r\n"); - fprintf(p->output, "RESP-CODES\r\n"); -#ifdef SASL - pop_capa_sasl(p); -#endif -#ifdef UIDL - fprintf(p->output, "UIDL\r\n"); -#endif -#ifdef XOVER - fprintf(p->output, "XOVER\r\n"); -#endif -#ifdef XDELE - fprintf(p->output, "XDELE\r\n"); -#endif - if(p->CurrentState == trans) - fprintf(p->output, "IMPLEMENTATION %s-%s\r\n", PACKAGE, VERSION); - fprintf(p->output,".\r\n"); - fflush(p->output); - - p->flags |= POP_FLAG_CAPA; - - return(POP_SUCCESS); -} - -state_table * -pop_get_command(POP *p, char *mp) -{ - state_table * s; - char buf[MAXMSGLINELEN]; - - /* Save a copy of the original client line */ -#ifdef DEBUG - if(p->debug) strlcpy (buf, mp, sizeof(buf)); -#endif /* DEBUG */ - - /* Parse the message into the parameter array */ - if ((p->parm_count = pop_parse(p,mp)) < 0) return(NULL); - - /* Do not log cleartext passwords */ -#ifdef DEBUG - if(p->debug){ - if(strcmp(p->pop_command,"pass") == 0) - pop_log(p,POP_DEBUG,"Received: \"%s xxxxxxxxx\"",p->pop_command); - else { - /* Remove trailing */ - buf[strlen(buf)-2] = '\0'; - pop_log(p,POP_DEBUG,"Received: \"%s\"",buf); - } - } -#endif /* DEBUG */ - - /* Search for the POP command in the command/state table */ - for (s = states; s->command; s++) { - - /* Is this a valid command for the current operating state? */ - if (strcmp(s->command,p->pop_command) == 0 - && s->ValidCurrentState == p->CurrentState) { - - /* Were too few parameters passed to the command? */ - if (p->parm_count < s->min_parms) { - pop_msg(p,POP_FAILURE, - "Too few arguments for the %s command.", - p->pop_command); - return NULL; - } - - /* Were too many parameters passed to the command? */ - if (p->parm_count > s->max_parms) { - pop_msg(p,POP_FAILURE, - "Too many arguments for the %s command.", - p->pop_command); - return NULL; - } - - /* Return a pointer to the entry for this command in - the command/state table */ - return (s); - } - } - /* The client command was not located in the command/state table */ - pop_msg(p,POP_FAILURE, - "Unknown command: \"%s\".",p->pop_command); - return NULL; -} - -int -pop_help (POP *p) -{ - state_table *s; - - pop_msg(p, POP_SUCCESS, "help"); - - for (s = states; s->command; s++) { - fprintf (p->output, "%s\r\n", s->command); - } - fprintf (p->output, ".\r\n"); - fflush (p->output); - return POP_SUCCESS; -} diff --git a/appl/popper/pop_init.c b/appl/popper/pop_init.c deleted file mode 100644 index a2924877d..000000000 --- a/appl/popper/pop_init.c +++ /dev/null @@ -1,364 +0,0 @@ -/* - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - */ - -#include -RCSID("$Id$"); - - -#if defined(KRB5) - -static int -pop_net_read(POP *p, int fd, void *buf, size_t len) -{ -#ifdef KRB5 - return krb5_net_read(p->context, &fd, buf, len); -#else -#error must define KRB5 -#endif -} -#endif - -static char *addr_log; - -static void -pop_write_addr(POP *p, struct sockaddr *addr) -{ - char ts[32]; - char as[128]; - time_t t; - FILE *f; - if(addr_log == NULL) - return; - t = time(NULL); - strftime(ts, sizeof(ts), "%Y%m%d%H%M%S", localtime(&t)); - if(inet_ntop (addr->sa_family, socket_get_address(addr), - as, sizeof(as)) == NULL) { - pop_log(p, POP_PRIORITY, "failed to print address"); - return; - } - - f = fopen(addr_log, "a"); - if(f == NULL) { - pop_log(p, POP_PRIORITY, "failed to open address log (%s)", addr_log); - return; - } - fprintf(f, "%s %s\n", as, ts); - fclose(f); -} - -#ifdef KRB5 -static int -krb5_authenticate (POP *p, int s, u_char *buf, struct sockaddr *addr) -{ - krb5_error_code ret; - krb5_auth_context auth_context = NULL; - uint32_t len; - krb5_ticket *ticket; - char *server; - - if (memcmp (buf, "\x00\x00\x00\x13", 4) != 0) - return -1; - len = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3]); - - if (krb5_net_read(p->context, &s, buf, len) != len) - return -1; - if (len != sizeof(KRB5_SENDAUTH_VERSION) - || memcmp (buf, KRB5_SENDAUTH_VERSION, len) != 0) - return -1; - - ret = krb5_recvauth (p->context, - &auth_context, - &s, - "KPOPV1.0", - NULL, /* let rd_req figure out what server to use */ - KRB5_RECVAUTH_IGNORE_VERSION, - NULL, - &ticket); - if (ret) { - pop_log(p, POP_PRIORITY, "krb5_recvauth: %s", - krb5_get_err_text(p->context, ret)); - return -1; - } - - - ret = krb5_unparse_name(p->context, ticket->server, &server); - if(ret) { - pop_log(p, POP_PRIORITY, "krb5_unparse_name: %s", - krb5_get_err_text(p->context, ret)); - ret = -1; - goto out; - } - /* does this make sense? */ - if(strncmp(server, "pop/", 4) != 0) { - pop_log(p, POP_PRIORITY, - "Got ticket for service `%s'", server); - ret = -1; - goto out; - } else if(p->debug) - pop_log(p, POP_DEBUG, - "Accepted ticket for service `%s'", server); - free(server); - out: - krb5_auth_con_free (p->context, auth_context); - krb5_copy_principal (p->context, ticket->client, &p->principal); - krb5_free_ticket (p->context, ticket); - - return ret; -} -#endif - -static int -krb_authenticate(POP *p, struct sockaddr *addr) -{ -#if defined(KRB5) - u_char buf[BUFSIZ]; - - if (pop_net_read (p, 0, buf, 4) != 4) { - pop_msg(p, POP_FAILURE, "Reading four bytes: %s", - strerror(errno)); - exit (1); - } - if (krb5_authenticate (p, 0, buf, addr) == 0){ - pop_write_addr(p, addr); - p->version = 5; - return POP_SUCCESS; - } -#endif - exit (1); - - return(POP_SUCCESS); -} - -static int -plain_authenticate (POP *p, struct sockaddr *addr) -{ - return(POP_SUCCESS); -} - -static int kerberos_flag; -static char *auth_str; -static int debug_flag; -static int interactive_flag; -static char *port_str; -static char *trace_file; -static int timeout; -static int help_flag; -static int version_flag; - -static struct getargs args[] = { -#if defined(KRB5) - { "kerberos", 'k', arg_flag, &kerberos_flag, "use kerberos" }, -#endif - { "auth-mode", 'a', arg_string, &auth_str, "required authentication", - "plaintext" -#ifdef OTP - "|otp" -#endif -#ifdef SASL - "|sasl" -#endif - }, - { "debug", 'd', arg_flag, &debug_flag }, - { "interactive", 'i', arg_flag, &interactive_flag, "create new socket" }, - { "port", 'p', arg_string, &port_str, "port to listen to", "port" }, - { "trace-file", 't', arg_string, &trace_file, "trace all command to file", "file" }, - { "timeout", 'T', arg_integer, &timeout, "timeout", "seconds" }, - { "address-log", 0, arg_string, &addr_log, "enable address log", "file" }, - { "help", 'h', arg_flag, &help_flag }, - { "version", 'v', arg_flag, &version_flag } -}; - -static int num_args = sizeof(args) / sizeof(args[0]); - -/* - * init: Start a Post Office Protocol session - */ - -static int -pop_getportbyname(POP *p, const char *service, - const char *proto, short def) -{ -#ifdef KRB5 - return krb5_getportbyname(p->context, service, proto, def); -#else - return htons(default); -#endif -} - -int -pop_init(POP *p,int argcount,char **argmessage) -{ - struct sockaddr_storage cs_ss; - struct sockaddr *cs = (struct sockaddr *)&cs_ss; - socklen_t len; - char * trace_file_name = "/tmp/popper-trace"; - int portnum = 0; - int optind = 0; - int error; - - /* Initialize the POP parameter block */ - memset (p, 0, sizeof(POP)); - - setprogname(argmessage[0]); - - /* Save my name in a global variable */ - p->myname = (char*)getprogname(); - - /* Get the name of our host */ - gethostname(p->myhost,MaxHostNameLen); - -#ifdef KRB5 - { - krb5_error_code ret; - - ret = krb5_init_context (&p->context); - if (ret) - errx (1, "krb5_init_context failed: %d", ret); - - krb5_openlog(p->context, p->myname, &p->logf); - krb5_set_warn_dest(p->context, p->logf); - } -#else - /* Open the log file */ - roken_openlog(p->myname,POP_LOGOPTS,POP_FACILITY); -#endif - - p->auth_level = AUTH_NONE; - - if(getarg(args, num_args, argcount, argmessage, &optind)){ - arg_printusage(args, num_args, NULL, ""); - exit(1); - } - if(help_flag){ - arg_printusage(args, num_args, NULL, ""); - exit(0); - } - if(version_flag){ - print_version(NULL); - exit(0); - } - - argcount -= optind; - argmessage += optind; - - if (argcount != 0) { - arg_printusage(args, num_args, NULL, ""); - exit(1); - } - - if(auth_str){ - if (strcasecmp (auth_str, "plaintext") == 0 || - strcasecmp (auth_str, "none") == 0) - p->auth_level = AUTH_NONE; - else if(strcasecmp(auth_str, "otp") == 0) { -#ifdef OTP - p->auth_level = AUTH_OTP; -#else - pop_log (p, POP_PRIORITY, "support for OTP not enabled"); - exit(1); -#endif - } else if(strcasecmp(auth_str, "sasl") == 0) { -#ifdef SASL - p->auth_level = AUTH_SASL; -#else - pop_log (p, POP_PRIORITY, "support for SASL not enabled"); - exit(1); -#endif - } else { - pop_log (p, POP_PRIORITY, "bad value for -a: %s", auth_str); - exit(1); - } - } - /* Debugging requested */ - p->debug = debug_flag; - - if(port_str) - portnum = htons(atoi(port_str)); - if(trace_file){ - p->debug++; - if ((p->trace = fopen(trace_file, "a+")) == NULL) { - pop_log(p, POP_PRIORITY, - "Unable to open trace file \"%s\", err = %d", - optarg,errno); - exit (1); - } - trace_file_name = trace_file; - } - -#if defined(KRB5) - p->kerberosp = kerberos_flag; -#endif - - if(timeout) - pop_timeout = timeout; - - /* Fake inetd */ - if (interactive_flag) { - if (portnum == 0) - portnum = p->kerberosp ? - pop_getportbyname(p, "kpop", "tcp", 1109) : - pop_getportbyname(p, "pop", "tcp", 110); - mini_inetd (portnum); - } - - /* Get the address and socket of the client to whom I am speaking */ - len = sizeof(cs_ss); - if (getpeername(STDIN_FILENO, cs, &len) < 0) { - pop_log(p,POP_PRIORITY, - "Unable to obtain socket and address of client, err = %d",errno); - exit (1); - } - - /* Save the dotted decimal form of the client's IP address - in the POP parameter block */ - inet_ntop (cs->sa_family, socket_get_address (cs), - p->ipaddr, sizeof(p->ipaddr)); - - /* Save the client's port */ - p->ipport = ntohs(socket_get_port (cs)); - - /* Get the canonical name of the host to whom I am speaking */ - error = getnameinfo_verified (cs, len, p->client, sizeof(p->client), - NULL, 0, 0); - if (error) { - pop_log (p, POP_PRIORITY, - "getnameinfo: %s", gai_strerror (error)); - strlcpy (p->client, p->ipaddr, sizeof(p->client)); - } - - /* Create input file stream for TCP/IP communication */ - if ((p->input = fdopen(STDIN_FILENO,"r")) == NULL){ - pop_log(p,POP_PRIORITY, - "Unable to open communication stream for input, err = %d",errno); - exit (1); - } - - /* Create output file stream for TCP/IP communication */ - if ((p->output = fdopen(STDOUT_FILENO,"w")) == NULL){ - pop_log(p,POP_PRIORITY, - "Unable to open communication stream for output, err = %d",errno); - exit (1); - } - - pop_log(p,POP_PRIORITY, - "(v%s) Servicing request from \"%s\" at %s\n", - VERSION,p->client,p->ipaddr); - -#ifdef DEBUG - if (p->trace) - pop_log(p,POP_PRIORITY, - "Tracing session and debugging information in file \"%s\"", - trace_file_name); - else if (p->debug) - pop_log(p,POP_PRIORITY,"Debugging turned on"); -#endif /* DEBUG */ - - - if(p->kerberosp) - return krb_authenticate(p, cs); - else - return plain_authenticate(p, cs); -} diff --git a/appl/popper/pop_last.c b/appl/popper/pop_last.c deleted file mode 100644 index 8f159e664..000000000 --- a/appl/popper/pop_last.c +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - */ - -#include -RCSID("$Id$"); - -/* - * last: Display the last message touched in a POP session - */ - -int -pop_last (POP *p) -{ - return (pop_msg(p,POP_SUCCESS,"%u is the last message seen.",p->last_msg)); -} diff --git a/appl/popper/pop_list.c b/appl/popper/pop_list.c deleted file mode 100644 index b7f0d1f99..000000000 --- a/appl/popper/pop_list.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - */ - -#include -RCSID("$Id$"); - -/* - * list: List the contents of a POP maildrop - */ - -int -pop_list (POP *p) -{ - MsgInfoList * mp; /* Pointer to message info list */ - int i; - int msg_num; - - /* Was a message number provided? */ - if (p->parm_count > 0) { - msg_num = atoi(p->pop_parm[1]); - - /* Is requested message out of range? */ - if ((msg_num < 1) || (msg_num > p->msg_count)) - return (pop_msg (p,POP_FAILURE, - "Message %d does not exist.",msg_num)); - - /* Get a pointer to the message in the message list */ - mp = &p->mlp[msg_num-1]; - - /* Is the message already flagged for deletion? */ - if (mp->flags & DEL_FLAG) - return (pop_msg (p,POP_FAILURE, - "Message %d has been deleted.",msg_num)); - - /* Display message information */ - return (pop_msg(p,POP_SUCCESS,"%d %ld",msg_num,mp->length)); - } - - /* Display the entire list of messages */ - pop_msg(p,POP_SUCCESS, - "%d messages (%ld octets)", - p->msg_count-p->msgs_deleted, - p->drop_size-p->bytes_deleted); - - /* Loop through the message information list. Skip deleted messages */ - for (i = p->msg_count, mp = p->mlp; i > 0; i--, mp++) { - if (!(mp->flags & DEL_FLAG)) - fprintf(p->output,"%u %lu\r\n",mp->number,mp->length); - } - - /* "." signals the end of a multi-line transmission */ - fprintf(p->output,".\r\n"); - fflush(p->output); - - return(POP_SUCCESS); -} diff --git a/appl/popper/pop_log.c b/appl/popper/pop_log.c deleted file mode 100644 index 3ae501962..000000000 --- a/appl/popper/pop_log.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - */ - -#include -RCSID("$Id$"); - -/* - * log: Make a log entry - */ - -int -pop_log(POP *p, int stat, char *format, ...) -{ - char msgbuf[MAXLINELEN]; - va_list ap; - - va_start(ap, format); - vsnprintf(msgbuf, sizeof(msgbuf), format, ap); - - if (p->debug && p->trace) { - fprintf(p->trace,"%s\n",msgbuf); - fflush(p->trace); - } else { -#ifdef KRB5 - krb5_log(p->context, p->logf, stat, "%s", msgbuf); -#else - syslog (stat,"%s",msgbuf); -#endif - } - va_end(ap); - - return(stat); -} diff --git a/appl/popper/pop_msg.c b/appl/popper/pop_msg.c deleted file mode 100644 index a197a41db..000000000 --- a/appl/popper/pop_msg.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - */ - -#include -RCSID("$Id$"); - -/* - * msg: Send a formatted line to the POP client - */ - -int -pop_msg(POP *p, int stat, const char *format, ...) -{ - char *mp; - char message[MAXLINELEN]; - va_list ap; - - va_start(ap, format); - - /* Point to the message buffer */ - mp = message; - - /* Format the POP status code at the beginning of the message */ - snprintf (mp, sizeof(message), "%s ", - (stat == POP_SUCCESS) ? POP_OK : POP_ERR); - - /* Point past the POP status indicator in the message message */ - mp += strlen(mp); - - /* Append the message (formatted, if necessary) */ - if (format) - vsnprintf (mp, sizeof(message) - strlen(message), - format, ap); - - /* Log the message if debugging is turned on */ -#ifdef DEBUG - if (p->debug && stat == POP_SUCCESS) - pop_log(p,POP_DEBUG,"%s",message); -#endif /* DEBUG */ - - /* Log the message if a failure occurred */ - if (stat != POP_SUCCESS) - pop_log(p,POP_PRIORITY,"%s",message); - - /* Append the */ - strlcat(message, "\r\n", sizeof(message)); - - /* Send the message to the client */ - fputs(message, p->output); - fflush(p->output); - - va_end(ap); - return(stat); -} diff --git a/appl/popper/pop_parse.c b/appl/popper/pop_parse.c deleted file mode 100644 index c4bbbc074..000000000 --- a/appl/popper/pop_parse.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - */ - -#include -RCSID("$Id$"); - -/* - * parse: Parse a raw input line from a POP client - * into null-delimited tokens - */ - -int -pop_parse(POP *p, char *buf) -{ - char * mp; - int i; - - /* Loop through the POP command array */ - for (mp = buf, i = 0; ; i++) { - - /* Skip leading spaces and tabs in the message */ - while (isspace((unsigned char)*mp))mp++; - - /* Are we at the end of the message? */ - if (*mp == 0) break; - - /* Have we already obtained the maximum allowable parameters? */ - if (i >= MAXPARMCOUNT) { - pop_msg(p,POP_FAILURE,"Too many arguments supplied."); - return(-1); - } - - /* Point to the start of the token */ - p->pop_parm[i] = mp; - - /* Search for the first space character (end of the token) */ - while (!isspace((unsigned char)*mp) && *mp) mp++; - - /* Delimit the token with a null */ - if (*mp) *mp++ = 0; - } - - /* Were any parameters passed at all? */ - if (i == 0) return (-1); - - /* Convert the first token (POP command) to lower case */ - strlwr(p->pop_command); - - /* Return the number of tokens extracted minus the command itself */ - return (i-1); - -} diff --git a/appl/popper/pop_pass.c b/appl/popper/pop_pass.c deleted file mode 100644 index e7f9aeb80..000000000 --- a/appl/popper/pop_pass.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - */ - -#include -#ifdef HAVE_CRYPT_H -#include -#endif - -RCSID("$Id$"); - -#ifdef KRB5 -static int -krb5_verify_password (POP *p) -{ - krb5_preauthtype pre_auth_types[] = {KRB5_PADATA_ENC_TIMESTAMP}; - krb5_get_init_creds_opt *get_options; - krb5_verify_init_creds_opt verify_options; - krb5_error_code ret; - krb5_principal client, server; - krb5_creds creds; - - ret = krb5_get_init_creds_opt_alloc (p->context, &get_options); - if (ret) { - pop_log(p, POP_PRIORITY, "krb5_get_init_creds_opt_alloc: %s", - krb5_get_err_text (p->context, ret)); - return 1; - } - - krb5_get_init_creds_opt_set_preauth_list (get_options, - pre_auth_types, - 1); - - krb5_verify_init_creds_opt_init (&verify_options); - - ret = krb5_parse_name (p->context, p->user, &client); - if (ret) { - krb5_get_init_creds_opt_free(p->context, get_options); - pop_log(p, POP_PRIORITY, "krb5_parse_name: %s", - krb5_get_err_text (p->context, ret)); - return 1; - } - - ret = krb5_get_init_creds_password (p->context, - &creds, - client, - p->pop_parm[1], - NULL, - NULL, - 0, - NULL, - get_options); - krb5_get_init_creds_opt_free(p->context, get_options); - if (ret) { - pop_log(p, POP_PRIORITY, - "krb5_get_init_creds_password: %s", - krb5_get_err_text (p->context, ret)); - return 1; - } - - ret = krb5_sname_to_principal (p->context, - p->myhost, - "pop", - KRB5_NT_SRV_HST, - &server); - if (ret) { - pop_log(p, POP_PRIORITY, - "krb5_get_init_creds_password: %s", - krb5_get_err_text (p->context, ret)); - return 1; - } - - ret = krb5_verify_init_creds (p->context, - &creds, - server, - NULL, - NULL, - &verify_options); - krb5_free_principal (p->context, client); - krb5_free_principal (p->context, server); - krb5_free_cred_contents (p->context, &creds); - return ret; -} -#endif -/* - * pass: Obtain the user password from a POP client - */ - -int -login_user(POP *p) -{ - struct stat st; - struct passwd *pw; - - /* Look for the user in the password file */ - if ((pw = k_getpwnam(p->user)) == NULL) { - pop_log(p, POP_PRIORITY, "user %s (from %s) not found", - p->user, p->ipaddr); - return pop_msg(p, POP_FAILURE, "Login incorrect."); - } - - pop_log(p, POP_INFO, "login from %s as %s", p->ipaddr, p->user); - - /* Build the name of the user's maildrop */ - snprintf(p->drop_name, sizeof(p->drop_name), "%s/%s", POP_MAILDIR, p->user); - if(stat(p->drop_name, &st) < 0 || !S_ISDIR(st.st_mode)){ - /* Make a temporary copy of the user's maildrop */ - /* and set the group and user id */ - if (pop_dropcopy(p, pw) != POP_SUCCESS) return (POP_FAILURE); - - /* Get information about the maildrop */ - if (pop_dropinfo(p) != POP_SUCCESS) return(POP_FAILURE); - } else { - if(changeuser(p, pw) != POP_SUCCESS) return POP_FAILURE; - if(pop_maildir_info(p) != POP_SUCCESS) return POP_FAILURE; - } - /* Initialize the last-message-accessed number */ - p->last_msg = 0; - return POP_SUCCESS; -} - -int -pop_pass (POP *p) -{ - struct passwd *pw; - int i; - int status; - - /* Make one string of all these parameters */ - - for (i = 1; i < p->parm_count; ++i) - p->pop_parm[i][strlen(p->pop_parm[i])] = ' '; - - /* Look for the user in the password file */ - if ((pw = k_getpwnam(p->user)) == NULL) - return (pop_msg(p,POP_FAILURE, - "Password supplied for \"%s\" is incorrect.", - p->user)); - - if (p->kerberosp) { -#ifdef KRB5 - if (p->version == 5) { - char *name; - - if (!krb5_kuserok (p->context, p->principal, p->user)) { - pop_log (p, POP_PRIORITY, - "krb5 permission denied"); - return pop_msg(p, POP_FAILURE, - "Popping not authorized"); - } - if(krb5_unparse_name (p->context, p->principal, &name) == 0) { - pop_log(p, POP_INFO, "%s: %s -> %s", - p->ipaddr, name, p->user); - free (name); - } - } else { - pop_log (p, POP_PRIORITY, "kerberos authentication failed"); - return pop_msg (p, POP_FAILURE, - "kerberos authentication failed"); - } -#endif - { } - } else { - /* We don't accept connections from users with null passwords */ - if (pw->pw_passwd == NULL) - return (pop_msg(p, - POP_FAILURE, - "Password supplied for \"%s\" is incorrect.", - p->user)); - -#ifdef OTP - if (otp_verify_user (&p->otp_ctx, p->pop_parm[1]) == 0) - /* pass OK */; - else -#endif - /* Compare the supplied password with the password file entry */ - if (p->auth_level != AUTH_NONE) - return pop_msg(p, POP_FAILURE, - "Password supplied for \"%s\" is incorrect.", - p->user); - else if (!strcmp(crypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd)) - /* pass OK */; - else { - int ret = -1; -#ifdef KRB5 - if(ret) - ret = krb5_verify_password (p); -#endif - if(ret) - return pop_msg(p, POP_FAILURE, - "Password incorrect"); - } - } - status = login_user(p); - if(status != POP_SUCCESS) - return status; - - /* Authorization completed successfully */ - return (pop_msg (p, POP_SUCCESS, - "%s has %d message(s) (%ld octets).", - p->user, p->msg_count, p->drop_size)); -} diff --git a/appl/popper/pop_quit.c b/appl/popper/pop_quit.c deleted file mode 100644 index ebea91d3b..000000000 --- a/appl/popper/pop_quit.c +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - */ - -#include -RCSID("$Id$"); - -/* - * quit: Terminate a POP session - */ - -int -pop_quit (POP *p) -{ - /* Release the message information list */ - if (p->mlp) free (p->mlp); - - return(POP_SUCCESS); -} diff --git a/appl/popper/pop_rset.c b/appl/popper/pop_rset.c deleted file mode 100644 index 78d2b5dcf..000000000 --- a/appl/popper/pop_rset.c +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - */ - -#include -RCSID("$Id$"); - -/* - * rset: Unflag all messages flagged for deletion in a POP maildrop - */ - -int -pop_rset (POP *p) -{ - MsgInfoList * mp; /* Pointer to the message info list */ - int i; - - /* Unmark all the messages */ - for (i = p->msg_count, mp = p->mlp; i > 0; i--, mp++) - mp->flags &= ~DEL_FLAG; - - /* Reset the messages-deleted and bytes-deleted counters */ - p->msgs_deleted = 0; - p->bytes_deleted = 0; - - /* Reset the last-message-access flag */ - p->last_msg = 0; - - return (pop_msg(p,POP_SUCCESS,"Maildrop has %u messages (%ld octets)", - p->msg_count, p->drop_size)); -} diff --git a/appl/popper/pop_send.c b/appl/popper/pop_send.c deleted file mode 100644 index 5054077b0..000000000 --- a/appl/popper/pop_send.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - */ - -#include -RCSID("$Id$"); - -/* - * sendline: Send a line of a multi-line response to a client. - */ -static int -pop_sendline(POP *p, char *buffer) -{ - char * bp; - - /* Byte stuff lines that begin with the termination octet */ - if (*buffer == POP_TERMINATE) - fputc(POP_TERMINATE,p->output); - - /* Look for a in the buffer */ - if ((bp = strchr(buffer, '\n'))) - *bp = 0; - - /* Send the line to the client */ - fputs(buffer,p->output); - -#ifdef DEBUG - if(p->debug) - pop_log(p,POP_DEBUG,"Sending line \"%s\"",buffer); -#endif /* DEBUG */ - - /* Put a if a newline was removed from the buffer */ - if (bp) - fputs ("\r\n",p->output); - return bp != NULL; -} - -/* - * send: Send the header and a specified number of lines - * from a mail message to a POP client. - */ - -int -pop_send(POP *p) -{ - MsgInfoList * mp; /* Pointer to message info list */ - int msg_num; - int msg_lines; - char buffer[MAXMSGLINELEN]; -#ifdef RETURN_PATH_HANDLING - char * return_path_adr; - char * return_path_end; - int return_path_sent; - int return_path_linlen; -#endif - int sent_nl = 0; - - /* Convert the first parameter into an integer */ - msg_num = atoi(p->pop_parm[1]); - - /* Is requested message out of range? */ - if ((msg_num < 1) || (msg_num > p->msg_count)) - return (pop_msg (p,POP_FAILURE,"Message %d does not exist.",msg_num)); - - /* Get a pointer to the message in the message list */ - mp = &p->mlp[msg_num-1]; - - /* Is the message flagged for deletion? */ - if (mp->flags & DEL_FLAG) - return (pop_msg (p,POP_FAILURE, - "Message %d has been deleted.",msg_num)); - - /* If this is a TOP command, get the number of lines to send */ - if (strcmp(p->pop_command, "top") == 0) { - /* Convert the second parameter into an integer */ - msg_lines = atoi(p->pop_parm[2]); - } - else { - /* Assume that a RETR (retrieve) command was issued */ - msg_lines = -1; - /* Flag the message as retreived */ - mp->flags |= RETR_FLAG; - } - - /* Display the number of bytes in the message */ - pop_msg(p, POP_SUCCESS, "%ld octets", mp->length); - - if(IS_MAILDIR(p)) { - int e = pop_maildir_open(p, mp); - if(e != POP_SUCCESS) - return e; - } - - /* Position to the start of the message */ - fseek(p->drop, mp->offset, 0); - - return_path_sent = 0; - - if(!IS_MAILDIR(p)) { - /* Skip the first line (the sendmail "From" line) */ - fgets (buffer,MAXMSGLINELEN,p->drop); - -#ifdef RETURN_PATH_HANDLING - if (strncmp(buffer,"From ",5) == 0) { - return_path_linlen = strlen(buffer); - for (return_path_adr = buffer+5; - (*return_path_adr == ' ' || *return_path_adr == '\t') && - return_path_adr < buffer + return_path_linlen; - return_path_adr++) - ; - if (return_path_adr < buffer + return_path_linlen) { - if ((return_path_end = strchr(return_path_adr, ' ')) != NULL) - *return_path_end = '\0'; - if (strlen(return_path_adr) != 0 && *return_path_adr != '\n') { - static char tmpbuf[MAXMSGLINELEN + 20]; - if (snprintf (tmpbuf, - sizeof(tmpbuf), - "Return-Path: %s\n", - return_path_adr) < MAXMSGLINELEN) { - pop_sendline (p,tmpbuf); - if (hangup) - return pop_msg (p, POP_FAILURE, - "SIGHUP or SIGPIPE flagged"); - return_path_sent++; - } - } - } - } -#endif - } - - /* Send the header of the message followed by a blank line */ - while (fgets(buffer,MAXMSGLINELEN,p->drop)) { -#ifdef RETURN_PATH_HANDLING - /* Don't send existing Return-Path-header if already sent own */ - if (!return_path_sent || strncasecmp(buffer, "Return-Path:", 12) != 0) -#endif - sent_nl = pop_sendline (p,buffer); - /* A single newline (blank line) signals the - end of the header. sendline() converts this to a NULL, - so that's what we look for. */ - if (*buffer == 0) break; - if (hangup) - return (pop_msg (p,POP_FAILURE,"SIGHUP or SIGPIPE flagged")); - } - /* Send the message body */ - { - int blank_line = 1; - while (fgets(buffer, MAXMSGLINELEN-1, p->drop)) { - /* Look for the start of the next message */ - if (!IS_MAILDIR(p) && blank_line && strncmp(buffer,"From ",5) == 0) - break; - blank_line = (strncmp(buffer, "\n", 1) == 0); - /* Decrement the lines sent (for a TOP command) */ - if (msg_lines >= 0 && msg_lines-- == 0) break; - sent_nl = pop_sendline(p,buffer); - if (hangup) - return (pop_msg (p,POP_FAILURE,"SIGHUP or SIGPIPE flagged")); - } - /* add missing newline at end */ - if(!sent_nl) - fputs("\r\n", p->output); - /* some pop-clients want a blank line at the end of the - message, we always add one here, but what the heck -- in - outer (white) space, no one can hear you scream */ - if(IS_MAILDIR(p)) - fputs("\r\n", p->output); - } - /* "." signals the end of a multi-line transmission */ - fputs(".\r\n",p->output); - fflush(p->output); - - return(POP_SUCCESS); -} diff --git a/appl/popper/pop_stat.c b/appl/popper/pop_stat.c deleted file mode 100644 index 799245a27..000000000 --- a/appl/popper/pop_stat.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - */ - -#include -RCSID("$Id$"); - -/* - * stat: Display the status of a POP maildrop to its client - */ - -int -pop_stat (POP *p) -{ -#ifdef DEBUG - if (p->debug) pop_log(p,POP_DEBUG,"%d message(s) (%ld octets).", - p->msg_count-p->msgs_deleted, - p->drop_size-p->bytes_deleted); -#endif /* DEBUG */ - return (pop_msg (p,POP_SUCCESS, - "%d %ld", - p->msg_count-p->msgs_deleted, - p->drop_size-p->bytes_deleted)); -} diff --git a/appl/popper/pop_uidl.c b/appl/popper/pop_uidl.c deleted file mode 100644 index 22beb829b..000000000 --- a/appl/popper/pop_uidl.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -RCSID("$Id$"); - -#ifdef UIDL -/* - * uidl: Uidl the contents of a POP maildrop - */ - -int -pop_uidl (POP *p) -{ - MsgInfoList * mp; /* Pointer to message info list */ - int i; - int msg_num; - - /* Was a message number provided? */ - if (p->parm_count > 0) { - msg_num = atoi(p->pop_parm[1]); - - /* Is requested message out of range? */ - if ((msg_num < 1) || (msg_num > p->msg_count)) - return (pop_msg (p,POP_FAILURE, - "Message %d does not exist.",msg_num)); - - /* Get a pointer to the message in the message list */ - mp = &p->mlp[msg_num-1]; - - /* Is the message already flagged for deletion? */ - if (mp->flags & DEL_FLAG) - return (pop_msg (p,POP_FAILURE, - "Message %d has been deleted.",msg_num)); - - /* Display message information */ - return (pop_msg(p,POP_SUCCESS,"%u %s",msg_num,mp->msg_id)); - } - - /* Display the entire list of messages */ - pop_msg(p,POP_SUCCESS, - "%d messages (%ld octets)", - p->msg_count-p->msgs_deleted, - p->drop_size-p->bytes_deleted); - - /* Loop through the message information list. Skip deleted messages */ - for (i = p->msg_count, mp = p->mlp; i > 0; i--, mp++) { - if (!(mp->flags & DEL_FLAG)) - fprintf(p->output,"%u %s\r\n",mp->number,mp->msg_id); - } - - /* "." signals the end of a multi-line transmission */ - fprintf(p->output,".\r\n"); - fflush(p->output); - - return(POP_SUCCESS); -} -#endif /* UIDL */ diff --git a/appl/popper/pop_updt.c b/appl/popper/pop_updt.c deleted file mode 100644 index ac6bfe09c..000000000 --- a/appl/popper/pop_updt.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - */ - -#include -RCSID("$Id$"); - -static const char standard_error[] = - "Error error updating primary drop. Mailbox unchanged"; - -/* - * updt: Apply changes to a user's POP maildrop - */ - -int -pop_updt (POP *p) -{ - FILE * md; /* Stream pointer for - the user's maildrop */ - int mfd; /* File descriptor for - above */ - char buffer[BUFSIZ]; /* Read buffer */ - - MsgInfoList * mp; /* Pointer to message - info list */ - int msg_num; /* Current message - counter */ - int status_written; /* Status header field - written */ - int nchar; /* Bytes read/written */ - - long offset; /* New mail offset */ - - int blank_line; - -#ifdef DEBUG - if (p->debug) { - pop_log(p,POP_DEBUG,"Performing maildrop update..."); - pop_log(p,POP_DEBUG,"Checking to see if all messages were deleted"); - } -#endif /* DEBUG */ - - if(IS_MAILDIR(p)) - return pop_maildir_update(p); - - if (p->msgs_deleted == p->msg_count) { - /* Truncate before close, to avoid race condition, DO NOT UNLINK! - Another process may have opened, and not yet tried to lock */ - ftruncate ((int)fileno(p->drop),0); - fclose(p->drop) ; - return (POP_SUCCESS); - } - -#ifdef DEBUG - if (p->debug) - pop_log(p,POP_DEBUG,"Opening mail drop \"%s\"",p->drop_name); -#endif /* DEBUG */ - - /* Open the user's real maildrop */ - if ((mfd = open(p->drop_name,O_RDWR|O_CREAT,0600)) == -1 || - (md = fdopen(mfd,"r+")) == NULL) { - return pop_msg(p,POP_FAILURE,standard_error); - } - - /* Lock the user's real mail drop */ - if ( flock(mfd, LOCK_EX) == -1 ) { - fclose(md) ; - return pop_msg(p,POP_FAILURE, "flock: '%s': %s", p->temp_drop, - strerror(errno)); - } - - /* Go to the right places */ - offset = lseek((int)fileno(p->drop),0,SEEK_END) ; - - /* Append any messages that may have arrived during the session - to the temporary maildrop */ - while ((nchar=read(mfd,buffer,BUFSIZ)) > 0) - if ( nchar != write((int)fileno(p->drop),buffer,nchar) ) { - nchar = -1; - break ; - } - if ( nchar != 0 ) { - fclose(md) ; - ftruncate((int)fileno(p->drop),(int)offset) ; - fclose(p->drop) ; - return pop_msg(p,POP_FAILURE,standard_error); - } - - rewind(md); - lseek(mfd,0,SEEK_SET); - ftruncate(mfd,0) ; - - /* Synch stdio and the kernel for the POP drop */ - rewind(p->drop); - lseek((int)fileno(p->drop),0,SEEK_SET); - - /* Transfer messages not flagged for deletion from the temporary - maildrop to the new maildrop */ -#ifdef DEBUG - if (p->debug) - pop_log(p,POP_DEBUG,"Creating new maildrop \"%s\" from \"%s\"", - p->drop_name,p->temp_drop); -#endif /* DEBUG */ - - for (msg_num = 0; msg_num < p->msg_count; ++msg_num) { - - int doing_body; - - /* Get a pointer to the message information list */ - mp = &p->mlp[msg_num]; - - if (mp->flags & DEL_FLAG) { -#ifdef DEBUG - if(p->debug) - pop_log(p,POP_DEBUG, - "Message %d flagged for deletion.",mp->number); -#endif /* DEBUG */ - continue; - } - - fseek(p->drop,mp->offset,0); - -#ifdef DEBUG - if(p->debug) - pop_log(p,POP_DEBUG,"Copying message %d.",mp->number); -#endif /* DEBUG */ - blank_line = 1; - for(status_written = doing_body = 0 ; - fgets(buffer,MAXMSGLINELEN,p->drop);) { - - if (doing_body == 0) { /* Header */ - - /* Update the message status */ - if (strncasecmp(buffer,"Status:",7) == 0) { - if (mp->flags & RETR_FLAG) - fputs("Status: RO\n",md); - else - fputs(buffer, md); - status_written++; - continue; - } - /* A blank line signals the end of the header. */ - if (*buffer == '\n') { - doing_body = 1; - if (status_written == 0) { - if (mp->flags & RETR_FLAG) - fputs("Status: RO\n\n",md); - else - fputs("Status: U\n\n",md); - } - else fputs ("\n", md); - continue; - } - /* Save another header line */ - fputs (buffer, md); - } - else { /* Body */ - if (blank_line && strncmp(buffer,"From ",5) == 0) break; - fputs (buffer, md); - blank_line = (*buffer == '\n'); - } - } - } - - /* flush and check for errors now! The new mail will writen - without stdio, since we need not separate messages */ - - fflush(md) ; - if (ferror(md)) { - ftruncate(mfd,0) ; - fclose(md) ; - fclose(p->drop) ; - return pop_msg(p,POP_FAILURE,standard_error); - } - - /* Go to start of new mail if any */ - lseek((int)fileno(p->drop),offset,SEEK_SET); - - while((nchar=read((int)fileno(p->drop),buffer,BUFSIZ)) > 0) - if ( nchar != write(mfd,buffer,nchar) ) { - nchar = -1; - break ; - } - if ( nchar != 0 ) { - ftruncate(mfd,0) ; - fclose(md) ; - fclose(p->drop) ; - return pop_msg(p,POP_FAILURE,standard_error); - } - - /* Close the maildrop and empty temporary maildrop */ - fclose(md); - ftruncate((int)fileno(p->drop),0); - fclose(p->drop); - - return(pop_quit(p)); -} diff --git a/appl/popper/pop_user.c b/appl/popper/pop_user.c deleted file mode 100644 index 56d07842a..000000000 --- a/appl/popper/pop_user.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - */ - -#include -RCSID("$Id$"); - -/* - * user: Prompt for the user name at the start of a POP session - */ - -int -pop_user (POP *p) -{ - strlcpy(p->user, p->pop_parm[1], sizeof(p->user)); - - if (p->auth_level == AUTH_OTP) { -#ifdef OTP - char ss[256], *s; - - if(otp_challenge (&p->otp_ctx, p->user, ss, sizeof(ss)) == 0) - return pop_msg(p, POP_SUCCESS, "Password %s required for %s.", - ss, p->user); - s = otp_error(&p->otp_ctx); - return pop_msg(p, POP_FAILURE, "Permission denied%s%s", - s ? ":" : "", s ? s : ""); -#endif - } - if (p->auth_level == AUTH_SASL) { - return pop_msg(p, POP_FAILURE, "Permission denied"); - } - return pop_msg(p, POP_SUCCESS, "Password required for %s.", p->user); -} diff --git a/appl/popper/pop_xover.c b/appl/popper/pop_xover.c deleted file mode 100644 index ceab60cc8..000000000 --- a/appl/popper/pop_xover.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -RCSID("$Id$"); - -int -pop_xover (POP *p) -{ -#ifdef XOVER - MsgInfoList * mp; /* Pointer to message info list */ - int i; - - pop_msg(p,POP_SUCCESS, - "%d messages (%ld octets)", - p->msg_count-p->msgs_deleted, - p->drop_size-p->bytes_deleted); - - /* Loop through the message information list. Skip deleted messages */ - for (i = p->msg_count, mp = p->mlp; i > 0; i--, mp++) { - if (!(mp->flags & DEL_FLAG)) - fprintf(p->output,"%u\t%s\t%s\t%s\t%s\t%lu\t%u\r\n", - mp->number, - mp->subject, - mp->from, - mp->date, - mp->msg_id, - mp->length, - mp->lines); - } - - /* "." signals the end of a multi-line transmission */ - fprintf(p->output,".\r\n"); - fflush(p->output); - - return(POP_SUCCESS); -#else - return pop_msg(p, POP_FAILURE, "Command not implemented."); -#endif -} diff --git a/appl/popper/popper.8 b/appl/popper/popper.8 deleted file mode 100644 index a6515a0cb..000000000 --- a/appl/popper/popper.8 +++ /dev/null @@ -1,104 +0,0 @@ -.\" Copyright (c) 2001 - 2004 Kungliga Tekniska Högskolan -.\" (Royal Institute of Technology, Stockholm, Sweden). -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" 3. Neither the name of the Institute nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" $Id$ -.\" -.Dd July 14, 2004 -.Dt POPPER 8 -.Os HEIMDAL -.Sh NAME -.Nm popper -.Nd -POP3 server -.Sh SYNOPSIS -.Nm -.Op Fl k -.Op Fl a Ar plaintext Ns \*(Ba Ns Ar otp Ns \*(Ba Ns Ar sasl -.Op Fl t Ar file -.Op Fl T Ar seconds -.Op Fl d -.Op Fl i -.Op Fl p Ar port -.Op Fl -address-log= Ns Pa file -.Sh DESCRIPTION -.Nm -serves mail via the Post Office Protocol. Supported options include: -.Bl -tag -width Ds -.It Fl a Ar plaintext Ns \*(Ba Ns Ar otp Ns \*(Ba Ns Ar sasl -Tells -.Nm -which authentication mode is acceptable, -.Ar sasl -enables SASL (RFC2222), and -.Ar otp -enables OTP (RFC1938) authentication. Both disable plaintext passwords. -.It Fl -address-log= Ns Pa file -Logs the addresses (along with a timestamp) of all clients to the -specified file. This can be used to implement POP-before-SMTP -authentication. -.It Fl d -Enables more verbose log messages. -.It Fl i -When not started by inetd, this flag tells -.Nm -that it has to create a socket by itself. -.It Fl k -Tells -.Nm -to use Kerberos for authentication. This is the traditional way of -doing Kerberos authentication, and is normally done on a separate port -(as it doesn't follow RFC1939), and should be used instead of using -SASL. -.It Fl p Ar port -Port to listen to, in combination with -.Fl i . -.It Fl t Ar file -Trace all commands to file. -.It Fl T Ar seconds -Set timeout to something other than the default of 120 seconds. -.El -.\".Sh ENVIRONMENT -.\".Sh FILES -.\".Sh EXAMPLES -.\".Sh DIAGNOSTICS -.Sh SEE ALSO -.Xr push 8 , -.Xr movemail 8 -.Sh STANDARDS -RFC1939 (Post Office Protocol - Version 3) -.\" RFC2449 (POP3 Extension Mechanism) -.\".Sh HISTORY -.Sh AUTHORS -The server was initially developed at the University of California, -Berkeley. -.Pp -Many changes have been made as part of the KTH Kerberos distributions. -.\".Sh BUGS diff --git a/appl/popper/popper.README.release b/appl/popper/popper.README.release deleted file mode 100644 index c0b313ecd..000000000 --- a/appl/popper/popper.README.release +++ /dev/null @@ -1,45 +0,0 @@ -Release Notes: - -popper-1.831beta is no longer beta 30 July 91 - Removed popper-1.7.tar.Z - -popper-1.831beta.tar.Z 03 April 91 - Changed mkstemp to mktemp for Ultrix. Sigh. - -popper-1.83beta.tar.Z 02 April 91 - - This version makes certain that while running as root we do nothing - at all destructive. - -popper-1.82beta.tar.Z 27 March 91 - - This version fixes problems on Encore MultiMax and some Sun releases - which wouldn't allow a user to ftruncate() a file from an open - file descripter unless the user owns the file. Now the user - owns the /usr/spool/mail/.userid.pop file. Thanks to Ben Levy - of FTP Software and Henry Holtzman of Apple. - -popper-1.81beta.tar.Z 20 March 91 - - This version of popper is supposed to fix three problems reported - with various versions of popper (all called 1.7 or 1.7something). - - 1) Dropped network connections meant lost mail files. Some 1.7 - versions also risked corrupting mail files. - - 2) Some versions of 1.7 created temporary drop files with world - read and write permissions. - - 3) Some versions of 1.7 were not careful about opening the temporary - drop file. - -popper-1.7.tar.Z 09 September 90 (updated 20 March 91) - - This version will exhibit the first problem listed above if it is - compiled with -DDEBUG and run without the "-d" (debug) flag. - - If it is compiled without -DDEBUG it will exhibit only the second - and third bug listed above. - -Cliff Frost poptest@nettlesome.berkeley.edu -UC Berkeley diff --git a/appl/popper/popper.c b/appl/popper/popper.c deleted file mode 100644 index 036a5dbdb..000000000 --- a/appl/popper/popper.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - */ - -#include -RCSID("$Id$"); - -int hangup = FALSE ; - -static RETSIGTYPE -catchSIGHUP(int sig) -{ - hangup = TRUE ; - - /* This should not be a problem on BSD systems */ - signal(SIGHUP, catchSIGHUP); - signal(SIGPIPE, catchSIGHUP); - SIGRETURN(0); -} - -int pop_timeout = POP_TIMEOUT; - -jmp_buf env; - -static RETSIGTYPE -ring(int sig) -{ - longjmp(env,1); -} - -/* - * fgets, but with a timeout - */ -static char * -tgets(char *str, int size, FILE *fp, int timeout) -{ - char *ret; - - signal(SIGALRM, ring); - alarm(timeout); - if (setjmp(env)) { - alarm(0); - signal(SIGALRM, SIG_DFL); - return NULL; - } - ret = fgets(str, size, fp); - alarm(0); - signal(SIGALRM, SIG_DFL); - return ret; -} - -/* - * popper: Handle a Post Office Protocol version 3 session - */ -int -main (int argc, char **argv) -{ - POP p; - state_table * s; - char message[MAXLINELEN]; - - signal(SIGHUP, catchSIGHUP); - signal(SIGPIPE, catchSIGHUP); - - /* Start things rolling */ - pop_init(&p,argc,argv); - - /* Tell the user that we are listenting */ - pop_msg(&p,POP_SUCCESS, "POP3 server ready"); - - /* State loop. The POP server is always in a particular state in - which a specific suite of commands can be executed. The following - loop reads a line from the client, gets the command, and processes - it in the current context (if allowed) or rejects it. This continues - until the client quits or an error occurs. */ - - for (p.CurrentState=auth1;p.CurrentState!=halt&&p.CurrentState!=error;) { - if (hangup) { - pop_msg(&p, POP_FAILURE, "POP hangup: %s", p.myhost); - if (p.CurrentState > auth2 && !pop_updt(&p)) - pop_msg(&p, POP_FAILURE, - "POP mailbox update failed: %s", p.myhost); - p.CurrentState = error; - } else if (tgets(message, MAXLINELEN, p.input, pop_timeout) == NULL) { - pop_msg(&p, POP_FAILURE, "POP timeout: %s", p.myhost); - if (p.CurrentState > auth2 && !pop_updt(&p)) - pop_msg(&p,POP_FAILURE, - "POP mailbox update failed: %s", p.myhost); - p.CurrentState = error; - } - else { - /* Search for the command in the command/state table */ - if ((s = pop_get_command(&p,message)) == NULL) continue; - - /* Call the function associated with this command in - the current state */ - if (s->function) p.CurrentState = s->result[(*s->function)(&p)]; - - /* Otherwise assume NOOP and send an OK message to the client */ - else { - p.CurrentState = s->success_state; - pop_msg(&p,POP_SUCCESS,"time passes"); - } - } - } - - /* Say goodbye to the client */ - pop_msg(&p,POP_SUCCESS,"Pop server at %s signing off.",p.myhost); - - /* Log the end of activity */ - pop_log(&p,POP_PRIORITY, - "(v%s) Ending request from \"%s\" at %s\n",VERSION,p.client,p.ipaddr); - - /* Stop logging */ - closelog(); - - return(0); -} diff --git a/appl/popper/popper.h b/appl/popper/popper.h deleted file mode 100644 index d792ab1fa..000000000 --- a/appl/popper/popper.h +++ /dev/null @@ -1,349 +0,0 @@ -/* - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - * - * static char copyright[] = "Copyright (c) 1990 Regents of the University of California.\nAll rights reserved.\n"; - * static char SccsId[] = "@(#)@(#)popper.h 2.2 2.2 4/2/91"; - * - */ - -/* $Id$ */ - -/* - * Header file for the POP programs - */ - -#ifdef HAVE_CONFIG_H -#include -#define UIDL -#define XOVER -#define XDELE -#define DEBUG -#define RETURN_PATH_HANDLING -#endif - -/* Common include files */ - -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_FCNTL_H -#include -#endif -#ifdef HAVE_PWD_H -#include -#endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_IO_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef HAVE_SYS_FILE_H -#include -#endif -#ifdef TIME_WITH_SYS_TIME -#include -#include -#elif defined(HAVE_SYS_TIME_H) -#include -#else -#include -#endif -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif -#ifdef HAVE_SYS_WAIT_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETINET_IN6_H -#include -#endif -#ifdef HAVE_NETINET6_IN6_H -#include -#endif - -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#ifdef _AIX -struct sockaddr_dl; /* AIX fun */ -struct ether_addr; -#endif -#include -#endif -#ifdef HAVE_SYSLOG_H -#include -#endif -#ifdef HAVE_SYS_SELECT_H -#include -#endif -#ifdef HAVE_SYS_PARAM_H -#include -#endif -#include "version.h" - -#ifdef SOCKS -#include -#endif - -#include -#include -#include - -#ifdef KRB5 -#include -#endif - -#define MAXUSERNAMELEN 65 -#define MAXLINELEN 1024 -#define MAXMSGLINELEN 1024 -#define MAXCMDLEN 4 -#define MAXPARMCOUNT 10 -#define MAXPARMLEN 10 -#define ALLOC_MSGS 20 -#define MAIL_COMMAND "/usr/lib/sendmail" - -#define POP_FACILITY LOG_LOCAL0 -#define POP_PRIORITY LOG_NOTICE -#define POP_DEBUG LOG_DEBUG -#define POP_INFO LOG_INFO -#define POP_LOGOPTS 0 - -#ifdef HAVE_PATHS_H -#include -#endif -#ifdef HAVE_MAILLOCK_H -#include -#endif - -#ifdef OTP -#include -#endif - -#if defined(_PATH_MAILDIR) -#define POP_MAILDIR _PATH_MAILDIR -#elif defined(MAILDIR) -#define POP_MAILDIR MAILDIR -#else -#define POP_MAILDIR "/usr/spool/mail" -#endif - -#define POP_DROP POP_MAILDIR "/.%s.pop" - /* POP_TMPSIZE needs to be big enough to hold the string - * defined by POP_TMPDROP. POP_DROP and POP_TMPDROP - * must be in the same filesystem. - */ -#define POP_TMPDROP POP_MAILDIR "/tmpXXXXXX" -#define POP_TMPSIZE 256 -#define POP_TMPXMIT "/tmp/xmitXXXXXX" -#define POP_OK "+OK" -#define POP_ERR "-ERR" -#define POP_SUCCESS 1 -#define POP_FAILURE 0 -#define POP_TERMINATE '.' -#define POP_TIMEOUT 120 /* timeout connection after this many secs */ - -extern int pop_timeout; - -extern int hangup; - -#define AUTH_NONE 0 -#define AUTH_OTP 1 -#define AUTH_SASL 2 - -#define pop_command pop_parm[0] /* POP command is first token */ -#define pop_subcommand pop_parm[1] /* POP XTND subcommand is the - second token */ - -typedef enum { /* POP processing states */ - auth1, /* Authorization: waiting for - USER command */ - auth2, /* Authorization: waiting for - PASS command */ - trans, /* Transaction */ - update, /* Update: session ended, - process maildrop changes */ - halt, /* (Halt): stop processing - and exit */ - error /* (Error): something really - bad happened */ -} state; - - -#define DEL_FLAG 1 -#define RETR_FLAG 2 -#define NEW_FLAG 4 - -typedef struct { /* Message information */ - int number; /* Message number relative to - the beginning of list */ - long length; /* Length of message in - bytes */ - int lines; /* Number of (null-terminated) lines in the message */ - long offset; /* Offset from beginning of - file */ - unsigned flags; - -#if defined(UIDL) || defined(XOVER) - char *msg_id; /* The POP UIDL uniqueifier */ -#endif -#ifdef XOVER - char *subject; - char *from; - char *date; -#endif - char *name; -} MsgInfoList; - -#define IS_MAILDIR(P) ((P)->temp_drop[0] == '\0') - -typedef struct { /* POP parameter block */ - int debug; /* Debugging requested */ - char * myname; /* The name of this POP - daemon program */ - char myhost[MaxHostNameLen]; /* The name of our host - computer */ - char client[MaxHostNameLen]; /* Canonical name of client - computer */ - char ipaddr[MaxHostNameLen]; /* Dotted-notation format of - client IP address */ - unsigned short ipport; /* Client port for privileged - operations */ - char user[MAXUSERNAMELEN]; /* Name of the POP user */ - state CurrentState; /* The current POP operational state */ - MsgInfoList * mlp; /* Message information list */ - int msg_count; /* Number of messages in - the maildrop */ - int msgs_deleted; /* Number of messages flagged - for deletion */ - int last_msg; /* Last message touched by - the user */ - long bytes_deleted; /* Number of maildrop bytes - flagged for deletion */ - char drop_name[MAXPATHLEN]; /* The name of the user's - maildrop */ - char temp_drop[MAXPATHLEN]; /* The name of the user's - temporary maildrop */ - long drop_size; /* Size of the maildrop in - bytes */ - FILE * drop; /* (Temporary) mail drop */ - FILE * input; /* Input TCP/IP communication - stream */ - FILE * output; /* Output TCP/IP communication stream */ - FILE * trace; /* Debugging trace file */ - char * pop_parm[MAXPARMCOUNT]; /* Parse POP parameter list */ - int parm_count; /* Number of parameters in - parsed list */ - int kerberosp; /* Using KPOP? */ -#ifdef KRB5 - krb5_context context; - krb5_principal principal; /* principal auth as */ - krb5_log_facility* logf; -#endif - int version; /* 4 or 5? */ - int auth_level; /* Dont allow cleartext */ -#ifdef OTP - OtpContext otp_ctx; /* OTP context */ -#endif - unsigned int flags; -#define POP_FLAG_CAPA 1 -} POP; - -typedef struct { /* State information for - each POP command */ - state ValidCurrentState; /* The operating state of - the command */ - char * command; /* The POP command */ - int min_parms; /* Minimum number of parms - for the command */ - int max_parms; /* Maximum number of parms - for the command */ - int (*function) (); /* The function that process - the command */ - state result[2]; /* The resulting state after - command processing */ -#define success_state result[0] /* State when a command - succeeds */ -} state_table; - -typedef struct { /* Table of extensions */ - char * subcommand; /* The POP XTND subcommand */ - int min_parms; /* Minimum number of parms for - the subcommand */ - int max_parms; /* Maximum number of parms for - the subcommand */ - int (*function) (); /* The function that processes - the subcommand */ -} xtnd_table; - -int pop_dele(POP *p); -int pop_dropcopy(POP *p, struct passwd *pwp); -int pop_dropinfo(POP *p); -int pop_init(POP *p,int argcount,char **argmessage); -int pop_last(POP *p); -int pop_list(POP *p); -int pop_parse(POP *p, char *buf); -int pop_pass(POP *p); -int pop_quit(POP *p); -int pop_rset(POP *p); -int pop_send(POP *p); -int pop_stat(POP *p); -int pop_updt(POP *p); -int pop_user(POP *p); -#ifdef UIDL -int pop_uidl(POP *p); -#endif -#ifdef XOVER -int pop_xover(POP *p); -#endif -#ifdef XDELE -int pop_xdele(POP *p); -#endif -int pop_help(POP *p); -state_table *pop_get_command(POP *p, char *mp); -void pop_lower(char *buf); -#ifdef SASL -int pop_auth (POP *p); -void pop_capa_sasl(POP *p); -#endif - -int pop_log(POP *p, int stat, char *format, ...) -#ifdef __GNUC__ -__attribute__ ((format (printf, 3, 4))) -#endif -; - -int pop_msg(POP *p, int stat, const char *format, ...) -#ifdef __GNUC__ -__attribute__ ((format (printf, 3, 4))) -#endif -; - -int pop_maildir_info (POP*); -int pop_maildir_open (POP*, MsgInfoList*); -int pop_maildir_update (POP*); - -int changeuser(POP*, struct passwd*); -void parse_header(MsgInfoList*, char*); -int add_missing_headers(POP*, MsgInfoList*); -int login_user(POP *p); diff --git a/appl/popper/version.h b/appl/popper/version.h deleted file mode 100644 index de8836245..000000000 --- a/appl/popper/version.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - * - * static char copyright[] = "Copyright (c) 1990 Regents of the University of California.\nAll rights reserved.\n"; - * static char SccsId[] = "@(#)@(#)version.h 2.6 2.6 4/3/91"; - * - */ - -/* $Id$ */ - -/* - * Current version of this POP implementation - */ - -#if 0 -#define VERSION krb4_version -#endif diff --git a/appl/push/ChangeLog b/appl/push/ChangeLog deleted file mode 100644 index ac4cb1ad4..000000000 --- a/appl/push/ChangeLog +++ /dev/null @@ -1,200 +0,0 @@ -2005-04-19 Love Hörnquist Åstrand - - * push.c: catch when snprint needs a larger buffer - -2004-06-17 Johan Danielsson - - * push.c: alloc memory to handle very long lines - -2003-04-03 Assar Westerlund - - * push.c: fixed one incorrect fprintf to stderr - -2003-03-18 Love Hörnquist Åstrand - - * push.c: add names of pop states, add some more debugging and use - fprintf(stderr) for all dbg stmts. - -2001-09-04 Assar Westerlund - - * push.c (doit): check return values from snprintf being negative - -2000-12-31 Assar Westerlund - - * push.c (main): handle krb5_init_context failure consistently - -2000-12-26 Assar Westerlund - - * push.c: support several headers, from use - estrdup, emalloc, erealloc - -2000-11-29 Johan Danielsson - - * pfrom.1: work around bug in grog that makes it think it needs - mdoc.old - - * push.8: work around bug in grog that makes it think it needs - mdoc.old - -2000-11-27 Johan Danielsson - - * push.c: add space to usage - -2000-10-08 Assar Westerlund - - * push.c (doit): check that fds are not too large to select on - -2000-03-04 Assar Westerlund - - * add man-page for pfrom - -1999-12-28 Assar Westerlund - - * push.c (main): call k_getportbyname with port number in - network-byte-order - -1999-12-14 Assar Westerlund - - * push.c (do_connect): remove bogus local block variable - -1999-12-05 Assar Westerlund - - * push.c (do_connect): use `getaddrinfo' - * push.c: add --count (print number of messages and bytes at - beginning) - -1999-11-13 Assar Westerlund - - * push.c: make `-v' a arg_counter - -1999-11-02 Assar Westerlund - - * push.c (main): redo the v4/v5 selection for consistency. -4 -> - try only v4 -5 -> try only v5 none, -45 -> try v5, v4 - -1999-08-19 Assar Westerlund - - * push.c (doit): remember to step over the error message when we - discover that XDELE is not supported - -1999-08-12 Johan Danielsson - - * push.c: use XDELE - -1999-08-05 Assar Westerlund - - * push.c (do_connect): v6-ify - -1999-06-15 Assar Westerlund - - * push.c: get_default_username and the resulting const propagation - -1999-05-21 Assar Westerlund - - * push.c (parse_pobox): try $USERNAME - -1999-05-11 Assar Westerlund - - * push.c (do_v5): remove unused and non-working code - -1999-05-10 Assar Westerlund - - * push.c (do_v5): call krb5_sendauth with ccache == NULL - -Wed Apr 7 23:40:00 1999 Assar Westerlund - - * Makefile.in: fix names of hesiod variables - -Wed Mar 24 04:37:04 1999 Assar Westerlund - - * Makefile.am (pfrom): fix typo - - * push.c (get_pobox): try to handle old and new hesiod APIs - -Mon Mar 22 22:19:40 1999 Assar Westerlund - - * Makefile.am: hesoid -> hesiod - -Sun Mar 21 18:02:10 1999 Johan Danielsson - - * Makefile.am: bindir -> libexecdir - -Sat Mar 20 00:12:26 1999 Assar Westerlund - - * Makefile.am: LDADD: add missing backslash - -Thu Mar 18 15:28:35 1999 Johan Danielsson - - * Makefile.am: clean pfrom - - * Makefile.am: include Makefile.am.common - -Mon Mar 15 18:26:16 1999 Johan Danielsson - - * push.c: strncasecmp headers - -Mon Feb 15 22:22:09 1999 Assar Westerlund - - * Makefile.in (pfrom): use libexecdir - - * Makefile.am: build and install pfrom - - * push.c (do_connect): init `s' - (pop_state): spell-check enums - -Tue Nov 24 23:20:54 1998 Assar Westerlund - - * Makefile.in: build and install pfrom - - * pfrom.in: bindir -> libexecdir - -Sun Nov 22 15:33:52 1998 Johan Danielsson - - * push.c: eliminate some warnings - -Sun Nov 22 10:34:54 1998 Assar Westerlund - - * Makefile.in (WFLAGS): set - -Thu Nov 19 01:17:33 1998 Assar Westerlund - - * push_locl.h: add - - * Makefile.am, Makefile.in: link and include hesiod - - * push.c (get_pobox): new function. add hesiod support. - -1998-11-07 Assar Westerlund - - * push.8: updated - - * push.c: --from implementation from - -Fri Jul 10 01:14:45 1998 Assar Westerlund - - * push.c (net_{read,write}): remove - -Wed Jun 24 14:41:41 1998 Johan Danielsson - - * push.c: allow `po:user@host' mailbox syntax - -Tue Jun 2 17:35:06 1998 Johan Danielsson - - * push.c: quote '^From ' properly - -Mon May 25 05:22:47 1998 Assar Westerlund - - * Makefile.in (clean): PROGS -> PROGRAMS - -Sun Apr 26 11:42:13 1998 Assar Westerlund - - * push.c (main): better default for v4 and v5 - - * push.c (main): init context correctly - - * push.c: should work with krb4 - - * push_locl.h: krb4 compat - - * Makefile.in: new file - diff --git a/appl/push/Makefile.am b/appl/push/Makefile.am deleted file mode 100644 index d98711926..000000000 --- a/appl/push/Makefile.am +++ /dev/null @@ -1,26 +0,0 @@ -# $Id$ - -include $(top_srcdir)/Makefile.am.common - -AM_CPPFLAGS += $(INCLUDE_hesiod) - -bin_SCRIPTS = pfrom - -libexec_PROGRAMS = push - -push_SOURCES = push.c push_locl.h - -pfrom: pfrom.in - sed -e "s!%libexecdir%!$(libexecdir)!" $(srcdir)/pfrom.in > $@ - chmod +x $@ - -man_MANS = push.8 pfrom.1 - -CLEANFILES = pfrom - -EXTRA_DIST = pfrom.in $(man_MANS) - -LDADD = $(LIB_krb5) \ - $(LIB_hcrypto) \ - $(LIB_roken) \ - $(LIB_hesiod) diff --git a/appl/push/pfrom.1 b/appl/push/pfrom.1 deleted file mode 100644 index c3878c2b2..000000000 --- a/appl/push/pfrom.1 +++ /dev/null @@ -1,55 +0,0 @@ -.\" Copyright (c) 2000 - 2002 Kungliga Tekniska Högskolan -.\" (Royal Institute of Technology, Stockholm, Sweden). -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" 3. Neither the name of the Institute nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" $Id$ -.\" -.Dd March 4, 2000 -.Dt PFROM 1 -.Os HEIMDAL -.Sh NAME -.Nm pfrom -.Nd "fetch a list of the current mail via POP" -.Sh SYNOPSIS -.Nm -.Op Fl 4 | Fl -krb4 -.Op Fl 5 | Fl -krb5 -.Op Fl v | Fl -verbose -.Op Fl c | -count -.Op Fl -header -.Oo Fl p Ar port-spec \*(Ba Xo -.Fl -port= Ns Ar port-spec -.Xc -.Oc -.Sh DESCRIPTION -.Nm -is a script that does push --from. -.Sh SEE ALSO -.Xr push 8 diff --git a/appl/push/pfrom.in b/appl/push/pfrom.in deleted file mode 100644 index e90141977..000000000 --- a/appl/push/pfrom.in +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -# $Id$ -libexecdir=%libexecdir% -PATH=$libexecdir:$PATH -export PATH -push --from $* diff --git a/appl/push/push.8 b/appl/push/push.8 deleted file mode 100644 index 32a9eb351..000000000 --- a/appl/push/push.8 +++ /dev/null @@ -1,132 +0,0 @@ -.\" $Id$ -.\" -.Dd May 31, 1998 -.Dt PUSH 8 -.Os HEIMDAL -.Sh NAME -.Nm push -.Nd fetch mail via POP -.Sh SYNOPSIS -.Nm -.Op Fl 5 | Fl -krb5 -.Op Fl v | Fl -verbose -.Op Fl f | Fl -fork -.Op Fl l | -leave -.Op Fl -from -.Op Fl c | -count -.Op Fl -headers Ns = Ns Ar headers -.Oo Fl p Ar port-spec \*(Ba Xo -.Fl -port Ns = Ns Ar port-spec -.Xc -.Oc -.Ar po-box -.Pa filename -.Sh DESCRIPTION -.Nm -retrieves mail from the post office box -.Ar po-box , -and stores the mail in mbox format in -.Pa filename . -The -.Ar po-box -can have any of the following formats: -.Bl -hang -compact -offset indent -.It Ql hostname:username -.It Ql po:hostname:username -.It Ql username@hostname -.It Ql po:username@hostname -.It Ql hostname -.It Ql po:username -.El -.Pp -If no username is specified, -.Nm -assumes that it's the same as on the local machine; -.Ar hostname -defaults to the value of the -.Ev MAILHOST -environment variable. -.Pp -Supported options: -.Bl -tag -width Ds -.It Xo -.Fl 5 , -.Fl -krb5 -.Xc -use Kerberos 5 (if compiled with support for Kerberos 5) -.It Xo -.Fl f , -.Fl -fork -.Xc -fork before starting to delete messages -.It Xo -.Fl l , -.Fl -leave -.Xc -don't delete fetched mail -.It Xo -.Fl -from -.Xc -behave like from. -.It Xo -.Fl c , -.Fl -count -.Xc -first print how many messages and bytes there are. -.It Xo -.Fl -headers Ns = Ns Ar headers -.Xc -a list of comma-separated headers that should get printed. -.It Xo -.Fl p Ar port-spec , -.Fl -port Ns = Ns Ar port-spec -.Xc -use this port instead of the default -.Ql kpop -or -.Ql 1109 . -.El -.Pp -The default is to first try Kerberos 5 authentication and then, if -that fails, Kerberos 4. -.Sh ENVIRONMENT -.Bl -tag -width Ds -.It Ev MAILHOST -points to the post office, if no other hostname is specified. -.El -.\".Sh FILES -.Sh EXAMPLES -.Bd -literal -offset indent -$ push cornfield:roosta ~/.emacs-mail-crash-box -.Ed -.Pp -tries to fetch mail for the user -.Ar roosta -from the post office at -.Dq cornfield , -and stores the mail in -.Pa ~/.emacs-mail-crash-box -(you are using Gnus, aren't you?) -.Bd -literal -offset indent -$ push --from -5 havregryn -.Ed -.Pp -tries to fetch -.Sy From: -lines for current user at post office -.Dq havregryn -using Kerberos 5. -.\".Sh DIAGNOSTICS -.Sh SEE ALSO -.Xr from 1 , -.Xr pfrom 1 , -.Xr movemail 8 , -.Xr popper 8 -.\".Sh STANDARDS -.Sh HISTORY -.Nm -was written while waiting for -.Nm movemail -to finish getting the mail. -.\".Sh AUTHORS -.\".Sh BUGS diff --git a/appl/push/push.c b/appl/push/push.c deleted file mode 100644 index d65276c7c..000000000 --- a/appl/push/push.c +++ /dev/null @@ -1,778 +0,0 @@ -/* - * Copyright (c) 1997-2004 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "push_locl.h" -RCSID("$Id$"); - -#ifdef KRB5 -static int use_v5 = -1; -static krb5_context context; -#endif - -static char *port_str; -static int verbose_level; -static int do_fork; -static int do_leave; -static int do_version; -static int do_help; -static int do_from; -static int do_count; -static char *header_str; - -struct getargs args[] = { -#ifdef KRB5 - { "krb5", '5', arg_flag, &use_v5, "Use Kerberos V5", - NULL }, -#endif - { "verbose",'v', arg_counter, &verbose_level, "Verbose", - NULL }, - { "fork", 'f', arg_flag, &do_fork, "Fork deleting proc", - NULL }, - { "leave", 'l', arg_flag, &do_leave, "Leave mail on server", - NULL }, - { "port", 'p', arg_string, &port_str, "Use this port", - "number-or-service" }, - { "from", 0, arg_flag, &do_from, "Behave like from", - NULL }, - { "headers", 0, arg_string, &header_str, "Headers to print", NULL }, - { "count", 'c', arg_flag, &do_count, "Print number of messages", NULL}, - { "version", 0, arg_flag, &do_version, "Print version", - NULL }, - { "help", 0, arg_flag, &do_help, NULL, - NULL } - -}; - -static void -usage (int ret) -{ - arg_printusage (args, - sizeof(args) / sizeof(args[0]), - NULL, - "[[{po:username[@hostname] | hostname[:username]}] ...] " - "filename"); - exit (ret); -} - -static int -do_connect (const char *hostname, int port, int nodelay) -{ - struct addrinfo *ai, *a; - struct addrinfo hints; - int error; - int s = -1; - char portstr[NI_MAXSERV]; - - memset (&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - - snprintf (portstr, sizeof(portstr), "%u", ntohs(port)); - - error = getaddrinfo (hostname, portstr, &hints, &ai); - if (error) - errx (1, "getaddrinfo(%s): %s", hostname, gai_strerror(error)); - - for (a = ai; a != NULL; a = a->ai_next) { - s = socket (a->ai_family, a->ai_socktype, a->ai_protocol); - if (s < 0) - continue; - if (connect (s, a->ai_addr, a->ai_addrlen) < 0) { - warn ("connect(%s)", hostname); - close (s); - continue; - } - break; - } - freeaddrinfo (ai); - if (a == NULL) { - warnx ("failed to contact %s", hostname); - return -1; - } - - if(setsockopt(s, IPPROTO_TCP, TCP_NODELAY, - (void *)&nodelay, sizeof(nodelay)) < 0) - err (1, "setsockopt TCP_NODELAY"); - return s; -} - -typedef enum { INIT = 0, GREET, USER, PASS, STAT, RETR, TOP, - DELE, XDELE, QUIT} pop_state; - -static char *pop_state_string[] = { - "INIT", "GREET", "USER", "PASS", "STAT", "RETR", "TOP", - "DELE", "XDELE", "QUIT" -}; - -#define PUSH_BUFSIZ 65536 - -#define STEP 16 - -struct write_state { - struct iovec *iovecs; - size_t niovecs, maxiovecs, allociovecs; - int fd; -}; - -static void -write_state_init (struct write_state *w, int fd) -{ -#ifdef UIO_MAXIOV - w->maxiovecs = UIO_MAXIOV; -#else - w->maxiovecs = 16; -#endif - w->allociovecs = min(STEP, w->maxiovecs); - w->niovecs = 0; - w->iovecs = emalloc(w->allociovecs * sizeof(*w->iovecs)); - w->fd = fd; -} - -static void -write_state_add (struct write_state *w, void *v, size_t len) -{ - if(w->niovecs == w->allociovecs) { - if(w->niovecs == w->maxiovecs) { - if(writev (w->fd, w->iovecs, w->niovecs) < 0) - err(1, "writev"); - w->niovecs = 0; - } else { - w->allociovecs = min(w->allociovecs + STEP, w->maxiovecs); - w->iovecs = erealloc (w->iovecs, - w->allociovecs * sizeof(*w->iovecs)); - } - } - w->iovecs[w->niovecs].iov_base = v; - w->iovecs[w->niovecs].iov_len = len; - ++w->niovecs; -} - -static void -write_state_flush (struct write_state *w) -{ - if (w->niovecs) { - if (writev (w->fd, w->iovecs, w->niovecs) < 0) - err (1, "writev"); - w->niovecs = 0; - } -} - -static void -write_state_destroy (struct write_state *w) -{ - free (w->iovecs); -} - -static int -doit(int s, - const char *host, - const char *user, - const char *outfilename, - const char *header_str, - int leavep, - int verbose, - int forkp) -{ - int ret; - char out_buf[PUSH_BUFSIZ]; - int out_len = 0; - char *in_buf; - size_t in_buf_size; - size_t in_len = 0; - char *in_ptr; - pop_state state = INIT; - unsigned count = 0, bytes; - unsigned asked_for = 0, retrieved = 0, asked_deleted = 0, deleted = 0; - unsigned sent_xdele = 0; - int out_fd; - char from_line[128]; - size_t from_line_length; - time_t now; - struct write_state write_state; - unsigned int numheaders = 1; - char **headers = NULL; - int i; - char *tmp = NULL; - - in_buf = emalloc(PUSH_BUFSIZ + 1); - in_ptr = in_buf; - in_buf_size = PUSH_BUFSIZ; - - if (do_from) { - char *tmp2; - - tmp2 = tmp = estrdup(header_str); - - out_fd = -1; - if (verbose) - fprintf (stderr, "%s@%s\n", user, host); - while (*tmp != '\0') { - tmp = strchr(tmp, ','); - if (tmp == NULL) - break; - tmp++; - numheaders++; - } - - headers = emalloc(sizeof(char *) * (numheaders + 1)); - for (i = 0; i < numheaders; i++) { - headers[i] = strtok_r(tmp2, ",", &tmp2); - } - headers[numheaders] = NULL; - } else { - out_fd = open(outfilename, O_WRONLY | O_APPEND | O_CREAT, 0666); - if (out_fd < 0) - err (1, "open %s", outfilename); - if (verbose) - fprintf (stderr, "%s@%s -> %s\n", user, host, outfilename); - } - - now = time(NULL); - from_line_length = snprintf (from_line, sizeof(from_line), - "From %s %s", "push", ctime(&now)); - if (from_line_length < 0 || from_line_length > sizeof(from_line)) - errx (1, "snprintf failed"); - - out_len = snprintf (out_buf, sizeof(out_buf), - "USER %s\r\nPASS hej\r\nSTAT\r\n", - user); - if (out_len < 0 || out_len > sizeof(out_buf)) - errx (1, "snprintf failed"); - if (net_write (s, out_buf, out_len) != out_len) - err (1, "write"); - if (verbose > 1) - fprintf (stderr, "%s", out_buf); - - if (!do_from) - write_state_init (&write_state, out_fd); - - while(state != QUIT) { - fd_set readset, writeset; - - FD_ZERO(&readset); - FD_ZERO(&writeset); - if (s >= FD_SETSIZE) - errx (1, "fd too large"); - FD_SET(s,&readset); - - if (verbose > 1) - fprintf (stderr, "state: %s count: %d asked_for: %d " - "retrieved: %d asked_deleted: %d\n", - pop_state_string[state], - count, asked_for, retrieved, asked_deleted); - - if (((state == STAT || state == RETR || state == TOP) - && asked_for < count) - || (state == XDELE && !sent_xdele) - || (state == DELE && asked_deleted < count)) - FD_SET(s,&writeset); - ret = select (s + 1, &readset, &writeset, NULL, NULL); - if (ret < 0) { - if (errno == EAGAIN) - continue; - else - err (1, "select"); - } - - if (FD_ISSET(s, &readset)) { - char *beg, *p; - size_t rem; - int blank_line = 0; - - if(in_len >= in_buf_size) { - char *tmp = erealloc(in_buf, in_buf_size + PUSH_BUFSIZ + 1); - in_ptr = tmp + (in_ptr - in_buf); - in_buf = tmp; - in_buf_size += PUSH_BUFSIZ; - } - - ret = read (s, in_ptr, in_buf_size - in_len); - if (ret < 0) - err (1, "read"); - else if (ret == 0) - errx (1, "EOF during read"); - - in_len += ret; - in_ptr += ret; - *in_ptr = '\0'; - - beg = in_buf; - rem = in_len; - while(rem > 1 - && (p = strstr(beg, "\r\n")) != NULL) { - if (state == TOP) { - char *copy = beg; - - for (i = 0; i < numheaders; i++) { - size_t len; - - len = min(p - copy + 1, strlen(headers[i])); - if (strncasecmp(copy, headers[i], len) == 0) { - fprintf (stdout, "%.*s\n", (int)(p - copy), copy); - } - } - if (beg[0] == '.' && beg[1] == '\r' && beg[2] == '\n') { - if (numheaders > 1) - fprintf (stdout, "\n"); - state = STAT; - if (++retrieved == count) { - state = QUIT; - net_write (s, "QUIT\r\n", 6); - if (verbose > 1) - fprintf (stderr, "QUIT\r\n"); - } - } - rem -= p - beg + 2; - beg = p + 2; - } else if (state == RETR) { - char *copy = beg; - if (beg[0] == '.') { - if (beg[1] == '\r' && beg[2] == '\n') { - if(!blank_line) - write_state_add(&write_state, "\n", 1); - state = STAT; - rem -= p - beg + 2; - beg = p + 2; - if (++retrieved == count) { - write_state_flush (&write_state); - if (fsync (out_fd) < 0) - err (1, "fsync"); - close(out_fd); - if (leavep) { - state = QUIT; - net_write (s, "QUIT\r\n", 6); - if (verbose > 1) - fprintf (stderr, "QUIT\r\n"); - } else { - if (forkp) { - pid_t pid; - - pid = fork(); - if (pid < 0) - warn ("fork"); - else if(pid != 0) { - if(verbose) - fprintf (stderr, - "(exiting)"); - return 0; - } - } - - state = XDELE; - if (verbose) - fprintf (stderr, "deleting... "); - } - } - continue; - } else - ++copy; - } - *p = '\n'; - if(blank_line && - strncmp(copy, "From ", min(p - copy + 1, 5)) == 0) - write_state_add(&write_state, ">", 1); - write_state_add(&write_state, copy, p - copy + 1); - blank_line = (*copy == '\n'); - rem -= p - beg + 2; - beg = p + 2; - } else if (rem >= 3 && strncmp (beg, "+OK", 3) == 0) { - if (state == STAT) { - if (!do_from) - write_state_add(&write_state, - from_line, from_line_length); - blank_line = 0; - if (do_from) - state = TOP; - else - state = RETR; - } else if (state == XDELE) { - state = QUIT; - net_write (s, "QUIT\r\n", 6); - if (verbose > 1) - fprintf (stderr, "QUIT\r\n"); - break; - } else if (state == DELE) { - if (++deleted == count) { - state = QUIT; - net_write (s, "QUIT\r\n", 6); - if (verbose > 1) - fprintf (stderr, "QUIT\r\n"); - break; - } - } else if (++state == STAT) { - if(sscanf (beg + 4, "%u %u", &count, &bytes) != 2) - errx(1, "Bad STAT-line: %.*s", (int)(p - beg), beg); - if (verbose) { - fprintf (stderr, "%u message(s) (%u bytes). " - "fetching... ", - count, bytes); - if (do_from) - fprintf (stderr, "\n"); - } else if (do_count) { - fprintf (stderr, "%u message(s) (%u bytes).\n", - count, bytes); - } - if (count == 0) { - state = QUIT; - net_write (s, "QUIT\r\n", 6); - if (verbose > 1) - fprintf (stderr, "QUIT\r\n"); - break; - } - } - - rem -= p - beg + 2; - beg = p + 2; - } else { - if(state == XDELE) { - state = DELE; - rem -= p - beg + 2; - beg = p + 2; - } else - errx (1, "Bad response: %.*s", (int)(p - beg), beg); - } - } - if (!do_from) - write_state_flush (&write_state); - - memmove (in_buf, beg, rem); - in_len = rem; - in_ptr = in_buf + rem; - } - if (FD_ISSET(s, &writeset)) { - if ((state == STAT && !do_from) || state == RETR) - out_len = snprintf (out_buf, sizeof(out_buf), - "RETR %u\r\n", ++asked_for); - else if ((state == STAT && do_from) || state == TOP) - out_len = snprintf (out_buf, sizeof(out_buf), - "TOP %u 0\r\n", ++asked_for); - else if(state == XDELE) { - out_len = snprintf(out_buf, sizeof(out_buf), - "XDELE %u %u\r\n", 1, count); - sent_xdele++; - } - else if(state == DELE) - out_len = snprintf (out_buf, sizeof(out_buf), - "DELE %u\r\n", ++asked_deleted); - if (out_len < 0 || out_len > sizeof(out_buf)) - errx (1, "snprintf failed"); - if (net_write (s, out_buf, out_len) != out_len) - err (1, "write"); - if (verbose > 1) - fprintf (stderr, "%s", out_buf); - } - } - if (verbose) - fprintf (stderr, "Done\n"); - if (do_from) { - free (tmp); - free (headers); - } else { - write_state_destroy (&write_state); - } - return 0; -} - -#ifdef KRB5 -static int -do_v5 (const char *host, - int port, - const char *user, - const char *filename, - const char *header_str, - int leavep, - int verbose, - int forkp) -{ - krb5_error_code ret; - krb5_auth_context auth_context = NULL; - krb5_principal server; - int s; - - s = do_connect (host, port, 1); - if (s < 0) - return 1; - - ret = krb5_sname_to_principal (context, - host, - "pop", - KRB5_NT_SRV_HST, - &server); - if (ret) { - warnx ("krb5_sname_to_principal: %s", - krb5_get_err_text (context, ret)); - return 1; - } - - ret = krb5_sendauth (context, - &auth_context, - &s, - "KPOPV1.0", - NULL, - server, - 0, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); - krb5_free_principal (context, server); - if (ret) { - warnx ("krb5_sendauth: %s", - krb5_get_err_text (context, ret)); - return 1; - } - return doit (s, host, user, filename, header_str, leavep, verbose, forkp); -} -#endif - -#ifdef HESIOD - -#ifdef HESIOD_INTERFACES - -static char * -hesiod_get_pobox (const char **user) -{ - void *context; - struct hesiod_postoffice *hpo; - char *ret = NULL; - - if(hesiod_init (&context) != 0) - err (1, "hesiod_init"); - - hpo = hesiod_getmailhost (context, *user); - if (hpo == NULL) { - warn ("hesiod_getmailhost %s", *user); - } else { - if (strcasecmp(hpo->hesiod_po_type, "pop") != 0) - errx (1, "Unsupported po type %s", hpo->hesiod_po_type); - - ret = estrdup(hpo->hesiod_po_host); - *user = estrdup(hpo->hesiod_po_name); - hesiod_free_postoffice (context, hpo); - } - hesiod_end (context); - return ret; -} - -#else /* !HESIOD_INTERFACES */ - -static char * -hesiod_get_pobox (const char **user) -{ - char *ret = NULL; - struct hes_postoffice *hpo; - - hpo = hes_getmailhost (*user); - if (hpo == NULL) { - warn ("hes_getmailhost %s", *user); - } else { - if (strcasecmp(hpo->po_type, "pop") != 0) - errx (1, "Unsupported po type %s", hpo->po_type); - - ret = estrdup(hpo->po_host); - *user = estrdup(hpo->po_name); - } - return ret; -} - -#endif /* HESIOD_INTERFACES */ - -#endif /* HESIOD */ - -static char * -get_pobox (const char **user) -{ - char *ret = NULL; - -#ifdef HESIOD - ret = hesiod_get_pobox (user); -#endif - - if (ret == NULL) - ret = getenv("MAILHOST"); - if (ret == NULL) - errx (1, "MAILHOST not set"); - return ret; -} - -static void -parse_pobox (char *a0, const char **host, const char **user) -{ - const char *h, *u; - char *p; - int po = 0; - - if (a0 == NULL) { - - *user = getenv ("USERNAME"); - if (*user == NULL) { - struct passwd *pwd = getpwuid (getuid ()); - - if (pwd == NULL) - errx (1, "Who are you?"); - *user = estrdup (pwd->pw_name); - } - *host = get_pobox (user); - return; - } - - /* if the specification starts with po:, remember this information */ - if(strncmp(a0, "po:", 3) == 0) { - a0 += 3; - po++; - } - /* if there is an `@', the hostname is after it, otherwise at the - beginning of the string */ - p = strchr(a0, '@'); - if(p != NULL) { - *p++ = '\0'; - h = p; - } else { - h = a0; - } - /* if there is a `:', the username comes before it, otherwise at - the beginning of the string */ - p = strchr(a0, ':'); - if(p != NULL) { - *p++ = '\0'; - u = p; - } else { - u = a0; - } - if(h == u) { - /* some inconsistent compatibility with various mailers */ - if(po) { - h = get_pobox (&u); - } else { - u = get_default_username (); - if (u == NULL) - errx (1, "Who are you?"); - } - } - *host = h; - *user = u; -} - -int -main(int argc, char **argv) -{ - int port = 0; - int optind = 0; - int ret = 1; - const char *host, *user, *filename = NULL; - char *pobox = NULL; - - setprogname (argv[0]); - -#ifdef KRB5 - { - krb5_error_code ret; - - ret = krb5_init_context (&context); - if (ret) - errx (1, "krb5_init_context failed: %d", ret); - } -#endif - - if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, - &optind)) - usage (1); - - argc -= optind; - argv += optind; - - if (do_help) - usage (0); - - if (do_version) { - print_version(NULL); - return 0; - } - - if (do_from && header_str == NULL) - header_str = "From:"; - else if (header_str != NULL) - do_from = 1; - - if (do_from) { - if (argc == 0) - pobox = NULL; - else if (argc == 1) - pobox = argv[0]; - else - usage (1); - } else { - if (argc == 1) { - filename = argv[0]; - pobox = NULL; - } else if (argc == 2) { - filename = argv[1]; - pobox = argv[0]; - } else - usage (1); - } - - if (port_str) { - struct servent *s = roken_getservbyname (port_str, "tcp"); - - if (s) - port = s->s_port; - else { - char *ptr; - - port = strtol (port_str, &ptr, 10); - if (port == 0 && ptr == port_str) - errx (1, "Bad port `%s'", port_str); - port = htons(port); - } - } - if (port == 0) { -#ifdef KRB5 - port = krb5_getportbyname (context, "kpop", "tcp", 1109); -#else -#error must define KRB5 -#endif - } - - parse_pobox (pobox, &host, &user); - -#ifdef KRB5 - if (ret && use_v5) { - ret = do_v5 (host, port, user, filename, header_str, - do_leave, verbose_level, do_fork); - } -#endif - return ret; -} diff --git a/appl/rcp/ChangeLog b/appl/rcp/ChangeLog deleted file mode 100644 index 25a0a5176..000000000 --- a/appl/rcp/ChangeLog +++ /dev/null @@ -1,130 +0,0 @@ -2008-04-17 Love Hörnquist Åstrand - - * Sync with NetBSD rcp, add v6 parsing support and no setuid code - at all. - -2007-12-13 Love Hörnquist Åstrand - - * Makefile.am: Add missing files, from Buchan Milne. - -2006-10-20 Love Hörnquist Åstrand - - * Makefile.am: more files - -2006-08-08 Love Hörnquist Åstrand - - * util.c: Check return values from setuid, prompted by MIT - advisory. Thanks to Tom Yu at MIT, and Michael Calmer and Marcus - Meissner at SUSE. Either of CVE-2006-3083 or CVE-2006-3084. - - * rcp.c: Check return values from setuid, prompted by MIT - advisory. Thanks to Tom Yu at MIT, and Michael Calmer and Marcus - Meissner at SUSE. Either of CVE-2006-3083 or CVE-2006-3084. - - * rcp.c: Check return values from seteuid, prompted by MIT - advisory. Thanks to Tom Yu at MIT, and Michael Calmer and Marcus - Meissner at SUSE. Either of CVE-2006-3083 or CVE-2006-3084. - -2005-10-22 Love Hörnquist Åstrand - - * rcp.c: Check return value from asprintf instead of string != - NULL since it undefined behavior on Linux. From Björn Sandell - -2005-08-30 Love Hörnquist Åstrand - - * util.c: Explicit typecast to avoid signess warning. - -2005-05-29 Love Hörnquist Åstrand - - * rcp_locl.h: undef _PATH_RSH to make sure our version is used - -2005-05-11 David Love - - * rcp.c: MODEMASK is defined in sys/vnode.h on Solaris, so undef - it before we define our own. - -2005-04-27 Love Hörnquist Åstrand - - * rcp_locl.h: use BINDIR instead of "/usr/bin/ with _PATH_RSH - -2005-04-18 Love Hörnquist Åstrand - - * util.c: use unsigned char * to make sure its not negative when - passing it to is* functions - -2004-05-14 Johan Danielsson - - * rcp.c: add -e (passed to rsh) - -2003-04-16 Johan Danielsson - - * rcp.1: add a HISTORY section - - * rcp.1: brief manpage - - * rcp.c: add a -4 option - -2001-09-24 Johan Danielsson - - * rcp.c: more va_* fixing; from Thomas Klausner - -2001-09-08 Assar Westerlund - - * rcp.c (run_err): always match va_start and va_end - -2001-09-04 Assar Westerlund - - * util.c (allocbuf): do not leak memory on failure and zero - re-used memory, from Markus Friedl - -2001-07-19 Assar Westerlund - - * rcp.c (main): add missing setprogname - -2001-06-14 Assar Westerlund - - * rcp.c: add some const replace a few malloc/snprintf with - asprintf - * rcp.c (sizestr): remove and use snprintf to do this correctly - instead - -2001-04-21 Johan Danielsson - - * rcp.c: convert to use getarg - - * rcp.c: do a better job of supporting files larger than 2GB - -2001-02-07 Assar Westerlund - - * rcp.c: add -F for forwarding ticket, from Ake Sandgren - - -2001-01-29 Assar Westerlund - - * util.c (roundup): add fallback definition - - * rcp.c: remove non-STDC code - * rcp_locl.h: add sys/types.h and sys/wait.h - - * rcp.c: no calls to err with NULL - -2001-01-28 Assar Westerlund - - * rcp_locl.h: add - - * Makefile.am (LDADD): remove unused libraries - -2001-01-27 Assar Westerlund - - * util.c: replace vfork by fork - - * rcp.c: add RCSID S_ISTXT -> S_ISVTX printf sizes of files with - %lu instead of %q (which is not portable) - - * util.c: add RCSID do not use sig_t - * rcp.c: remove __P, use st_mtime et al from struct stat - * extern.h: remove __P - - * initial import of port of bsd rcp changed to use existing rsh, - contributed by Richard Nyberg - diff --git a/appl/rcp/Makefile.am b/appl/rcp/Makefile.am deleted file mode 100644 index e635d8987..000000000 --- a/appl/rcp/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ -# $Id$ - -include $(top_srcdir)/Makefile.am.common - -AM_CPPFLAGS += $(INCLUDE_krb4) - -bin_PROGRAMS = rcp - -rcp_SOURCES = rcp.c util.c rcp_locl.h extern.h - -man_MANS = rcp.1 - -EXTRA_DIST = $(man_MANS) - -LDADD = $(LIB_roken) diff --git a/appl/rcp/rcp.1 b/appl/rcp/rcp.1 deleted file mode 100644 index 4c0f13ddb..000000000 --- a/appl/rcp/rcp.1 +++ /dev/null @@ -1,67 +0,0 @@ -.\" $Id$ -.\" -.Dd April 16, 2003 -.Dt RCP 1 -.Os HEIMDAL -.Sh NAME -.Nm rcp -.Nd -copy file to and from remote machines -.Sh SYNOPSIS -.Nm rcp -.Op Fl 45FKpxz -.Op Fl P Ar port -.Ar file1 file2 -.Nm rcp -.Op Fl 45FKprxz -.Op Fl P Ar port -.Ar file... directory -.Sh DESCRIPTION -.Nm rcp -copies files between machines. Each file argument is either a remote file name of the form -.Dq rname@rhost:path -or a local file (containing no colon or with a slash before the first -colon). -.Pp -Supported options: -.Bl -tag -width Ds -.It Xo -.Fl 4 , -.Fl 5 , -.Fl K , -.Fl F , -.Fl x , -.Fl z -.Xc -These options are passed on to -.Xr rsh 1 . -.It Fl P Ar port -This will pass the option -.Fl p Ar port -to -.Xr rsh 1 . -.It Fl p -Preserve file permissions. -.It Fl r -Copy source directories recursively. -.El -.\".Sh ENVIRONMENT -.\".Sh FILES -.\".Sh EXAMPLES -.Sh DIAGNOSTICS -.Nm rcp -is implemented as a protocol on top of -.Xr rsh 1 , -and thus requires a working rsh. If you intend to use Kerberos -authentication, rsh needs to be Kerberos aware, else you may see more -or less strange errors, such as "login incorrect", or "lost -connection". -.\".Sh SEE ALSO -.\".Sh STANDARDS -.Sh HISTORY -The -.Nm rcp -utility first appeared in 4.2BSD. This version is derived from -4.3BSD-Reno. -.\".Sh AUTHORS -.\".Sh BUGS diff --git a/appl/rcp/rcp.c b/appl/rcp/rcp.c deleted file mode 100644 index 13e831ee0..000000000 --- a/appl/rcp/rcp.c +++ /dev/null @@ -1,788 +0,0 @@ -/* - * Copyright (c) 1983, 1990, 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "rcp_locl.h" -#include - -#define RSH_PROGRAM "rsh" - -struct passwd *pwd; -uid_t userid; -int errs, remin, remout; -int pflag, iamremote, iamrecursive, targetshouldbedirectory; -int doencrypt, noencrypt; -int usebroken, usekrb4, usekrb5, forwardtkt; -char *port; -int eflag = 0; - -#define CMDNEEDS 64 -char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ - -int response (void); -void rsource (char *, struct stat *); -void sink (int, char *[]); -void source (int, char *[]); -void tolocal (int, char *[]); -void toremote (char *, int, char *[]); - -int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout); - -static int fflag, tflag; - -static int version_flag, help_flag; - -struct getargs args[] = { - { NULL, '4', arg_flag, &usekrb4, "use Kerberos 4 authentication" }, - { NULL, '5', arg_flag, &usekrb5, "use Kerberos 5 authentication" }, - { NULL, 'F', arg_flag, &forwardtkt, "forward credentials" }, - { NULL, 'K', arg_flag, &usebroken, "use BSD authentication" }, - { NULL, 'P', arg_string, &port, "non-default port", "port" }, - { NULL, 'p', arg_flag, &pflag, "preserve file permissions" }, - { NULL, 'r', arg_flag, &iamrecursive, "recursive mode" }, - { NULL, 'x', arg_flag, &doencrypt, "use encryption" }, - { NULL, 'z', arg_flag, &noencrypt, "don't encrypt" }, - { NULL, 'd', arg_flag, &targetshouldbedirectory }, - { NULL, 'e', arg_flag, &eflag, "passed to rsh" }, - { NULL, 'f', arg_flag, &fflag }, - { NULL, 't', arg_flag, &tflag }, - { "version", 0, arg_flag, &version_flag }, - { "help", 0, arg_flag, &help_flag } -}; - -static void -usage (int ret) -{ - arg_printusage (args, - sizeof(args) / sizeof(args[0]), - NULL, - "file1 file2|file... directory"); - exit (ret); -} - -int -main(int argc, char **argv) -{ - char *targ; - int optind = 0; - - setprogname(argv[0]); - if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, - &optind)) - usage (1); - if(help_flag) - usage(0); - if (version_flag) { - print_version (NULL); - return 0; - } - - iamremote = (fflag || tflag); - - argc -= optind; - argv += optind; - - if ((pwd = getpwuid(userid = getuid())) == NULL) - errx(1, "unknown user %d", (int)userid); - - remin = STDIN_FILENO; /* XXX */ - remout = STDOUT_FILENO; - - if (fflag) { /* Follow "protocol", send data. */ - (void)response(); - source(argc, argv); - exit(errs); - } - - if (tflag) { /* Receive data. */ - sink(argc, argv); - exit(errs); - } - - if (argc < 2) - usage(1); - if (argc > 2) - targetshouldbedirectory = 1; - - remin = remout = -1; - /* Command to be executed on remote system using "rsh". */ - snprintf(cmd, sizeof(cmd), - "rcp%s%s%s", iamrecursive ? " -r" : "", - pflag ? " -p" : "", targetshouldbedirectory ? " -d" : ""); - - signal(SIGPIPE, lostconn); - - if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */ - toremote(targ, argc, argv); - else { - tolocal(argc, argv); /* Dest is local host. */ - if (targetshouldbedirectory) - verifydir(argv[argc - 1]); - } - exit(errs); -} - -void -toremote(char *targ, int argc, char **argv) -{ - int i; - char *bp, *host, *src, *suser, *thost, *tuser; - - *targ++ = 0; - if (*targ == 0) - targ = "."; - - if ((thost = strchr(argv[argc - 1], '@')) != NULL) { - /* user@host */ - *thost++ = 0; - tuser = argv[argc - 1]; - if (*tuser == '\0') - tuser = NULL; - else if (!okname(tuser)) - exit(1); - } else { - thost = argv[argc - 1]; - tuser = NULL; - } - thost = unbracket(thost); - - for (i = 0; i < argc - 1; i++) { - src = colon(argv[i]); - if (src) { /* remote to remote */ - int ret; - *src++ = 0; - if (*src == 0) - src = "."; - host = strchr(argv[i], '@'); - if (host) { - *host++ = '\0'; - host = unbracket(host); - suser = argv[i]; - if (*suser == '\0') - suser = pwd->pw_name; - else if (!okname(suser)) - continue; - ret = asprintf(&bp, - "%s%s %s -l %s -n %s %s '%s%s%s:%s'", - _PATH_RSH, eflag ? " -e" : "", - host, suser, cmd, src, - tuser ? tuser : "", tuser ? "@" : "", - thost, targ); - } else { - host = unbracket(argv[i]); - ret = asprintf(&bp, - "exec %s%s %s -n %s %s '%s%s%s:%s'", - _PATH_RSH, eflag ? " -e" : "", - host, cmd, src, - tuser ? tuser : "", tuser ? "@" : "", - thost, targ); - } - if (ret == -1) - err (1, "malloc"); - susystem(bp); - free(bp); - } else { /* local to remote */ - if (remin == -1) { - if (asprintf(&bp, "%s -t %s", cmd, targ) == -1) - err (1, "malloc"); - host = thost; - - if (do_cmd(host, tuser, bp, &remin, &remout) < 0) - exit(1); - - if (response() < 0) - exit(1); - free(bp); - } - source(1, argv+i); - } - } -} - -void -tolocal(int argc, char **argv) -{ - int i; - char *bp, *host, *src, *suser; - - for (i = 0; i < argc - 1; i++) { - int ret; - - if (!(src = colon(argv[i]))) { /* Local to local. */ - ret = asprintf(&bp, "exec %s%s%s %s %s", _PATH_CP, - iamrecursive ? " -PR" : "", pflag ? " -p" : "", - argv[i], argv[argc - 1]); - if (ret == -1) - err (1, "malloc"); - if (susystem(bp)) - ++errs; - free(bp); - continue; - } - *src++ = 0; - if (*src == 0) - src = "."; - if ((host = strchr(argv[i], '@')) == NULL) { - host = argv[i]; - suser = pwd->pw_name; - } else { - *host++ = 0; - suser = argv[i]; - if (*suser == '\0') - suser = pwd->pw_name; - else if (!okname(suser)) - continue; - } - ret = asprintf(&bp, "%s -f %s", cmd, src); - if (ret == -1) - err (1, "malloc"); - if (do_cmd(host, suser, bp, &remin, &remout) < 0) { - free(bp); - ++errs; - continue; - } - free(bp); - sink(1, argv + argc - 1); - close(remin); - remin = remout = -1; - } -} - -void -source(int argc, char **argv) -{ - struct stat stb; - static BUF buffer; - BUF *bp; - off_t i; - off_t amt; - int fd, haderr, indx, result; - char *last, *name, buf[BUFSIZ]; - - for (indx = 0; indx < argc; ++indx) { - name = argv[indx]; - if ((fd = open(name, O_RDONLY, 0)) < 0) - goto syserr; - if (fstat(fd, &stb)) { -syserr: run_err("%s: %s", name, strerror(errno)); - goto next; - } - if (S_ISDIR(stb.st_mode) && iamrecursive) { - rsource(name, &stb); - goto next; - } else if (!S_ISREG(stb.st_mode)) { - run_err("%s: not a regular file", name); - goto next; - } - if ((last = strrchr(name, '/')) == NULL) - last = name; - else - ++last; - if (pflag) { - /* - * Make it compatible with possible future - * versions expecting microseconds. - */ - snprintf(buf, sizeof(buf), "T%ld 0 %ld 0\n", - (long)stb.st_mtime, - (long)stb.st_atime); - write(remout, buf, strlen(buf)); - if (response() < 0) - goto next; - } -#undef MODEMASK -#define MODEMASK (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) - snprintf(buf, sizeof(buf), "C%04o %lu %s\n", - stb.st_mode & MODEMASK, - (unsigned long)stb.st_size, - last); - write(remout, buf, strlen(buf)); - if (response() < 0) - goto next; - if ((bp = allocbuf(&buffer, fd, BUFSIZ)) == NULL) { -next: close(fd); - continue; - } - - /* Keep writing after an error so that we stay sync'd up. */ - for (haderr = i = 0; i < stb.st_size; i += bp->cnt) { - amt = bp->cnt; - if (i + amt > stb.st_size) - amt = stb.st_size - i; - if (!haderr) { - result = read(fd, bp->buf, (size_t)amt); - if (result != amt) - haderr = result >= 0 ? EIO : errno; - } - if (haderr) - write(remout, bp->buf, amt); - else { - result = write(remout, bp->buf, (size_t)amt); - if (result != amt) - haderr = result >= 0 ? EIO : errno; - } - } - if (close(fd) && !haderr) - haderr = errno; - if (!haderr) - write(remout, "", 1); - else - run_err("%s: %s", name, strerror(haderr)); - response(); - } -} - -void -rsource(char *name, struct stat *statp) -{ - DIR *dirp; - struct dirent *dp; - char *last, *vect[1], path[MAXPATHLEN]; - - if (!(dirp = opendir(name))) { - run_err("%s: %s", name, strerror(errno)); - return; - } - last = strrchr(name, '/'); - if (last == 0) - last = name; - else - last++; - if (pflag) { - snprintf(path, sizeof(path), "T%ld 0 %ld 0\n", - (long)statp->st_mtime, - (long)statp->st_atime); - write(remout, path, strlen(path)); - if (response() < 0) { - closedir(dirp); - return; - } - } - snprintf(path, sizeof(path), - "D%04o %d %s\n", statp->st_mode & MODEMASK, 0, last); - write(remout, path, strlen(path)); - if (response() < 0) { - closedir(dirp); - return; - } - while ((dp = readdir(dirp)) != NULL) { - if (dp->d_ino == 0) - continue; - if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) - continue; - if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) { - run_err("%s/%s: name too long", name, dp->d_name); - continue; - } - snprintf(path, sizeof(path), "%s/%s", name, dp->d_name); - vect[0] = path; - source(1, vect); - } - closedir(dirp); - write(remout, "E\n", 2); - response(); -} - -void -sink(int argc, char **argv) -{ - static BUF buffer; - struct stat stb; - struct timeval tv[2]; - enum { YES, NO, DISPLAYED } wrerr; - BUF *bp; - off_t i, j, size; - int amt, count, exists, first, mask, mode, ofd, omode; - int setimes, targisdir, wrerrno = 0; - char ch, *cp, *np, *targ, *why, *vect[1], buf[BUFSIZ]; - -#define atime tv[0] -#define mtime tv[1] -#define SCREWUP(str) { why = str; goto screwup; } - - setimes = targisdir = 0; - mask = umask(0); - if (!pflag) - umask(mask); - if (argc != 1) { - run_err("ambiguous target"); - exit(1); - } - targ = *argv; - if (targetshouldbedirectory) - verifydir(targ); - write(remout, "", 1); - if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) - targisdir = 1; - for (first = 1;; first = 0) { - cp = buf; - if (read(remin, cp, 1) <= 0) - return; - if (*cp++ == '\n') - SCREWUP("unexpected "); - do { - if (read(remin, &ch, sizeof(ch)) != sizeof(ch)) - SCREWUP("lost connection"); - *cp++ = ch; - } while (cp < &buf[BUFSIZ - 1] && ch != '\n'); - *cp = 0; - - if (buf[0] == '\01' || buf[0] == '\02') { - if (iamremote == 0) - write(STDERR_FILENO, - buf + 1, strlen(buf + 1)); - if (buf[0] == '\02') - exit(1); - ++errs; - continue; - } - if (buf[0] == 'E') { - write(remout, "", 1); - return; - } - - if (ch == '\n') - *--cp = 0; - - cp = buf; - if (*cp == 'T') { - setimes++; - cp++; - mtime.tv_sec = strtol(cp, &cp, 10); - if (!cp || *cp++ != ' ') - SCREWUP("mtime.sec not delimited"); - mtime.tv_usec = strtol(cp, &cp, 10); - if (!cp || *cp++ != ' ') - SCREWUP("mtime.usec not delimited"); - atime.tv_sec = strtol(cp, &cp, 10); - if (!cp || *cp++ != ' ') - SCREWUP("atime.sec not delimited"); - atime.tv_usec = strtol(cp, &cp, 10); - if (!cp || *cp++ != '\0') - SCREWUP("atime.usec not delimited"); - write(remout, "", 1); - continue; - } - if (*cp != 'C' && *cp != 'D') { - /* - * Check for the case "rcp remote:foo\* local:bar". - * In this case, the line "No match." can be returned - * by the shell before the rcp command on the remote is - * executed so the ^Aerror_message convention isn't - * followed. - */ - if (first) { - run_err("%s", cp); - exit(1); - } - SCREWUP("expected control record"); - } - mode = 0; - for (++cp; cp < buf + 5; cp++) { - if (*cp < '0' || *cp > '7') - SCREWUP("bad mode"); - mode = (mode << 3) | (*cp - '0'); - } - if (*cp++ != ' ') - SCREWUP("mode not delimited"); - - for (size = 0; isdigit((unsigned char)*cp);) - size = size * 10 + (*cp++ - '0'); - if (*cp++ != ' ') - SCREWUP("size not delimited"); - if (targisdir) { - static char *namebuf; - static int cursize; - size_t need; - - need = strlen(targ) + strlen(cp) + 250; - if (need > cursize) { - if (!(namebuf = malloc(need))) - run_err("%s", strerror(errno)); - } - snprintf(namebuf, need, "%s%s%s", targ, - *targ ? "/" : "", cp); - np = namebuf; - } else - np = targ; - exists = stat(np, &stb) == 0; - if (buf[0] == 'D') { - int mod_flag = pflag; - if (exists) { - if (!S_ISDIR(stb.st_mode)) { - errno = ENOTDIR; - goto bad; - } - if (pflag) - chmod(np, mode); - } else { - /* Handle copying from a read-only directory */ - mod_flag = 1; - if (mkdir(np, mode | S_IRWXU) < 0) - goto bad; - } - vect[0] = np; - sink(1, vect); - if (setimes) { - setimes = 0; - if (utimes(np, tv) < 0) - run_err("%s: set times: %s", - np, strerror(errno)); - } - if (mod_flag) - chmod(np, mode); - continue; - } - omode = mode; - mode |= S_IWRITE; - if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { -bad: run_err("%s: %s", np, strerror(errno)); - continue; - } - write(remout, "", 1); - if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == NULL) { - close(ofd); - continue; - } - cp = bp->buf; - wrerr = NO; - for (count = i = 0; i < size; i += BUFSIZ) { - amt = BUFSIZ; - if (i + amt > size) - amt = size - i; - count += amt; - if((j = net_read(remin, cp, amt)) != amt) { - run_err("%s", j ? strerror(errno) : - "dropped connection"); - exit(1); - } - amt -= j; - cp += j; - if (count == bp->cnt) { - /* Keep reading so we stay sync'd up. */ - if (wrerr == NO) { - j = write(ofd, bp->buf, (size_t)count); - if (j != count) { - wrerr = YES; - wrerrno = j >= 0 ? EIO : errno; - } - } - count = 0; - cp = bp->buf; - } - } - if (count != 0 && wrerr == NO && - (j = write(ofd, bp->buf, (size_t)count)) != count) { - wrerr = YES; - wrerrno = j >= 0 ? EIO : errno; - } - if (ftruncate(ofd, size)) { - run_err("%s: truncate: %s", np, strerror(errno)); - wrerr = DISPLAYED; - } - if (pflag) { - if (exists || omode != mode) - if (fchmod(ofd, omode)) - run_err("%s: set mode: %s", - np, strerror(errno)); - } else { - if (!exists && omode != mode) - if (fchmod(ofd, omode & ~mask)) - run_err("%s: set mode: %s", - np, strerror(errno)); - } - close(ofd); - response(); - if (setimes && wrerr == NO) { - setimes = 0; - if (utimes(np, tv) < 0) { - run_err("%s: set times: %s", - np, strerror(errno)); - wrerr = DISPLAYED; - } - } - switch(wrerr) { - case YES: - run_err("%s: %s", np, strerror(wrerrno)); - break; - case NO: - write(remout, "", 1); - break; - case DISPLAYED: - break; - } - } -screwup: - run_err("protocol error: %s", why); - exit(1); -} - -int -response(void) -{ - char ch, *cp, resp, rbuf[BUFSIZ]; - - if (read(remin, &resp, sizeof(resp)) != sizeof(resp)) - lostconn(0); - - cp = rbuf; - switch(resp) { - case 0: /* ok */ - return (0); - default: - *cp++ = resp; - /* FALLTHROUGH */ - case 1: /* error, followed by error msg */ - case 2: /* fatal error, "" */ - do { - if (read(remin, &ch, sizeof(ch)) != sizeof(ch)) - lostconn(0); - *cp++ = ch; - } while (cp < &rbuf[BUFSIZ] && ch != '\n'); - - if (!iamremote) - write(STDERR_FILENO, rbuf, cp - rbuf); - ++errs; - if (resp == 1) - return (-1); - exit(1); - } - /* NOTREACHED */ -} - -#include - -void -run_err(const char *fmt, ...) -{ - static FILE *fp; - va_list ap; - - ++errs; - if (fp == NULL && !(fp = fdopen(remout, "w"))) - return; - va_start(ap, fmt); - fprintf(fp, "%c", 0x01); - fprintf(fp, "rcp: "); - vfprintf(fp, fmt, ap); - fprintf(fp, "\n"); - fflush(fp); - va_end(ap); - - if (!iamremote) { - va_start(ap, fmt); - vwarnx(fmt, ap); - va_end(ap); - } -} - -/* - * This function executes the given command as the specified user on the - * given host. This returns < 0 if execution fails, and >= 0 otherwise. This - * assigns the input and output file descriptors on success. - * - * If it cannot create necessary pipes it exits with error message. - */ - -int -do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout) -{ - int pin[2], pout[2], reserved[2]; - - /* - * Reserve two descriptors so that the real pipes won't get - * descriptors 0 and 1 because that will screw up dup2 below. - */ - pipe(reserved); - - /* Create a socket pair for communicating with rsh. */ - if (pipe(pin) < 0) { - perror("pipe"); - exit(255); - } - if (pipe(pout) < 0) { - perror("pipe"); - exit(255); - } - - /* Free the reserved descriptors. */ - close(reserved[0]); - close(reserved[1]); - - /* For a child to execute the command on the remote host using rsh. */ - if (fork() == 0) { - char *args[100]; - unsigned int i; - - /* Child. */ - close(pin[1]); - close(pout[0]); - dup2(pin[0], 0); - dup2(pout[1], 1); - close(pin[0]); - close(pout[1]); - - i = 0; - args[i++] = RSH_PROGRAM; - if (usekrb4) - args[i++] = "-4"; - if (usekrb5) - args[i++] = "-5"; - if (usebroken) - args[i++] = "-K"; - if (doencrypt) - args[i++] = "-x"; - if (forwardtkt) - args[i++] = "-F"; - if (noencrypt) - args[i++] = "-z"; - if (port != NULL) { - args[i++] = "-p"; - args[i++] = port; - } - if (eflag) - args[i++] = "-e"; - if (remuser != NULL) { - args[i++] = "-l"; - args[i++] = remuser; - } - args[i++] = host; - args[i++] = cmd; - args[i++] = NULL; - - execvp(RSH_PROGRAM, args); - perror(RSH_PROGRAM); - exit(1); - } - /* Parent. Close the other side, and return the local side. */ - close(pin[0]); - *fdout = pin[1]; - close(pout[1]); - *fdin = pout[0]; - return 0; -} diff --git a/appl/rcp/util.c b/appl/rcp/util.c deleted file mode 100644 index 890d3b5f3..000000000 --- a/appl/rcp/util.c +++ /dev/null @@ -1,184 +0,0 @@ -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if 0 -#ifndef lint -#if 0 -static char sccsid[] = "@(#)util.c 8.2 (Berkeley) 4/2/94"; -#endif -static const char rcsid[] = - "$FreeBSD: src/bin/rcp/util.c,v 1.9 1999/08/27 23:14:58 peter Exp $"; -#endif /* not lint */ -#endif - -#include "rcp_locl.h" - -RCSID("$Id$"); - -char * -colon(cp) - char *cp; -{ - if (*cp == ':') /* Leading colon is part of file name. */ - return (0); - - for (; *cp; ++cp) { - if (*cp == ':') - return (cp); - if (*cp == '/') - return (0); - } - return (0); -} - -char * -unbracket(char *cp) -{ - char *ep; - - if (*cp == '[') { - ep = cp + (strlen(cp) - 1); - if (*ep == ']') { - *ep = '\0'; - ++cp; - } - } - return (cp); -} - -void -verifydir(cp) - char *cp; -{ - struct stat stb; - - if (!stat(cp, &stb)) { - if (S_ISDIR(stb.st_mode)) - return; - errno = ENOTDIR; - } - run_err("%s: %s", cp, strerror(errno)); - exit(1); -} - -int -okname(cp0) - char *cp0; -{ - int c; - unsigned char *cp; - - cp = (unsigned char *)cp0; - do { - c = *cp; - if (c & 0200) - goto bad; - if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') - goto bad; - } while (*++cp); - return (1); - -bad: warnx("%s: invalid user name", cp0); - return (0); -} - -int -susystem(s) - char *s; -{ - void (*istat)(int), (*qstat)(int); - int status; - pid_t pid; - - pid = fork(); - switch (pid) { - case -1: - return (127); - - case 0: - execl(_PATH_BSHELL, "sh", "-c", s, NULL); - _exit(127); - } - istat = signal(SIGINT, SIG_IGN); - qstat = signal(SIGQUIT, SIG_IGN); - if (waitpid(pid, &status, 0) < 0) - status = -1; - (void)signal(SIGINT, istat); - (void)signal(SIGQUIT, qstat); - return (status); -} - -#ifndef roundup -#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) -#endif - -BUF * -allocbuf(bp, fd, blksize) - BUF *bp; - int fd, blksize; -{ - struct stat stb; - size_t size; - char *p; - - if (fstat(fd, &stb) < 0) { - run_err("fstat: %s", strerror(errno)); - return (0); - } - size = roundup(stb.st_blksize, blksize); - if (size == 0) - size = blksize; - if (bp->cnt >= size) - return (bp); - if ((p = realloc(bp->buf, size)) == NULL) { - if (bp->buf) - free(bp->buf); - bp->buf = NULL; - bp->cnt = 0; - run_err("%s", strerror(errno)); - return (0); - } - memset(p, 0, size); - bp->buf = p; - bp->cnt = size; - return (bp); -} - -void -lostconn(signo) - int signo; -{ - if (!iamremote) - warnx("lost connection"); - exit(1); -} diff --git a/appl/rsh/ChangeLog b/appl/rsh/ChangeLog deleted file mode 100644 index 18202873f..000000000 --- a/appl/rsh/ChangeLog +++ /dev/null @@ -1,549 +0,0 @@ -2007-07-12 Love Hörnquist Åstrand - - * rsh.c: Fix pointer vs strict alias rules. - - * rshd.c: Fix pointer vs strict alias rules. - -2007-01-04 Love Hörnquist Åstrand - - * rshd.c: Declare iruserok if needed, based on bug report from - David Love. - -2006-11-14 Love Hörnquist Åstrand - - * rsh_locl.h: Forward decl. - -2006-10-14 Love Hörnquist Åstrand - - * rsh_locl.h: Include "crypto-headers.h". - -2006-10-07 Love Hörnquist Åstrand - - * Makefile.am: Add man_MANS to EXTRA_DIST - -2006-04-27 Love Hörnquist Åstrand - - * Makefile.am: rshd_SOURCES += add limits_conf.c - - * rsh_locl.h: Include "loginpaths.h" - - * rshd.c: Read limits from limits.confon non-root login, patch - from Daniel Ahlin - -2006-02-27 Johan Danielsson - - * rshd.8: grammar (from Thomas Klausner) - -2006-01-31 Johan Danielsson - - * rshd.c (krb5_start_session): syslog failures to store cred cache - -2005-12-21 Love Hörnquist Åstrand - - * rshd.c (doit): move creation of users ticket file to later to - avoid seteuid/setuid dance. this breaks DCE, so remove support for - it completely. - -2005-10-22 Love Hörnquist Åstrand - - * rshd.c: Check return value from asprintf instead of string != - NULL since it undefined behavior on Linux. From Björn Sandell - - * rsh.c: Check return value from asprintf instead of string != - NULL since it undefined behavior on Linux. From Björn Sandell - -2005-06-08 Love Hörnquist Åstrand - - * rshd.c: init some important variables and check that they are - set checking authentication, all to please gcc - -2005-05-27 Love Hörnquist Åstrand - - * rshd.c: case uid_t to unsigned long in printf format - -2005-04-27 Love Hörnquist Åstrand - - * rsh_locl.h: Use larger buffer for recving data to be compatible - with older versions of heimdal (0.4 branch specificly) - - * rshd.c: Use larger buffer for recving data to be compatible with - older versions of heimdal (0.4 branch specificly) - -2005-04-25 Love Hörnquist Åstrand - - * rshd.c: use snprintf to format tkfile - -2005-04-24 Love Hörnquist Åstrand - - * rsh.c: use strlcat - - * rsh.c: use strlcpy - - * rsh_locl.h: forward declaration for private structures - -2005-04-20 Love Hörnquist Åstrand - - * rsh.c: cast size_t to unsigned long - -2004-09-21 Johan Danielsson - - * rshd.c: rename loop to rshd_loop - - * rshd.c: pass errsock status to init_ivecs - - * rsh.c: rename loop() to rsh_loop() - - * rsh.c (loop): pass errsock status to init_ivecs - - * common.c (init_ivecs): if we don't have an errsock the ivecs - should point to the same data - - * rshd.c: if we don't have an errsock, dup stdout to stderr (this - would normally be done by inetd, but not by mini_inetd). - - * rshd.c: move keepalive setting to after setting up sockets - -2004-02-20 Johan Danielsson - - * rsh.1: reorder and document some options - - * rsh_locl.h: include kafs.h if krb4 || krb5 - - * rsh.c: reorder some options - -2003-09-04 Johan Danielsson - - * rsh.1: document -d - -2003-08-19 Johan Danielsson - - * rshd.c: -P also with KRB5 - -2003-04-22 Love Hörnquist Åstrand - - * rsh.1: replace > with \*[Gt] - -2003-04-16 Johan Danielsson - - * rsh.c: use krb5_appdefault to get defaults for forward and - encrypt - - * rshd.c: use ARG_MAX + 1 - - * rshd.c (read_str): return allocated string - - * rsh_locl.h: set NCARGS to 8k if undefined - -2003-03-23 Assar Westerlund - - * rsh.c (loop): only check errsock if it's valid - -2003-03-18 Love Love Hörnquist Åstrand - - * rshd.c: do krb5_afslog when compling with afs support - - * rsh_locl.h: always include kafs.h - -2002-11-22 Johan Danielsson - - * rshd.8: clarify -x and kerberos 5 - -2002-11-01 Johan Danielsson - - * rsh_locl.h: bump COMMAND_SZ to NCARGS+1 - -2002-09-04 Johan Danielsson - - * rsh.c: free some memory - -2002-09-04 Assar Westerlund - - * common.c: krb5_crypto_block_size -> krb5_crypto_getblocksize - -2002-09-04 Johan Danielsson - - * rsh.1: document -P - -2002-09-03 Johan Danielsson - - * rsh.c: revert to protocol v1 if not asked for specific protocol - - * rshd.c: handle protocol version 2 - - * rsh.c: handle protocol version 2 - - * common.c: handle protocol version 2 - - * rsh_locl.h: handle protocol version 2 - -2002-02-18 Johan Danielsson - - * rshd.c: don't show options that doesn't apply - - * rsh.c: don't show options that doesn't apply - - * rsh_locl.h: if we're not building with any kerberos support, - just call read/write directly - - * common.c: if we're not building with any kerberos support, just - call read/write directly - - * rshd.c: make this build without krb5; also use the addrinfo - interface to mini_inetd, and set the keepalive option if requested - - * rsh.c: make this build without krb5 - - * rsh_locl.h: make this build without krb5 - - * common.c: make this build without krb5 - -2001-11-30 Johan Danielsson - - * rshd.c: make the syslog messages somewhat more informative - -2001-08-15 Johan Danielsson - - * rsh.c: only complain about encryption flag when old - authentication is requested - -2001-08-07 Johan Danielsson - - * rsh.c: don't try broken auth if rresvport failed; try to give - some more informative error messages - -2001-07-31 Johan Danielsson - - * rshd.8: add an EXAMPLE - * rshd.8: manual page - * rshd.c: add some compat flags - * rsh.1: manual page - * rsh.c: iff -d, set the SO_DEBUG flags of the stdout and stderr - socket; implement parsing user@host - -2001-07-19 Assar Westerlund - - * rshd.c (fatal): use vsnprintf correctly - -2001-02-07 Assar Westerlund - - * Makefile.am: add login_access - * rshd.c (login_access): add prototype - (syslog_and_die, fatal): add printf attributes - (*): AIX -> _AIX - (doit): use login_access - based on patches from Ake Sandgren - -2001-01-09 Assar Westerlund - - * rshd.c (save_krb5_creds): use krb5_rd_cred2 instead of - krb5_rd_cred - -2000-12-31 Assar Westerlund - - * rshd.c (main): handle krb5_init_context failure consistently - * rsh.c (main): handle krb5_init_context failure consistently - -2000-12-05 Johan Danielsson - - * rshd.c: require encryption if passed -x - -2000-11-15 Assar Westerlund - - * rshd.c (loop): check that the fd's aren't too large to select on - * rsh.c (loop, proto): check that the fd's aren't too large to - select on - -2000-08-10 Assar Westerlund - - * rsh.c: move code to do config/command parsing correctly. - -2000-08-09 Assar Westerlund - - * rsh.c (main): only fetch stuff from krb5.conf when no option has - been given - -2000-08-01 Assar Westerlund - - * rsh.c (doit): loop until we create an error socket of an - supported socket family - -2000-07-02 Assar Westerlund - - * rshd.c: DCE stuff from Ake Sandgren - do not call syslog with a variable as format string - - * rsh_locl.h (_PATH_ETC_ENVIRONMENT): add - -2000-06-09 Assar Westerlund - - * rsh.c (main): work-around for setuid and capabilities bug fixed - in Linux 2.2.16 - -2000-06-06 Johan Danielsson - - * rsh.c: nuke long option from -z - - * rsh.c: don't try to encrypt if auth is broken (Daniel Kouril) - -2000-06-03 Assar Westerlund - - * rshd.c (doit): check return value of getspnam. From - - -2000-05-23 Assar Westerlund - - * rsh.c (proto): select on the normal socket when waiting for the - daemon to connect back to the stderr port, so that we discover - when data arrives there before. when that happens, we assume that - the daemon did not manage to connect (because of NAT/whatever) and - continue as if `-e' was given - * rshd.c (doit): if we fail to connect back to the stderr port, - act as if `-e' was given on the client side, i.e. without the - special TCP-connection. This tries to make things better when - running the head against a NAT wall, for example. - -2000-02-07 Assar Westerlund - - * Makefile.am (LDADD): make sure we use the heimdal libdes - -2000-02-06 Assar Westerlund - - * *: conditionalize des stuff on KRB4 - -1999-12-16 Assar Westerlund - - * rsh.c (doit): addrinfo returned from getaddrinfo() is not usable - directly as hints. copy it and set AI_PASSIVE. - -1999-11-20 Assar Westerlund - - * rsh.c (main): remember to close the priviledged sockets before - calling rlogin - -1999-11-02 Assar Westerlund - - * rsh.c (main): redo the v4/v5 selection for consistency. -4 -> - try only v4 -5 -> try only v5 none, -45 -> try v5, v4 - -1999-10-26 Assar Westerlund - - * rshd.c (main): ignore SIGPIPE - - * common.c (do_read): the encoded length can be longer than the - buffer being used, allocate memory for it dynamically. From Brian - A May - -1999-10-14 Assar Westerlund - - * rsh.c (proto): be more careful and don't print errno when read() - returns 0 - -1999-09-20 Assar Westerlund - - * rshd.c (recv_krb4_auth): set `iv' - -1999-08-16 Assar Westerlund - - * common.c (do_read): be careful with the return value from - krb5_net_read - -1999-08-05 Assar Westerlund - - * rsh.c: call freehostent - - * rsh.c: remove some dead code - -1999-08-04 Assar Westerlund - - * rshd.c: re-write the handling of forwarded credentials and - stuff. From Miroslav Ruda - - * rsh_locl.h: always include kafs.h - - * rsh.c: add `-z' and `-G' options - - * rsh.c (loop): shutdown one side of the TCP connection on EOF. - From Brian A May - - * common.c (do_read): handle EOF. From Brian A May - - -1999-08-01 Assar Westerlund - - * rsh.c: const fixes - -1999-07-29 Assar Westerlund - - * rshd.c: v6-ify - - * rsh.c: v6-ify - -1999-07-28 Assar Westerlund - - * rsh_locl.h: move around kafs.h - -1999-07-24 Assar Westerlund - - * rsh_locl.h: - - * rsh.c, rshd.c: improve forwarding and implement unique ccache on - server. From Miroslav Ruda - -1999-07-03 Assar Westerlund - - * rsh.c (construct_command): handle argc == 0 for generality - -1999-06-23 Assar Westerlund - - * rsh.c: new option `-e' for not trying to open an stderr socket - -1999-06-17 Assar Westerlund - - * rsh_locl.h (RSH_BUFSIZ): bump to 16 * 1024 to be sure that we - don't leave any data inside des_enc_read. (that constant should - really be exported in some way...) - -1999-06-15 Assar Westerlund - - * rsh.c: use get_default_username and resulting const pollution - -1999-05-21 Assar Westerlund - - * rsh.c (main): try $USERNAME - -1999-05-14 Assar Westerlund - - * rshd.c (doit): afslog correctly - -1999-05-11 Assar Westerlund - - * rsh.c (main): add fallback to rlogin - -1999-05-10 Assar Westerlund - - * rsh.c (send_krb5_auth): call krb5_sendauth with ccache == NULL. - check return value from krb5_crypto_init - - * common.c (do_write, do_read): always return -1 for failure - (net_write, net_read): remove. they already exist in libroken - -1999-05-09 Assar Westerlund - - * rsh.c: make sure it tries with all other authentication methods - after one has failed - * rsh.c (main): detect the case of no command given. - -1999-04-11 Assar Westerlund - - * rsh.c: new option --forwardable. use print_version - -Sat Apr 10 17:10:55 1999 Assar Westerlund - - * rshd.c (setup_copier): use `socketpair' instead of `pipe'. Some - shells don't think it's a rsh session if they find a pipe at the - other end. - (setup_environment): add SSH_CLIENT just to make bash happy - - * common.c (do_read): use krb5_get_wrapped_length - -Wed Mar 24 03:59:42 1999 Assar Westerlund - - * rsh.c (loop): more braces to make gcc happy - -Tue Mar 23 17:08:32 1999 Johan Danielsson - - * rsh_locl.h: kafs.h - - * rshd.c: add `-P', `-v', and `-L' flags - -Thu Mar 18 11:37:24 1999 Johan Danielsson - - * Makefile.am: include Makefile.am.common - -Tue Dec 1 14:44:44 1998 Johan Danielsson - - * appl/rsh/rshd.c: update to new crypto framework - - * appl/rsh/rsh_locl.h: update to new crypto framework - - * appl/rsh/rsh.c: update to new crypto framework - - * appl/rsh/common.c: update to new crypto framework - -Mon Nov 2 01:15:06 1998 Assar Westerlund - - * appl/rsh/rsh.c (main): initialize host - - * appl/rsh/rshd.c (recv_krb5_auth): disable `do_encrypt' if not - encrypting. - -Thu Jul 30 23:12:17 1998 Assar Westerlund - - * appl/rsh/rsh.c: kludges for parsing `rsh hostname -l user' - -Thu Jul 23 19:49:03 1998 Johan Danielsson - - * appl/rsh/rshd.c: use krb5_verify_authenticator_checksum - -Sat Apr 18 21:13:06 1998 Johan Danielsson - - * appl/rsh/rsh.c: Don't try v5 if (only) `-4' is specified. - -Sun Dec 21 09:44:05 1997 Assar Westerlund - - * appl/rsh/rshd.c (recv_krb5_auth): swap the order of the - `local_user' and the `remote_user' - - * appl/rsh/rsh.c (send_krb5_auth): swap the order of the - `local_user' and the `remote_user' - -Sat Nov 29 07:10:11 1997 Assar Westerlund - - * appl/rsh/rshd.c: updated to use getarg. - changed `struct fd_set' to `fd_set'. - implemented broken/BSD authentication (requires iruserok) - -Wed Nov 12 02:35:57 1997 Assar Westerlund - - * appl/rsh/rsh_locl.h: add AUTH_BROKEN and PATH_RSH - - * appl/rsh/Makefile.am: set BINDIR - - * appl/rsh/rsh.c: implemented BSD-style reserved port - `authentication' - -Sun Aug 24 08:06:54 1997 Assar Westerlund - - * appl/rsh/rshd.c: syslog remote shells - -Tue Aug 12 01:29:46 1997 Assar Westerlund - - * appl/rshd/rshd.c: Use `krb5_sock_to_principal'. Send server - parameter to krb5_rd_req/krb5_recvauth. Set addresses in - auth_context. - -Fri Jul 25 17:32:12 1997 Assar Westerlund - - * appl/rsh/rshd.c: implement forwarding - - * appl/rsh/rsh.c: Use getarg. Implement forwarding. - -Sun Jul 13 00:32:16 1997 Assar Westerlund - - * appl/rsh: Conditionalize the krb4-support. - -Wed Jul 9 06:58:00 1997 Assar Westerlund - - * appl/rsh/rsh.c: use the correct user for the checksum - -Mon Jul 7 11:15:51 1997 Assar Westerlund - - * appl/rsh/rshd.c: Now works. Also implementd encryption and - `-p'. - - * appl/rsh/common.c: new file - -Mon Jun 30 06:08:14 1997 Assar Westerlund - - * appl/rsh: New program. - diff --git a/appl/rsh/Makefile.am b/appl/rsh/Makefile.am deleted file mode 100644 index 9d0c4117d..000000000 --- a/appl/rsh/Makefile.am +++ /dev/null @@ -1,28 +0,0 @@ -# $Id$ - -include $(top_srcdir)/Makefile.am.common - -AM_CPPFLAGS += -I$(srcdir)/../login - -bin_PROGRAMS = rsh - -man_MANS = rsh.1 rshd.8 - -libexec_PROGRAMS = rshd - -rsh_SOURCES = rsh.c common.c rsh_locl.h - -rshd_SOURCES = rshd.c common.c login_access.c limits_conf.c rsh_locl.h - -login_access.c: - $(LN_S) $(srcdir)/../login/login_access.c . - -limits_conf.c: - $(LN_S) $(srcdir)/../login/limits_conf.c . - -LDADD = $(LIB_kafs) \ - $(LIB_krb5) \ - $(LIB_hcrypto) \ - $(LIB_roken) - -EXTRA_DIST = $(man_MANS) diff --git a/appl/rsh/common.c b/appl/rsh/common.c deleted file mode 100644 index dd605a516..000000000 --- a/appl/rsh/common.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 1997-2004 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "rsh_locl.h" -RCSID("$Id$"); - -#if defined(KRB5) - -#ifdef KRB5 -int key_usage = 1026; - -void *ivec_in[2]; -void *ivec_out[2]; - -void -init_ivecs(int client, int have_errsock) -{ - size_t blocksize; - - krb5_crypto_getblocksize(context, crypto, &blocksize); - - ivec_in[0] = malloc(blocksize); - memset(ivec_in[0], client, blocksize); - - if(have_errsock) { - ivec_in[1] = malloc(blocksize); - memset(ivec_in[1], 2 | client, blocksize); - } else - ivec_in[1] = ivec_in[0]; - - ivec_out[0] = malloc(blocksize); - memset(ivec_out[0], !client, blocksize); - - if(have_errsock) { - ivec_out[1] = malloc(blocksize); - memset(ivec_out[1], 2 | !client, blocksize); - } else - ivec_out[1] = ivec_out[0]; -} -#endif - - -ssize_t -do_read (int fd, void *buf, size_t sz, void *ivec) -{ - if (do_encrypt) { -#ifdef KRB5 - if(auth_method == AUTH_KRB5) { - krb5_error_code ret; - uint32_t len, outer_len; - int status; - krb5_data data; - void *edata; - - ret = krb5_net_read (context, &fd, &len, 4); - if (ret <= 0) - return ret; - len = ntohl(len); - if (len > sz) - abort (); - /* ivec will be non null for protocol version 2 */ - if(ivec != NULL) - outer_len = krb5_get_wrapped_length (context, crypto, len + 4); - else - outer_len = krb5_get_wrapped_length (context, crypto, len); - edata = malloc (outer_len); - if (edata == NULL) - errx (1, "malloc: cannot allocate %u bytes", outer_len); - ret = krb5_net_read (context, &fd, edata, outer_len); - if (ret <= 0) { - free(edata); - return ret; - } - - status = krb5_decrypt_ivec(context, crypto, key_usage, - edata, outer_len, &data, ivec); - free (edata); - - if (status) - krb5_err (context, 1, status, "decrypting data"); - if(ivec != NULL) { - unsigned long l; - if(data.length < len + 4) - errx (1, "data received is too short"); - _krb5_get_int(data.data, &l, 4); - if(l != len) - errx (1, "inconsistency in received data"); - memcpy (buf, (unsigned char *)data.data+4, len); - } else - memcpy (buf, data.data, len); - krb5_data_free (&data); - return len; - } else -#endif /* KRB5 */ - abort (); - } else - return read (fd, buf, sz); -} - -ssize_t -do_write (int fd, void *buf, size_t sz, void *ivec) -{ - if (do_encrypt) { -#ifdef KRB5 - if(auth_method == AUTH_KRB5) { - krb5_error_code status; - krb5_data data; - unsigned char len[4]; - int ret; - - _krb5_put_int(len, sz, 4); - if(ivec != NULL) { - unsigned char *tmp = malloc(sz + 4); - if(tmp == NULL) - err(1, "malloc"); - _krb5_put_int(tmp, sz, 4); - memcpy(tmp + 4, buf, sz); - status = krb5_encrypt_ivec(context, crypto, key_usage, - tmp, sz + 4, &data, ivec); - free(tmp); - } else - status = krb5_encrypt_ivec(context, crypto, key_usage, - buf, sz, &data, ivec); - - if (status) - krb5_err(context, 1, status, "encrypting data"); - - ret = krb5_net_write (context, &fd, len, 4); - if (ret != 4) - return ret; - ret = krb5_net_write (context, &fd, data.data, data.length); - if (ret != data.length) - return ret; - free (data.data); - return sz; - } else -#endif /* KRB5 */ - abort(); - } else - return write (fd, buf, sz); -} -#endif /* KRB5 */ diff --git a/appl/rsh/rsh.1 b/appl/rsh/rsh.1 deleted file mode 100644 index b5e96637e..000000000 --- a/appl/rsh/rsh.1 +++ /dev/null @@ -1,295 +0,0 @@ -.\" Copyright (c) 2002 - 2003 Kungliga Tekniska Högskolan -.\" (Royal Institute of Technology, Stockholm, Sweden). -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" 3. Neither the name of the Institute nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" $Id$ -.\" -.Dd February 20, 2004 -.Dt RSH 1 -.Os HEIMDAL -.Sh NAME -.Nm rsh -.Nd -remote shell -.Sh SYNOPSIS -.Nm -.Op Fl 45FGKdefnuxz -.Op Fl U Pa string -.Op Fl p Ar port -.Op Fl l Ar username -.Op Fl P Ar N|O -.Ar host [command] -.Sh DESCRIPTION -.Nm -authenticates to the -.Xr rshd 8 -daemon on the remote -.Ar host , -and then executes the specified -.Ar command . -.Pp -.Nm -copies its standard input to the remote command, and the standard -output and error of the remote command to its own. -.Pp -Valid options are: -.Bl -tag -width Ds -.It Xo -.Fl 4 , -.Fl -krb4 -.Xc -The -.Fl 4 -option requests Kerberos 4 authentication. Normally all supported -authentication mechanisms will be tried, but in some cases more -explicit control is desired. -.It Xo -.Fl 5 , -.Fl -krb5 -.Xc -The -.Fl 5 -option requests Kerberos 5 authentication. This is analogous to the -.Fl 4 -option. -.It Xo -.Fl K , -.Fl -broken -.Xc -The -.Fl K -option turns off all Kerberos authentication. The security in this -mode relies on reserved ports. The long name is an indication of how -good this is. -.It Xo -.Fl n , -.Fl -no-input -.Xc -The -.Fl n -option directs the input from the -.Pa /dev/null -device (see the -.Sx BUGS -section of this manual page). -.It Fl d -Enable -.Xr setsockopt 2 -socket debugging. -.It Xo -.Fl e , -.Fl -no-stderr -.Xc -Don't use a separate socket for the stderr stream. This can be -necessary if rsh-ing through a NAT bridge. -.It Xo -.Fl x , -.Fl -encrypt -.Xc -The -.Fl x -option enables encryption for all data exchange. This is only valid -for Kerberos authenticated connections (see the -.Sx BUGS -section for limitations). -.It Xo -.Fl z -.Xc -The opposite of -.Fl x . -This is the default, and is mainly useful if encryption has been -enabled by default, for instance in the -.Li appdefaults -section of -.Pa /etc/krb5.conf -when using Kerberos 5. -.It Xo -.Fl f , -.Fl -forward -.Xc -Forward Kerberos 5 credentials to the remote host. -Also settable via -.Li appdefaults -(see -.Xr krb5.conf ) . -.It Xo -.Fl F , -.Fl -forwardable -.Xc -Make the forwarded credentials re-forwardable. -Also settable via -.Li appdefaults -(see -.Xr krb5.conf ) . -.It Xo -.Fl l Ar string , -.Fl -user= Ns Ar string -.Xc -By default the remote username is the same as the local. The -.Fl l -option or the -.Pa username@host -format allow the remote name to be specified. -.It Xo -.Fl n , -.Fl -no-input -.Xc -Direct input from -.Pa /dev/null -(see the -.Sx BUGS -section). -.It Xo -.Fl p Ar number-or-service , -.Fl -port= Ns Ar number-or-service -.Xc -Connect to this port instead of the default (which is 514 when using -old port based authentication, 544 for Kerberos 5 and non-encrypted -Kerberos 4, and 545 for encrytpted Kerberos 4; subject of course to -the contents of -.Pa /etc/services ) . -.It Xo -.Fl P Ar N|O|1|2 , -.Fl -protocol= Ns Ar N|O|1|2 -.Xc -Specifies the protocol version to use with Kerberos 5. -.Ar N -and -.Ar 2 -select protocol version 2, while -.Ar O -and -.Ar 1 -select version 1. Version 2 is believed to be more secure, and is the -default. Unless asked for a specific version, -.Nm -will try both. This behaviour may change in the future. -.It Xo -.Fl u , -.Fl -unique -.Xc -Make sure the remote credentials cache is unique, that is, don't reuse -any existing cache. Mutually exclusive to -.Fl U . -.It Xo -.Fl U Pa string , -.Fl -tkfile= Ns Pa string -.Xc -Name of the remote credentials cache. Mutually exclusive to -.Fl u . -.It Xo -.Fl x , -.Fl -encrypt -.Xc -The -.Fl x -option enables encryption for all data exchange. This is only valid -for Kerberos authenticated connections (see the -.Sx BUGS -section for limitations). -.It Fl z -The opposite of -.Fl x . -This is the default, but encryption can be enabled when using -Kerberos 5, by setting the -.Li libdefaults/encrypt -option in -.Xr krb5.conf 5 . -.El -.\".Pp -.\"Without a -.\".Ar command -.\".Nm -.\"will just exec -.\".Xr rlogin 1 -.\"with the same arguments. -.Sh EXAMPLES -Care should be taken when issuing commands containing shell meta -characters. Without quoting, these will be expanded on the local -machine. -.Pp -The following command: -.Pp -.Dl rsh otherhost cat remotefile \*[Gt] localfile -.Pp -will write the contents of the remote -.Pa remotefile -to the local -.Pa localfile , -but: -.Pp -.Dl rsh otherhost 'cat remotefile \*[Gt] remotefile2' -.Pp -will write it to the remote -.Pa remotefile2 . -.\".Sh ENVIRONMENT -.Sh FILES -.Bl -tag -width /etc/hosts -compact -.It Pa /etc/hosts -.El -.\".Sh DIAGNOSTICS -.Sh SEE ALSO -.Xr rlogin 1 , -.Xr krb_realmofhost 3 , -.Xr krb_sendauth 3 , -.Xr hosts.equiv 5 , -.Xr krb5.conf 5 , -.Xr rhosts 5 , -.Xr kerberos 8 -.Xr rshd 8 -.\".Sh STANDARDS -.Sh HISTORY -The -.Nm -command appeared in -.Bx 4.2 . -.Sh AUTHORS -This implementation of -.Nm -was written as part of the Heimdal Kerberos 5 implementation. -.Sh BUGS -Some shells (notably -.Xr csh 1 ) -will cause -.Nm -to block if run in the background, unless the standard input is directed away from the terminal. This is what the -.Fl n -option is for. -.Pp -The -.Fl x -options enables encryption for the session, but for both Kerberos 4 -and 5 the actual command is sent unencrypted, so you should not send -any secret information in the command line (which is probably a bad -idea anyway, since the command line can usually be read with tools -like -.Xr ps 1 ) . -Forthermore in Kerberos 4 the command is not even integrity -protected, so anyone with the right tools can modify the command. diff --git a/appl/rsh/rsh.c b/appl/rsh/rsh.c deleted file mode 100644 index f1e2ca32e..000000000 --- a/appl/rsh/rsh.c +++ /dev/null @@ -1,1033 +0,0 @@ -/* - * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "rsh_locl.h" -RCSID("$Id$"); - -enum auth_method auth_method; -#if defined(KRB5) -int do_encrypt = -1; -#endif -#ifdef KRB5 -int do_unique_tkfile = 0; -char *unique_tkfile = NULL; -char tkfile[MAXPATHLEN]; -int do_forward = -1; -int do_forwardable = -1; -krb5_context context; -krb5_keyblock *keyblock; -krb5_crypto crypto; -#endif -int sock_debug = 0; - -#ifdef KRB5 -static int use_v5 = -1; -#endif -#if defined(KRB5) -static int use_only_broken = 0; -#else -static int use_only_broken = 1; -#endif -static int use_broken = 1; -static char *port_str; -static const char *user; -static int do_version; -static int do_help; -static int do_errsock = 1; -#ifdef KRB5 -static char *protocol_version_str; -static int protocol_version = 2; -#endif - -/* - * - */ - -static int input = 1; /* Read from stdin */ - -static int -rsh_loop (int s, int errsock) -{ - fd_set real_readset; - int count = 1; - -#ifdef KRB5 - if(auth_method == AUTH_KRB5 && protocol_version == 2) - init_ivecs(1, errsock != -1); -#endif - - if (s >= FD_SETSIZE || (errsock != -1 && errsock >= FD_SETSIZE)) - errx (1, "fd too large"); - - FD_ZERO(&real_readset); - FD_SET(s, &real_readset); - if (errsock != -1) { - FD_SET(errsock, &real_readset); - ++count; - } - if(input) - FD_SET(STDIN_FILENO, &real_readset); - - for (;;) { - int ret; - fd_set readset; - char buf[RSH_BUFSIZ]; - - readset = real_readset; - ret = select (max(s, errsock) + 1, &readset, NULL, NULL, NULL); - if (ret < 0) { - if (errno == EINTR) - continue; - else - err (1, "select"); - } - if (FD_ISSET(s, &readset)) { - ret = do_read (s, buf, sizeof(buf), ivec_in[0]); - if (ret < 0) - err (1, "read"); - else if (ret == 0) { - close (s); - FD_CLR(s, &real_readset); - if (--count == 0) - return 0; - } else - net_write (STDOUT_FILENO, buf, ret); - } - if (errsock != -1 && FD_ISSET(errsock, &readset)) { - ret = do_read (errsock, buf, sizeof(buf), ivec_in[1]); - if (ret < 0) - err (1, "read"); - else if (ret == 0) { - close (errsock); - FD_CLR(errsock, &real_readset); - if (--count == 0) - return 0; - } else - net_write (STDERR_FILENO, buf, ret); - } - if (FD_ISSET(STDIN_FILENO, &readset)) { - ret = read (STDIN_FILENO, buf, sizeof(buf)); - if (ret < 0) - err (1, "read"); - else if (ret == 0) { - close (STDIN_FILENO); - FD_CLR(STDIN_FILENO, &real_readset); - shutdown (s, SHUT_WR); - } else - do_write (s, buf, ret, ivec_out[0]); - } - } -} - -#ifdef KRB5 -/* - * Send forward information on `s' for host `hostname', them being - * forwardable themselves if `forwardable' - */ - -static int -krb5_forward_cred (krb5_auth_context auth_context, - int s, - const char *hostname, - int forwardable) -{ - krb5_error_code ret; - krb5_ccache ccache; - krb5_creds creds; - krb5_kdc_flags flags; - krb5_data out_data; - krb5_principal principal; - - memset (&creds, 0, sizeof(creds)); - - ret = krb5_cc_default (context, &ccache); - if (ret) { - warnx ("could not forward creds: krb5_cc_default: %s", - krb5_get_err_text (context, ret)); - return 1; - } - - ret = krb5_cc_get_principal (context, ccache, &principal); - if (ret) { - warnx ("could not forward creds: krb5_cc_get_principal: %s", - krb5_get_err_text (context, ret)); - return 1; - } - - creds.client = principal; - - ret = krb5_build_principal (context, - &creds.server, - strlen(principal->realm), - principal->realm, - "krbtgt", - principal->realm, - NULL); - - if (ret) { - warnx ("could not forward creds: krb5_build_principal: %s", - krb5_get_err_text (context, ret)); - return 1; - } - - creds.times.endtime = 0; - - flags.i = 0; - flags.b.forwarded = 1; - flags.b.forwardable = forwardable; - - ret = krb5_get_forwarded_creds (context, - auth_context, - ccache, - flags.i, - hostname, - &creds, - &out_data); - if (ret) { - warnx ("could not forward creds: krb5_get_forwarded_creds: %s", - krb5_get_err_text (context, ret)); - return 1; - } - - ret = krb5_write_message (context, - (void *)&s, - &out_data); - krb5_data_free (&out_data); - - if (ret) - warnx ("could not forward creds: krb5_write_message: %s", - krb5_get_err_text (context, ret)); - return 0; -} - -static int sendauth_version_error; - -static int -send_krb5_auth(int s, - struct sockaddr *thisaddr, - struct sockaddr *thataddr, - const char *hostname, - const char *remote_user, - const char *local_user, - size_t cmd_len, - const char *cmd) -{ - krb5_principal server; - krb5_data cksum_data; - int status; - size_t len; - krb5_auth_context auth_context = NULL; - const char *protocol_string = NULL; - krb5_flags ap_opts; - char *str; - - status = krb5_sname_to_principal(context, - hostname, - "host", - KRB5_NT_SRV_HST, - &server); - if (status) { - warnx ("%s: %s", hostname, krb5_get_err_text(context, status)); - return 1; - } - - if(do_encrypt == -1) { - krb5_appdefault_boolean(context, NULL, - krb5_principal_get_realm(context, server), - "encrypt", - FALSE, - &do_encrypt); - } - - cksum_data.length = asprintf (&str, - "%u:%s%s%s", - ntohs(socket_get_port(thataddr)), - do_encrypt ? "-x " : "", - cmd, - remote_user); - if (str == NULL) { - warnx ("%s: failed to allocate command", hostname); - return 1; - } - cksum_data.data = str; - - ap_opts = 0; - - if(do_encrypt) - ap_opts |= AP_OPTS_MUTUAL_REQUIRED; - - switch(protocol_version) { - case 2: - ap_opts |= AP_OPTS_USE_SUBKEY; - protocol_string = KCMD_NEW_VERSION; - break; - case 1: - protocol_string = KCMD_OLD_VERSION; - key_usage = KRB5_KU_OTHER_ENCRYPTED; - break; - default: - abort(); - } - - status = krb5_sendauth (context, - &auth_context, - &s, - protocol_string, - NULL, - server, - ap_opts, - &cksum_data, - NULL, - NULL, - NULL, - NULL, - NULL); - - /* do this while we have a principal */ - if(do_forward == -1 || do_forwardable == -1) { - krb5_const_realm realm = krb5_principal_get_realm(context, server); - if (do_forwardable == -1) - krb5_appdefault_boolean(context, NULL, realm, - "forwardable", FALSE, - &do_forwardable); - if (do_forward == -1) - krb5_appdefault_boolean(context, NULL, realm, - "forward", FALSE, - &do_forward); - } - - krb5_free_principal(context, server); - krb5_data_free(&cksum_data); - - if (status) { - if(status == KRB5_SENDAUTH_REJECTED && - protocol_version == 2 && protocol_version_str == NULL) - sendauth_version_error = 1; - else - krb5_warn(context, status, "%s", hostname); - return 1; - } - - status = krb5_auth_con_getlocalsubkey (context, auth_context, &keyblock); - if(keyblock == NULL) - status = krb5_auth_con_getkey (context, auth_context, &keyblock); - if (status) { - warnx ("krb5_auth_con_getkey: %s", krb5_get_err_text(context, status)); - return 1; - } - - status = krb5_auth_con_setaddrs_from_fd (context, - auth_context, - &s); - if (status) { - warnx("krb5_auth_con_setaddrs_from_fd: %s", - krb5_get_err_text(context, status)); - return(1); - } - - status = krb5_crypto_init(context, keyblock, 0, &crypto); - if(status) { - warnx ("krb5_crypto_init: %s", krb5_get_err_text(context, status)); - return 1; - } - - len = strlen(remote_user) + 1; - if (net_write (s, remote_user, len) != len) { - warn ("write"); - return 1; - } - if (do_encrypt && net_write (s, "-x ", 3) != 3) { - warn ("write"); - return 1; - } - if (net_write (s, cmd, cmd_len) != cmd_len) { - warn ("write"); - return 1; - } - - if (do_unique_tkfile) { - if (net_write (s, tkfile, strlen(tkfile)) != strlen(tkfile)) { - warn ("write"); - return 1; - } - } - len = strlen(local_user) + 1; - if (net_write (s, local_user, len) != len) { - warn ("write"); - return 1; - } - - if (!do_forward - || krb5_forward_cred (auth_context, s, hostname, do_forwardable)) { - /* Empty forwarding info */ - - u_char zero[4] = {0, 0, 0, 0}; - write (s, &zero, 4); - } - krb5_auth_con_free (context, auth_context); - return 0; -} - -#endif /* KRB5 */ - -static int -send_broken_auth(int s, - struct sockaddr *thisaddr, - struct sockaddr *thataddr, - const char *hostname, - const char *remote_user, - const char *local_user, - size_t cmd_len, - const char *cmd) -{ - size_t len; - - len = strlen(local_user) + 1; - if (net_write (s, local_user, len) != len) { - warn ("write"); - return 1; - } - len = strlen(remote_user) + 1; - if (net_write (s, remote_user, len) != len) { - warn ("write"); - return 1; - } - if (net_write (s, cmd, cmd_len) != cmd_len) { - warn ("write"); - return 1; - } - return 0; -} - -static int -proto (int s, int errsock, - const char *hostname, const char *local_user, const char *remote_user, - const char *cmd, size_t cmd_len, - int (*auth_func)(int s, - struct sockaddr *this, struct sockaddr *that, - const char *hostname, const char *remote_user, - const char *local_user, size_t cmd_len, - const char *cmd)) -{ - int errsock2; - char buf[BUFSIZ]; - char *p; - size_t len; - char reply; - struct sockaddr_storage thisaddr_ss; - struct sockaddr *thisaddr = (struct sockaddr *)&thisaddr_ss; - struct sockaddr_storage thataddr_ss; - struct sockaddr *thataddr = (struct sockaddr *)&thataddr_ss; - struct sockaddr_storage erraddr_ss; - struct sockaddr *erraddr = (struct sockaddr *)&erraddr_ss; - socklen_t addrlen; - int ret; - - addrlen = sizeof(thisaddr_ss); - if (getsockname (s, thisaddr, &addrlen) < 0) { - warn ("getsockname(%s)", hostname); - return 1; - } - addrlen = sizeof(thataddr_ss); - if (getpeername (s, thataddr, &addrlen) < 0) { - warn ("getpeername(%s)", hostname); - return 1; - } - - if (errsock != -1) { - - addrlen = sizeof(erraddr_ss); - if (getsockname (errsock, erraddr, &addrlen) < 0) { - warn ("getsockname"); - return 1; - } - - if (listen (errsock, 1) < 0) { - warn ("listen"); - return 1; - } - - p = buf; - snprintf (p, sizeof(buf), "%u", - ntohs(socket_get_port(erraddr))); - len = strlen(buf) + 1; - if(net_write (s, buf, len) != len) { - warn ("write"); - close (errsock); - return 1; - } - - - for (;;) { - fd_set fdset; - - if (errsock >= FD_SETSIZE || s >= FD_SETSIZE) - errx (1, "fd too large"); - - FD_ZERO(&fdset); - FD_SET(errsock, &fdset); - FD_SET(s, &fdset); - - ret = select (max(errsock, s) + 1, &fdset, NULL, NULL, NULL); - if (ret < 0) { - if (errno == EINTR) - continue; - warn ("select"); - close (errsock); - return 1; - } - if (FD_ISSET(errsock, &fdset)) { - errsock2 = accept (errsock, NULL, NULL); - close (errsock); - if (errsock2 < 0) { - warn ("accept"); - return 1; - } - break; - } - - /* - * there should not arrive any data on this fd so if it's - * readable it probably indicates that the other side when - * away. - */ - - if (FD_ISSET(s, &fdset)) { - warnx ("socket closed"); - close (errsock); - errsock2 = -1; - break; - } - } - } else { - if (net_write (s, "0", 2) != 2) { - warn ("write"); - return 1; - } - errsock2 = -1; - } - - if ((*auth_func)(s, thisaddr, thataddr, hostname, - remote_user, local_user, - cmd_len, cmd)) { - close (errsock2); - return 1; - } - - ret = net_read (s, &reply, 1); - if (ret < 0) { - warn ("read"); - close (errsock2); - return 1; - } else if (ret == 0) { - warnx ("unexpected EOF from %s", hostname); - close (errsock2); - return 1; - } - if (reply != 0) { - - warnx ("Error from rshd at %s:", hostname); - - while ((ret = read (s, buf, sizeof(buf))) > 0) - write (STDOUT_FILENO, buf, ret); - write (STDOUT_FILENO,"\n",1); - close (errsock2); - return 1; - } - - if (sock_debug) { - int one = 1; - if (setsockopt(s, SOL_SOCKET, SO_DEBUG, (void *)&one, sizeof(one)) < 0) - warn("setsockopt remote"); - if (errsock2 != -1 && - setsockopt(errsock2, SOL_SOCKET, SO_DEBUG, - (void *)&one, sizeof(one)) < 0) - warn("setsockopt stderr"); - } - - return rsh_loop (s, errsock2); -} - -/* - * Return in `res' a copy of the concatenation of `argc, argv' into - * malloced space. */ - -static size_t -construct_command (char **res, int argc, char **argv) -{ - int i; - size_t len = 0; - char *tmp; - - for (i = 0; i < argc; ++i) - len += strlen(argv[i]) + 1; - len = max (1, len); - tmp = malloc (len); - if (tmp == NULL) - errx (1, "malloc %lu failed", (unsigned long)len); - - *tmp = '\0'; - for (i = 0; i < argc - 1; ++i) { - strlcat (tmp, argv[i], len); - strlcat (tmp, " ", len); - } - if (argc > 0) - strlcat (tmp, argv[argc-1], len); - *res = tmp; - return len; -} - -static char * -print_addr (const struct sockaddr *sa) -{ - char addr_str[256]; - char *res; - const char *as = NULL; - - if(sa->sa_family == AF_INET) - as = inet_ntop (sa->sa_family, &((struct sockaddr_in*)sa)->sin_addr, - addr_str, sizeof(addr_str)); -#ifdef HAVE_INET6 - else if(sa->sa_family == AF_INET6) - as = inet_ntop (sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr, - addr_str, sizeof(addr_str)); -#endif - if(as == NULL) - return NULL; - res = strdup(as); - if (res == NULL) - errx (1, "malloc: out of memory"); - return res; -} - -static int -doit_broken (int argc, - char **argv, - int hostindex, - struct addrinfo *ai, - const char *remote_user, - const char *local_user, - int priv_socket1, - int priv_socket2, - const char *cmd, - size_t cmd_len) -{ - struct addrinfo *a; - - if (connect (priv_socket1, ai->ai_addr, ai->ai_addrlen) < 0) { - int save_errno = errno; - - close(priv_socket1); - close(priv_socket2); - - for (a = ai->ai_next; a != NULL; a = a->ai_next) { - pid_t pid; - char *adr = print_addr(a->ai_addr); - if(adr == NULL) - continue; - - pid = fork(); - if (pid < 0) - err (1, "fork"); - else if(pid == 0) { - char **new_argv; - int i = 0; - - new_argv = malloc((argc + 2) * sizeof(*new_argv)); - if (new_argv == NULL) - errx (1, "malloc: out of memory"); - new_argv[i] = argv[i]; - ++i; - if (hostindex == i) - new_argv[i++] = adr; - new_argv[i++] = "-K"; - for(; i <= argc; ++i) - new_argv[i] = argv[i - 1]; - if (hostindex > 1) - new_argv[hostindex + 1] = adr; - new_argv[argc + 1] = NULL; - execv(PATH_RSH, new_argv); - err(1, "execv(%s)", PATH_RSH); - } else { - int status; - free(adr); - - while(waitpid(pid, &status, 0) < 0) - ; - if(WIFEXITED(status) && WEXITSTATUS(status) == 0) - return 0; - } - } - errno = save_errno; - warn("%s", argv[hostindex]); - return 1; - } else { - int ret; - - ret = proto (priv_socket1, priv_socket2, - argv[hostindex], - local_user, remote_user, - cmd, cmd_len, - send_broken_auth); - return ret; - } -} - -#if defined(KRB5) -static int -doit (const char *hostname, - struct addrinfo *ai, - const char *remote_user, - const char *local_user, - const char *cmd, - size_t cmd_len, - int (*auth_func)(int s, - struct sockaddr *this, struct sockaddr *that, - const char *hostname, const char *remote_user, - const char *local_user, size_t cmd_len, - const char *cmd)) -{ - int error; - struct addrinfo *a; - int socketfailed = 1; - int ret; - - for (a = ai; a != NULL; a = a->ai_next) { - int s; - int errsock; - - s = socket (a->ai_family, a->ai_socktype, a->ai_protocol); - if (s < 0) - continue; - socketfailed = 0; - if (connect (s, a->ai_addr, a->ai_addrlen) < 0) { - char addr[128]; - if(getnameinfo(a->ai_addr, a->ai_addrlen, - addr, sizeof(addr), NULL, 0, NI_NUMERICHOST) == 0) - warn ("connect(%s [%s])", hostname, addr); - else - warn ("connect(%s)", hostname); - close (s); - continue; - } - if (do_errsock) { - struct addrinfo *ea, *eai; - struct addrinfo hints; - - memset (&hints, 0, sizeof(hints)); - hints.ai_socktype = a->ai_socktype; - hints.ai_protocol = a->ai_protocol; - hints.ai_family = a->ai_family; - hints.ai_flags = AI_PASSIVE; - - errsock = -1; - - error = getaddrinfo (NULL, "0", &hints, &eai); - if (error) - errx (1, "getaddrinfo: %s", gai_strerror(error)); - for (ea = eai; ea != NULL; ea = ea->ai_next) { - errsock = socket (ea->ai_family, ea->ai_socktype, - ea->ai_protocol); - if (errsock < 0) - continue; - if (bind (errsock, ea->ai_addr, ea->ai_addrlen) < 0) - err (1, "bind"); - break; - } - if (errsock < 0) - err (1, "socket"); - freeaddrinfo (eai); - } else - errsock = -1; - - ret = proto (s, errsock, - hostname, - local_user, remote_user, - cmd, cmd_len, auth_func); - close (s); - return ret; - } - if(socketfailed) - warnx ("failed to contact %s", hostname); - return -1; -} -#endif /* KRB5 */ - -struct getargs args[] = { -#ifdef KRB5 - { "krb5", '5', arg_flag, &use_v5, "Use Kerberos V5" }, - { "forward", 'f', arg_flag, &do_forward, "Forward credentials [krb5]"}, - { "forwardable", 'F', arg_flag, &do_forwardable, - "Forward forwardable credentials [krb5]" }, - { NULL, 'G', arg_negative_flag,&do_forward, "Don't forward credentials" }, - { "unique", 'u', arg_flag, &do_unique_tkfile, - "Use unique remote credentials cache [krb5]" }, - { "tkfile", 'U', arg_string, &unique_tkfile, - "Specifies remote credentials cache [krb5]" }, - { "protocol", 'P', arg_string, &protocol_version_str, - "Protocol version [krb5]", "protocol" }, -#endif - { "broken", 'K', arg_flag, &use_only_broken, "Use only priv port" }, -#if defined(KRB5) - { "encrypt", 'x', arg_flag, &do_encrypt, "Encrypt connection" }, - { NULL, 'z', arg_negative_flag, &do_encrypt, - "Don't encrypt connection", NULL }, -#endif - { NULL, 'd', arg_flag, &sock_debug, "Enable socket debugging" }, - { "input", 'n', arg_negative_flag, &input, "Close stdin" }, - { "port", 'p', arg_string, &port_str, "Use this port", - "port" }, - { "user", 'l', arg_string, &user, "Run as this user", "login" }, - { "stderr", 'e', arg_negative_flag, &do_errsock, "Don't open stderr"}, -#ifdef KRB5 -#endif - { "version", 0, arg_flag, &do_version, NULL }, - { "help", 0, arg_flag, &do_help, NULL } -}; - -static void -usage (int ret) -{ - arg_printusage (args, - sizeof(args) / sizeof(args[0]), - NULL, - "[login@]host [command]"); - exit (ret); -} - -/* - * - */ - -int -main(int argc, char **argv) -{ - int priv_port1, priv_port2; - int priv_socket1, priv_socket2; - int argindex = 0; - int error; - struct addrinfo hints, *ai; - int ret = 1; - char *cmd; - char *tmp; - size_t cmd_len; - const char *local_user; - char *host = NULL; - int host_index = -1; -#ifdef KRB5 - int status; -#endif - uid_t uid; - - priv_port1 = priv_port2 = IPPORT_RESERVED-1; - priv_socket1 = rresvport(&priv_port1); - priv_socket2 = rresvport(&priv_port2); - uid = getuid (); - if (setuid (uid) || (uid != 0 && setuid(0) == 0)) - err (1, "setuid"); - - setprogname (argv[0]); - - if (argc >= 2 && argv[1][0] != '-') { - host = argv[host_index = 1]; - argindex = 1; - } - - if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, - &argindex)) - usage (1); - - if (do_help) - usage (0); - - if (do_version) { - print_version (NULL); - return 0; - } - -#ifdef KRB5 - if(protocol_version_str != NULL) { - if(strcasecmp(protocol_version_str, "N") == 0) - protocol_version = 2; - else if(strcasecmp(protocol_version_str, "O") == 0) - protocol_version = 1; - else { - char *end; - int v; - v = strtol(protocol_version_str, &end, 0); - if(*end != '\0' || (v != 1 && v != 2)) { - errx(1, "unknown protocol version \"%s\"", - protocol_version_str); - } - protocol_version = v; - } - } - - status = krb5_init_context (&context); - if (status) { - if(use_v5 == 1) - errx(1, "krb5_init_context failed: %d", status); - else - use_v5 = 0; - } - - /* request for forwardable on the command line means we should - also forward */ - if (do_forwardable == 1) - do_forward = 1; - -#endif - - if (use_only_broken) { -#ifdef KRB5 - use_v5 = 0; -#endif - } - - if(priv_socket1 < 0) { - if (use_only_broken) - errx (1, "unable to bind reserved port: is rsh setuid root?"); - use_broken = 0; - } - -#if defined(KRB5) - if (do_encrypt == 1 && use_only_broken) - errx (1, "encryption not supported with old style authentication"); -#endif - - - -#ifdef KRB5 - if (do_unique_tkfile && unique_tkfile != NULL) - errx (1, "Only one of -u and -U allowed."); - - if (do_unique_tkfile) - strlcpy(tkfile,"-u ", sizeof(tkfile)); - else if (unique_tkfile != NULL) { - if (strchr(unique_tkfile,' ') != NULL) { - warnx("Space is not allowed in tkfilename"); - usage(1); - } - do_unique_tkfile = 1; - snprintf (tkfile, sizeof(tkfile), "-U %s ", unique_tkfile); - } -#endif - - if (host == NULL) { - if (argc - argindex < 1) - usage (1); - else - host = argv[host_index = argindex++]; - } - - if((tmp = strchr(host, '@')) != NULL) { - *tmp++ = '\0'; - user = host; - host = tmp; - } - - if (argindex == argc) { - close (priv_socket1); - close (priv_socket2); - argv[0] = "rlogin"; - execvp ("rlogin", argv); - err (1, "execvp rlogin"); - } - - local_user = get_default_username (); - if (local_user == NULL) - errx (1, "who are you?"); - - if (user == NULL) - user = local_user; - - cmd_len = construct_command(&cmd, argc - argindex, argv + argindex); - - /* - * Try all different authentication methods - */ - -#ifdef KRB5 - if (ret && use_v5) { - memset (&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - - if(port_str == NULL) { - error = getaddrinfo(host, "kshell", &hints, &ai); - if(error == EAI_NONAME) - error = getaddrinfo(host, "544", &hints, &ai); - } else - error = getaddrinfo(host, port_str, &hints, &ai); - - if(error) - errx (1, "getaddrinfo: %s", gai_strerror(error)); - - auth_method = AUTH_KRB5; - again: - ret = doit (host, ai, user, local_user, cmd, cmd_len, - send_krb5_auth); - if(ret != 0 && sendauth_version_error && - protocol_version == 2) { - protocol_version = 1; - goto again; - } - freeaddrinfo(ai); - } -#endif - if (ret && use_broken) { - memset (&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - - if(port_str == NULL) { - error = getaddrinfo(host, "shell", &hints, &ai); - if(error == EAI_NONAME) - error = getaddrinfo(host, "514", &hints, &ai); - } else - error = getaddrinfo(host, port_str, &hints, &ai); - - if(error) - errx (1, "getaddrinfo: %s", gai_strerror(error)); - - auth_method = AUTH_BROKEN; - ret = doit_broken (argc, argv, host_index, ai, - user, local_user, - priv_socket1, - do_errsock ? priv_socket2 : -1, - cmd, cmd_len); - freeaddrinfo(ai); - } - free(cmd); - return ret; -} diff --git a/appl/rsh/rsh_locl.h b/appl/rsh/rsh_locl.h deleted file mode 100644 index 088729772..000000000 --- a/appl/rsh/rsh_locl.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* $Id$ */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_SYS_WAIT_H -#include -#endif -#ifdef HAVE_SYS_SELECT_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETINET_IN6_H -#include -#endif -#ifdef HAVE_NETINET6_IN6_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif - -#ifdef HAVE_PWD_H -#include -#endif -#ifdef HAVE_SHADOW_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_LIMITS_H -#include -#endif -#include - -#ifdef HAVE_SYS_PARAM_H -#include -#endif - -#ifdef HAVE_SYSLOG_H -#include -#endif -#ifdef HAVE_PATHS_H -#include -#endif -#include -#include -#include -#ifdef KRB5 -#include -/* XXX */ -struct krb5_pk_identity; -struct krb5_pk_cert; -struct ContentInfo; -struct AlgorithmIdentifier; -struct _krb5_krb_auth_data; -struct krb5_dh_moduli; -#include "crypto-headers.h" -#include /* for _krb5_{get,put}_int */ -#endif -#if defined(KRB5) -#include -#endif - -#ifndef _PATH_BSHELL -#define _PATH_BSHELL "/bin/sh" -#endif - -#ifndef _PATH_DEFPATH -#define _PATH_DEFPATH "/usr/bin:/bin" -#endif - -#include "loginpaths.h" - -/* - * - */ - -enum auth_method { AUTH_KRB5, AUTH_BROKEN }; - -extern enum auth_method auth_method; -extern int do_encrypt; -#ifdef KRB5 -extern krb5_context context; -extern krb5_keyblock *keyblock; -extern krb5_crypto crypto; -extern int key_usage; -extern void *ivec_in[2]; -extern void *ivec_out[2]; -void init_ivecs(int, int); -#endif - -#define KCMD_OLD_VERSION "KCMDV0.1" -#define KCMD_NEW_VERSION "KCMDV0.2" - -#define USERNAME_SZ 16 -#ifndef ARG_MAX -#define ARG_MAX 8192 -#endif - -#define RSH_BUFSIZ (5 * 1024) /* MIT kcmd can't handle larger buffers */ -#define RSHD_BUFSIZ (16 * 1024) /* Old maxize for Heimdal 0.4 rsh */ - -#define PATH_RSH BINDIR "/rsh" - -#if defined(KRB5) -ssize_t do_read (int, void*, size_t, void*); -ssize_t do_write (int, void*, size_t, void*); -#else -#define do_write(F, B, L, I) write((F), (B), (L)) -#define do_read(F, B, L, I) read((F), (B), (L)) -#endif diff --git a/appl/rsh/rshd.8 b/appl/rsh/rshd.8 deleted file mode 100644 index 1f4035c2b..000000000 --- a/appl/rsh/rshd.8 +++ /dev/null @@ -1,162 +0,0 @@ -.\" Copyright (c) 2001 - 2006 Kungliga Tekniska Högskolan -.\" (Royal Institute of Technology, Stockholm, Sweden). -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" 3. Neither the name of the Institute nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" $Id$ -.\" -.Dd November 22, 2002 -.Dt RSHD 8 -.Os HEIMDAL -.Sh NAME -.Nm rshd -.Nd -remote shell server -.Sh SYNOPSIS -.Nm -.Op Fl aiklnvxPL -.Op Fl p Ar port -.Sh DESCRIPTION -.Nm -is the server for -the -.Xr rsh 1 -program. It provides an authenticated remote command execution -service. Supported options are: -.Bl -tag -width Ds -.It Xo -.Fl n , -.Fl -no-keepalive -.Xc -Disables keep-alive messages. -Keep-alives are packets sent at certain intervals to make sure that the -client is still there, even when it doesn't send any data. -.It Xo -.Fl k , -.Fl -kerberos -.Xc -Assume that clients connecting to this server will use some form of -Kerberos authentication. See the -.Sx EXAMPLES -section for a sample -.Xr inetd.conf 5 -configuration. -.It Xo -.Fl x , -.Fl -encrypt -.Xc -For Kerberos 4 this means that the connections are encrypted. Kerberos -5 can negotiate encryption even without this option, but if it's -present -.Nm -will deny unencrypted connections. This option implies -.Fl k . -.\".It Xo -.\".Fl l , -.\".Fl -no-rhosts -.\".Xc -.\"When using old port-based authentication, the user's -.\".Pa .rhosts -.\"files are normally checked. This option disables this. -.It Xo -.Fl v , -.Fl -vacuous -.Xc -If the connecting client does not use any Kerberised authentication, -print a message that complains about this fact, and exit. This is -helpful if you want to move away from old port-based authentication. -.It Xo -.Fl P -.Xc -When using the AFS filesystem, users' authentication tokens are put in -something called a PAG (Process Authentication Group). Multiple -processes can share a PAG, but normally each login session has its own -PAG. This option disables the -.Fn setpag -call, so all tokens will be put in the default (uid-based) PAG, making -it possible to share tokens between sessions. This is only useful in -peculiar environments, such as some batch systems. -.It Xo -.Fl i , -.Fl -no-inetd -.Xc -The -.Fl i -option will cause -.Nm -to create a socket, instead of assuming that its stdin came from -.Xr inetd 8 . -This is mostly useful for debugging. -.It Xo -.Fl p Ar port , -.Fl -port= Ns Ar port -.Xc -Port to use with -.Fl i . -.It Xo -.Fl a -.Xc -This flag is for backwards compatibility only. -.It Xo -.Fl L -.Xc -This flag enables logging of connections to -.Xr syslogd 8 . -This option is always on in this implementation. -.El -.\".Sh ENVIRONMENT -.Sh FILES -.Bl -tag -width /etc/hosts.equiv -compact -.It Pa /etc/hosts.equiv -.It Pa ~/.rhosts -.El -.Sh EXAMPLES -The following can be used to enable Kerberised rsh in -.Xr inetd.cond 5 , -while disabling non-Kerberised connections: -.Bd -literal -shell stream tcp nowait root /usr/libexec/rshd rshd -v -kshell stream tcp nowait root /usr/libexec/rshd rshd -k -ekshell stream tcp nowait root /usr/libexec/rshd rshd -kx -.Ed -.\".Sh DIAGNOSTICS -.Sh SEE ALSO -.Xr rsh 1 , -.Xr iruserok 3 -.\".Sh STANDARDS -.Sh HISTORY -The -.Nm -command appeared in -.Bx 4.2 . -.Sh AUTHORS -This implementation of -.Nm -was written as part of the Heimdal Kerberos 5 implementation. -.\".Sh BUGS diff --git a/appl/rsh/rshd.c b/appl/rsh/rshd.c deleted file mode 100644 index b22918b40..000000000 --- a/appl/rsh/rshd.c +++ /dev/null @@ -1,979 +0,0 @@ -/* - * Copyright (c) 1997-2007 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "rsh_locl.h" -#include "login_locl.h" -RCSID("$Id$"); - -int -login_access( struct passwd *user, char *from); -int -read_limits_conf(const char *file, const struct passwd *pwd); - -#ifdef NEED_IRUSEROK_PROTO -int iruserok(uint32_t, int, const char *, const char *); -#endif - -enum auth_method auth_method; - -#ifdef KRB5 -krb5_context context; -krb5_keyblock *keyblock; -krb5_crypto crypto; -#endif - -#ifdef KRB5 -krb5_ccache ccache, ccache2; -int kerberos_status = 0; -#endif - -int do_encrypt = 0; - -static int do_unique_tkfile = 0; -static char tkfile[MAXPATHLEN] = ""; - -static int do_inetd = 1; -static char *port_str; -static int do_rhosts = 1; -static int do_kerberos = 0; -#define DO_KRB5 4 -static int do_vacuous = 0; -static int do_log = 1; -static int do_newpag = 1; -static int do_addr_verify = 0; -static int do_keepalive = 1; -static int do_version; -static int do_help = 0; - -static void -syslog_and_die (const char *m, ...) - __attribute__ ((format (printf, 1, 2))); - -static void -syslog_and_die (const char *m, ...) -{ - va_list args; - - va_start(args, m); - vsyslog (LOG_ERR, m, args); - va_end(args); - exit (1); -} - -static void -fatal (int, const char*, const char *, ...) - __attribute__ ((noreturn, format (printf, 3, 4))); - -static void -fatal (int sock, const char *what, const char *m, ...) -{ - va_list args; - char buf[BUFSIZ]; - size_t len; - - *buf = 1; - va_start(args, m); - len = vsnprintf (buf + 1, sizeof(buf) - 1, m, args); - len = min(len, sizeof(buf) - 1); - va_end(args); - if(what != NULL) - syslog (LOG_ERR, "%s: %s: %s", what, strerror(errno), buf + 1); - else - syslog (LOG_ERR, "%s", buf + 1); - net_write (sock, buf, len + 1); - exit (1); -} - -static char * -read_str (int s, size_t sz, char *expl) -{ - char *str = malloc(sz); - char *p = str; - if(str == NULL) - fatal(s, NULL, "%s too long", expl); - while(p < str + sz) { - if(net_read(s, p, 1) != 1) - syslog_and_die("read: %s", strerror(errno)); - if(*p == '\0') - return str; - p++; - } - fatal(s, NULL, "%s too long", expl); -} - -static int -recv_bsd_auth (int s, u_char *buf, - struct sockaddr_in *thisaddr, - struct sockaddr_in *thataddr, - char **client_username, - char **server_username, - char **cmd) -{ - struct passwd *pwd; - - *client_username = read_str (s, USERNAME_SZ, "local username"); - *server_username = read_str (s, USERNAME_SZ, "remote username"); - *cmd = read_str (s, ARG_MAX + 1, "command"); - pwd = getpwnam(*server_username); - if (pwd == NULL) - fatal(s, NULL, "Login incorrect."); - if (iruserok(thataddr->sin_addr.s_addr, pwd->pw_uid == 0, - *client_username, *server_username)) - fatal(s, NULL, "Login incorrect."); - return 0; -} - -#ifdef KRB5 -static int -save_krb5_creds (int s, - krb5_auth_context auth_context, - krb5_principal client) - -{ - int ret; - krb5_data remote_cred; - - krb5_data_zero (&remote_cred); - ret= krb5_read_message (context, (void *)&s, &remote_cred); - if (ret) { - krb5_data_free(&remote_cred); - return 0; - } - if (remote_cred.length == 0) - return 0; - - ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache); - if (ret) { - krb5_data_free(&remote_cred); - return 0; - } - - krb5_cc_initialize(context,ccache,client); - ret = krb5_rd_cred2(context, auth_context, ccache, &remote_cred); - if(ret != 0) - syslog(LOG_INFO|LOG_AUTH, - "reading creds: %s", krb5_get_err_text(context, ret)); - krb5_data_free (&remote_cred); - if (ret) - return 0; - return 1; -} - -static void -krb5_start_session (void) -{ - krb5_error_code ret; - char *estr; - - ret = krb5_cc_resolve (context, tkfile, &ccache2); - if (ret) { - estr = krb5_get_error_string(context); - syslog(LOG_WARNING, "resolve cred cache %s: %s", - tkfile, - estr ? estr : krb5_get_err_text(context, ret)); - free(estr); - krb5_cc_destroy(context, ccache); - return; - } - - ret = krb5_cc_copy_cache (context, ccache, ccache2); - if (ret) { - estr = krb5_get_error_string(context); - syslog(LOG_WARNING, "storing credentials: %s", - estr ? estr : krb5_get_err_text(context, ret)); - free(estr); - krb5_cc_destroy(context, ccache); - return ; - } - - krb5_cc_close(context, ccache2); - krb5_cc_destroy(context, ccache); - return; -} - -static int protocol_version; - -static krb5_boolean -match_kcmd_version(const void *data, const char *version) -{ - if(strcmp(version, KCMD_NEW_VERSION) == 0) { - protocol_version = 2; - return TRUE; - } - if(strcmp(version, KCMD_OLD_VERSION) == 0) { - protocol_version = 1; - key_usage = KRB5_KU_OTHER_ENCRYPTED; - return TRUE; - } - return FALSE; -} - - -static int -recv_krb5_auth (int s, u_char *buf, - struct sockaddr *thisaddr, - struct sockaddr *thataddr, - char **client_username, - char **server_username, - char **cmd) -{ - uint32_t len; - krb5_auth_context auth_context = NULL; - krb5_ticket *ticket; - krb5_error_code status; - krb5_data cksum_data; - krb5_principal server; - char *str; - - if (memcmp (buf, "\x00\x00\x00\x13", 4) != 0) - return -1; - len = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3]); - - if (net_read(s, buf, len) != len) - syslog_and_die ("reading auth info: %s", strerror(errno)); - if (len != sizeof(KRB5_SENDAUTH_VERSION) - || memcmp (buf, KRB5_SENDAUTH_VERSION, len) != 0) - syslog_and_die ("bad sendauth version: %.8s", buf); - - status = krb5_sock_to_principal (context, - s, - "host", - KRB5_NT_SRV_HST, - &server); - if (status) - syslog_and_die ("krb5_sock_to_principal: %s", - krb5_get_err_text(context, status)); - - status = krb5_recvauth_match_version(context, - &auth_context, - &s, - match_kcmd_version, - NULL, - server, - KRB5_RECVAUTH_IGNORE_VERSION, - NULL, - &ticket); - krb5_free_principal (context, server); - if (status) - syslog_and_die ("krb5_recvauth: %s", - krb5_get_err_text(context, status)); - - *server_username = read_str (s, USERNAME_SZ, "remote username"); - *cmd = read_str (s, ARG_MAX + 1, "command"); - *client_username = read_str (s, ARG_MAX + 1, "local username"); - - if(protocol_version == 2) { - status = krb5_auth_con_getremotesubkey(context, auth_context, - &keyblock); - if(status != 0 || keyblock == NULL) - syslog_and_die("failed to get remote subkey"); - } else if(protocol_version == 1) { - status = krb5_auth_con_getkey (context, auth_context, &keyblock); - if(status != 0 || keyblock == NULL) - syslog_and_die("failed to get key"); - } - if (status != 0 || keyblock == NULL) - syslog_and_die ("krb5_auth_con_getkey: %s", - krb5_get_err_text(context, status)); - - status = krb5_crypto_init(context, keyblock, 0, &crypto); - if(status) - syslog_and_die("krb5_crypto_init: %s", - krb5_get_err_text(context, status)); - - - cksum_data.length = asprintf (&str, - "%u:%s%s", - ntohs(socket_get_port (thisaddr)), - *cmd, - *server_username); - if (str == NULL) - syslog_and_die ("asprintf: out of memory"); - cksum_data.data = str; - - status = krb5_verify_authenticator_checksum(context, - auth_context, - cksum_data.data, - cksum_data.length); - - if (status) - syslog_and_die ("krb5_verify_authenticator_checksum: %s", - krb5_get_err_text(context, status)); - - free (cksum_data.data); - - if (strncmp (*client_username, "-u ", 3) == 0) { - do_unique_tkfile = 1; - memmove (*client_username, *client_username + 3, - strlen(*client_username) - 2); - } - - if (strncmp (*client_username, "-U ", 3) == 0) { - char *end, *temp_tkfile; - - do_unique_tkfile = 1; - if (strncmp (*client_username + 3, "FILE:", 5) == 0) { - temp_tkfile = tkfile; - } else { - strlcpy (tkfile, "FILE:", sizeof(tkfile)); - temp_tkfile = tkfile + 5; - } - end = strchr(*client_username + 3,' '); - if (end == NULL) - syslog_and_die("missing argument after -U"); - snprintf(temp_tkfile, sizeof(tkfile) - (temp_tkfile - tkfile), - "%.*s", - (int)(end - *client_username - 3), - *client_username + 3); - memmove (*client_username, end + 1, strlen(end+1)+1); - } - - kerberos_status = save_krb5_creds (s, auth_context, ticket->client); - - if(!krb5_kuserok (context, - ticket->client, - *server_username)) - fatal (s, NULL, "Permission denied."); - - if (strncmp (*cmd, "-x ", 3) == 0) { - do_encrypt = 1; - memmove (*cmd, *cmd + 3, strlen(*cmd) - 2); - } else { - if(do_encrypt) - fatal (s, NULL, "Encryption is required."); - do_encrypt = 0; - } - - { - char *name; - - if (krb5_unparse_name (context, ticket->client, &name) == 0) { - char addr_str[256]; - - if (inet_ntop (thataddr->sa_family, - socket_get_address (thataddr), - addr_str, sizeof(addr_str)) == NULL) - strlcpy (addr_str, "unknown address", - sizeof(addr_str)); - - syslog(LOG_INFO|LOG_AUTH, - "kerberos v5 shell from %s on %s as %s, cmd '%.80s'", - name, - addr_str, - *server_username, - *cmd); - free (name); - } - } - - krb5_auth_con_free(context, auth_context); - - return 0; -} -#endif /* KRB5 */ - -static void -rshd_loop (int from0, int to0, - int to1, int from1, - int to2, int from2, - int have_errsock) -{ - fd_set real_readset; - int max_fd; - int count = 2; - char *buf; - - if(from0 >= FD_SETSIZE || from1 >= FD_SETSIZE || from2 >= FD_SETSIZE) - errx (1, "fd too large"); - -#ifdef KRB5 - if(auth_method == AUTH_KRB5 && protocol_version == 2) - init_ivecs(0, have_errsock); -#endif - - FD_ZERO(&real_readset); - FD_SET(from0, &real_readset); - FD_SET(from1, &real_readset); - FD_SET(from2, &real_readset); - max_fd = max(from0, max(from1, from2)) + 1; - - buf = malloc(max(RSHD_BUFSIZ, RSH_BUFSIZ)); - if (buf == NULL) - syslog_and_die("out of memory"); - - for (;;) { - int ret; - fd_set readset = real_readset; - - ret = select (max_fd, &readset, NULL, NULL, NULL); - if (ret < 0) { - if (errno == EINTR) - continue; - else - syslog_and_die ("select: %s", strerror(errno)); - } - if (FD_ISSET(from0, &readset)) { - ret = do_read (from0, buf, RSHD_BUFSIZ, ivec_in[0]); - if (ret < 0) - syslog_and_die ("read: %s", strerror(errno)); - else if (ret == 0) { - close (from0); - close (to0); - FD_CLR(from0, &real_readset); - } else - net_write (to0, buf, ret); - } - if (FD_ISSET(from1, &readset)) { - ret = read (from1, buf, RSH_BUFSIZ); - if (ret < 0) - syslog_and_die ("read: %s", strerror(errno)); - else if (ret == 0) { - close (from1); - close (to1); - FD_CLR(from1, &real_readset); - if (--count == 0) - exit (0); - } else - do_write (to1, buf, ret, ivec_out[0]); - } - if (FD_ISSET(from2, &readset)) { - ret = read (from2, buf, RSH_BUFSIZ); - if (ret < 0) - syslog_and_die ("read: %s", strerror(errno)); - else if (ret == 0) { - close (from2); - close (to2); - FD_CLR(from2, &real_readset); - if (--count == 0) - exit (0); - } else - do_write (to2, buf, ret, ivec_out[1]); - } - } -} - -/* - * Used by `setup_copier' to create some pipe-like means of - * communcation. Real pipes would probably be the best thing, but - * then the shell doesn't understand it's talking to rshd. If - * socketpair doesn't work everywhere, some autoconf magic would have - * to be added here. - * - * If it fails creating the `pipe', it aborts by calling fatal. - */ - -static void -pipe_a_like (int fd[2]) -{ - if (socketpair (AF_UNIX, SOCK_STREAM, 0, fd) < 0) - fatal (STDOUT_FILENO, "socketpair", "Pipe creation failed."); -} - -/* - * Start a child process and leave the parent copying data to and from it. */ - -static void -setup_copier (int have_errsock) -{ - int p0[2], p1[2], p2[2]; - pid_t pid; - - pipe_a_like(p0); - pipe_a_like(p1); - pipe_a_like(p2); - pid = fork (); - if (pid < 0) - fatal (STDOUT_FILENO, "fork", "Could not create child process."); - if (pid == 0) { /* child */ - close (p0[1]); - close (p1[0]); - close (p2[0]); - dup2 (p0[0], STDIN_FILENO); - dup2 (p1[1], STDOUT_FILENO); - dup2 (p2[1], STDERR_FILENO); - close (p0[0]); - close (p1[1]); - close (p2[1]); - } else { /* parent */ - close (p0[0]); - close (p1[1]); - close (p2[1]); - - if (net_write (STDOUT_FILENO, "", 1) != 1) - fatal (STDOUT_FILENO, "net_write", "Write failure."); - - rshd_loop (STDIN_FILENO, p0[1], - STDOUT_FILENO, p1[0], - STDERR_FILENO, p2[0], - have_errsock); - } -} - -/* - * Is `port' a ``reserverd'' port? - */ - -static int -is_reserved(u_short port) -{ - return ntohs(port) < IPPORT_RESERVED; -} - -/* - * Set the necessary part of the environment in `env'. - */ - -static void -setup_environment (char ***env, const struct passwd *pwd) -{ - int i, j, path; - char **e; - - i = 0; - path = 0; - *env = NULL; - - i = read_environment(_PATH_ETC_ENVIRONMENT, env); - e = *env; - for (j = 0; j < i; j++) { - if (!strncmp(e[j], "PATH=", 5)) { - path = 1; - } - } - - e = *env; - e = realloc(e, (i + 7) * sizeof(char *)); - - if (asprintf (&e[i++], "USER=%s", pwd->pw_name) == -1) - syslog_and_die ("asprintf: out of memory"); - if (asprintf (&e[i++], "HOME=%s", pwd->pw_dir) == -1) - syslog_and_die ("asprintf: out of memory"); - if (asprintf (&e[i++], "SHELL=%s", pwd->pw_shell) == -1) - syslog_and_die ("asprintf: out of memory"); - if (! path) { - if (asprintf (&e[i++], "PATH=%s", _PATH_DEFPATH) == -1) - syslog_and_die ("asprintf: out of memory"); - } - asprintf (&e[i++], "SSH_CLIENT=only_to_make_bash_happy"); - if (do_unique_tkfile) - if (asprintf (&e[i++], "KRB5CCNAME=%s", tkfile) == -1) - syslog_and_die ("asprintf: out of memory"); - e[i++] = NULL; - *env = e; -} - -static void -doit (void) -{ - u_char buf[BUFSIZ]; - u_char *p; - struct sockaddr_storage thisaddr_ss; - struct sockaddr *thisaddr = (struct sockaddr *)&thisaddr_ss; - struct sockaddr_storage thataddr_ss; - struct sockaddr *thataddr = (struct sockaddr *)&thataddr_ss; - struct sockaddr_storage erraddr_ss; - struct sockaddr *erraddr = (struct sockaddr *)&erraddr_ss; - socklen_t thisaddr_len, thataddr_len; - int port; - int errsock = -1; - char *client_user = NULL, *server_user = NULL, *cmd = NULL; - struct passwd *pwd; - int s = STDIN_FILENO; - char **env; - int ret; - char that_host[NI_MAXHOST]; - - thisaddr_len = sizeof(thisaddr_ss); - if (getsockname (s, thisaddr, &thisaddr_len) < 0) - syslog_and_die("getsockname: %s", strerror(errno)); - thataddr_len = sizeof(thataddr_ss); - if (getpeername (s, thataddr, &thataddr_len) < 0) - syslog_and_die ("getpeername: %s", strerror(errno)); - - /* check for V4MAPPED addresses? */ - - if (do_kerberos == 0 && !is_reserved(socket_get_port(thataddr))) - fatal(s, NULL, "Permission denied."); - - p = buf; - port = 0; - for(;;) { - if (net_read (s, p, 1) != 1) - syslog_and_die ("reading port number: %s", strerror(errno)); - if (*p == '\0') - break; - else if (isdigit(*p)) - port = port * 10 + *p - '0'; - else - syslog_and_die ("non-digit in port number: %c", *p); - } - - if (do_kerberos == 0 && !is_reserved(htons(port))) - fatal(s, NULL, "Permission denied."); - - if (port) { - int priv_port = IPPORT_RESERVED - 1; - - /* - * There's no reason to require a ``privileged'' port number - * here, but for some reason the brain dead rsh clients - * do... :-( - */ - - erraddr->sa_family = thataddr->sa_family; - socket_set_address_and_port (erraddr, - socket_get_address (thataddr), - htons(port)); - - /* - * we only do reserved port for IPv4 - */ - - if (erraddr->sa_family == AF_INET) - errsock = rresvport (&priv_port); - else - errsock = socket (erraddr->sa_family, SOCK_STREAM, 0); - if (errsock < 0) - syslog_and_die ("socket: %s", strerror(errno)); - if (connect (errsock, - erraddr, - socket_sockaddr_size (erraddr)) < 0) { - syslog (LOG_WARNING, "connect: %s", strerror(errno)); - close (errsock); - } - } - - if(do_kerberos) { - if (net_read (s, buf, 4) != 4) - syslog_and_die ("reading auth info: %s", strerror(errno)); - -#ifdef KRB5 - if((do_kerberos & DO_KRB5) && - recv_krb5_auth (s, buf, thisaddr, thataddr, - &client_user, - &server_user, - &cmd) == 0) - auth_method = AUTH_KRB5; - else -#endif /* KRB5 */ - syslog_and_die ("unrecognized auth protocol: %x %x %x %x", - buf[0], buf[1], buf[2], buf[3]); - } else { - if(recv_bsd_auth (s, buf, - (struct sockaddr_in *)thisaddr, - (struct sockaddr_in *)thataddr, - &client_user, - &server_user, - &cmd) == 0) { - auth_method = AUTH_BROKEN; - if(do_vacuous) { - printf("Remote host requires Kerberos authentication\n"); - exit(0); - } - } else - syslog_and_die("recv_bsd_auth failed"); - } - - if (client_user == NULL || server_user == NULL || cmd == NULL) - syslog_and_die("mising client/server/cmd"); - - pwd = getpwnam (server_user); - if (pwd == NULL) - fatal (s, NULL, "Login incorrect."); - - if (*pwd->pw_shell == '\0') - pwd->pw_shell = _PATH_BSHELL; - - if (pwd->pw_uid != 0 && access (_PATH_NOLOGIN, F_OK) == 0) - fatal (s, NULL, "Login disabled."); - - - ret = getnameinfo_verified (thataddr, thataddr_len, - that_host, sizeof(that_host), - NULL, 0, 0); - if (ret) - fatal (s, NULL, "getnameinfo: %s", gai_strerror(ret)); - - if (login_access(pwd, that_host) == 0) { - syslog(LOG_NOTICE, "Kerberos rsh denied to %s from %s", - server_user, that_host); - fatal(s, NULL, "Permission denied."); - } - -#ifdef HAVE_GETSPNAM - { - struct spwd *sp; - long today; - - sp = getspnam(server_user); - if (sp != NULL) { - today = time(0)/(24L * 60 * 60); - if (sp->sp_expire > 0) - if (today > sp->sp_expire) - fatal(s, NULL, "Account has expired."); - } - } -#endif - - -#ifdef HAVE_SETLOGIN - if (setlogin(pwd->pw_name) < 0) - syslog(LOG_ERR, "setlogin() failed: %s", strerror(errno)); -#endif - -#ifdef HAVE_SETPCRED - if (setpcred (pwd->pw_name, NULL) == -1) - syslog(LOG_ERR, "setpcred() failure: %s", strerror(errno)); -#endif /* HAVE_SETPCRED */ - - /* Apply limits if not root */ - if(pwd->pw_uid != 0) { - const char *file = _PATH_LIMITS_CONF; - read_limits_conf(file, pwd); - } - - if (initgroups (pwd->pw_name, pwd->pw_gid) < 0) - fatal (s, "initgroups", "Login incorrect."); - - if (setgid(pwd->pw_gid) < 0) - fatal (s, "setgid", "Login incorrect."); - - if (setuid (pwd->pw_uid) < 0) - fatal (s, "setuid", "Login incorrect."); - - if (chdir (pwd->pw_dir) < 0) - fatal (s, "chdir", "Remote directory."); - - if (errsock >= 0) { - if (dup2 (errsock, STDERR_FILENO) < 0) - fatal (s, "dup2", "Cannot dup stderr."); - close (errsock); - } else { - if (dup2 (STDOUT_FILENO, STDERR_FILENO) < 0) - fatal (s, "dup2", "Cannot dup stderr."); - } - -#ifdef KRB5 - { - int fd; - - if (!do_unique_tkfile) - snprintf(tkfile,sizeof(tkfile),"FILE:/tmp/krb5cc_%lu", - (unsigned long)pwd->pw_uid); - else if (*tkfile=='\0') { - snprintf(tkfile,sizeof(tkfile),"FILE:/tmp/krb5cc_XXXXXX"); - fd = mkstemp(tkfile+5); - close(fd); - unlink(tkfile+5); - } - - if (kerberos_status) - krb5_start_session(); - } -#endif - - setup_environment (&env, pwd); - - if (do_encrypt) { - setup_copier (errsock >= 0); - } else { - if (net_write (s, "", 1) != 1) - fatal (s, "net_write", "write failed"); - } - -#if defined(KRB5) - if(k_hasafs()) { - char cell[64]; - - if(do_newpag) - k_setpag(); - - /* XXX */ - if (kerberos_status) { - krb5_ccache ccache; - krb5_error_code status; - - status = krb5_cc_resolve (context, tkfile, &ccache); - if (!status) { - if (k_afs_cell_of_file (pwd->pw_dir, cell, sizeof(cell)) == 0) - krb5_afslog_uid_home(context, ccache, cell, NULL, - pwd->pw_uid, pwd->pw_dir); - krb5_afslog_uid_home(context, ccache, NULL, NULL, - pwd->pw_uid, pwd->pw_dir); - krb5_cc_close (context, ccache); - } - } - } -#endif /* KRB5 */ - execle (pwd->pw_shell, pwd->pw_shell, "-c", cmd, NULL, env); - err(1, "exec %s", pwd->pw_shell); -} - -struct getargs args[] = { - { NULL, 'a', arg_flag, &do_addr_verify }, - { "keepalive", 'n', arg_negative_flag, &do_keepalive }, - { "inetd", 'i', arg_negative_flag, &do_inetd, - "Not started from inetd" }, -#if defined(KRB5) - { "kerberos", 'k', arg_flag, &do_kerberos, - "Implement kerberised services" }, - { "encrypt", 'x', arg_flag, &do_encrypt, - "Implement encrypted service" }, -#endif - { "rhosts", 'l', arg_negative_flag, &do_rhosts, - "Don't check users .rhosts" }, - { "port", 'p', arg_string, &port_str, "Use this port", - "port" }, - { "vacuous", 'v', arg_flag, &do_vacuous, - "Don't accept non-kerberised connections" }, -#if defined(KRB5) - { NULL, 'P', arg_negative_flag, &do_newpag, - "Don't put process in new PAG" }, -#endif - /* compatibility flag: */ - { NULL, 'L', arg_flag, &do_log }, - { "version", 0, arg_flag, &do_version }, - { "help", 0, arg_flag, &do_help } -}; - -static void -usage (int ret) -{ - if(isatty(STDIN_FILENO)) - arg_printusage (args, - sizeof(args) / sizeof(args[0]), - NULL, - ""); - else - syslog (LOG_ERR, "Usage: %s [-ikxlvPL] [-p port]", getprogname()); - exit (ret); -} - - -int -main(int argc, char **argv) -{ - int optind = 0; - int on = 1; - - setprogname (argv[0]); - roken_openlog ("rshd", LOG_ODELAY | LOG_PID, LOG_AUTH); - - if (getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, - &optind)) - usage(1); - - if(do_help) - usage (0); - - if (do_version) { - print_version(NULL); - exit(0); - } - -#if defined(KRB5) - if (do_encrypt) - do_kerberos = 1; - - if(do_kerberos) - do_kerberos = DO_KRB5; -#endif - -#ifdef KRB5 - if((do_kerberos & DO_KRB5) && krb5_init_context (&context) != 0) - do_kerberos &= ~DO_KRB5; -#endif - - if (!do_inetd) { - int error; - struct addrinfo *ai = NULL, hints; - char portstr[NI_MAXSERV]; - - memset (&hints, 0, sizeof(hints)); - hints.ai_flags = AI_PASSIVE; - hints.ai_socktype = SOCK_STREAM; - hints.ai_family = PF_UNSPEC; - - if(port_str != NULL) { - error = getaddrinfo (NULL, port_str, &hints, &ai); - if (error) - errx (1, "getaddrinfo: %s", gai_strerror (error)); - } - if (ai == NULL) { -#if defined(KRB5) - if (do_kerberos) { - if (do_encrypt) { - error = getaddrinfo(NULL, "ekshell", &hints, &ai); - if(error == EAI_NONAME) { - snprintf(portstr, sizeof(portstr), "%d", 545); - error = getaddrinfo(NULL, portstr, &hints, &ai); - } - if(error) - errx (1, "getaddrinfo: %s", gai_strerror (error)); - } else { - error = getaddrinfo(NULL, "kshell", &hints, &ai); - if(error == EAI_NONAME) { - snprintf(portstr, sizeof(portstr), "%d", 544); - error = getaddrinfo(NULL, portstr, &hints, &ai); - } - if(error) - errx (1, "getaddrinfo: %s", gai_strerror (error)); - } - } else -#endif - { - error = getaddrinfo(NULL, "shell", &hints, &ai); - if(error == EAI_NONAME) { - snprintf(portstr, sizeof(portstr), "%d", 514); - error = getaddrinfo(NULL, portstr, &hints, &ai); - } - if(error) - errx (1, "getaddrinfo: %s", gai_strerror (error)); - } - } - mini_inetd_addrinfo (ai); - freeaddrinfo(ai); - } - - if (do_keepalive && - setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, - sizeof(on)) < 0) - syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %s", strerror(errno)); - - /* set SO_LINGER? */ - - signal (SIGPIPE, SIG_IGN); - - doit (); - return 0; -} diff --git a/appl/su/ChangeLog b/appl/su/ChangeLog deleted file mode 100644 index 6e2e56926..000000000 --- a/appl/su/ChangeLog +++ /dev/null @@ -1,129 +0,0 @@ -2008-07-15 Love Hörnquist Åstrand - - * Makefile.am: no krb4 - - * su.c: Drop kerberos 4 support. - -2007-10-19 Love Hörnquist Åstrand - - * su.c: read environment from _PATH_ETC_ENVIRONMENT - - * supaths.c: paths - -2007-08-02 Love Hörnquist Åstrand - - * su.c: Check all local realms when su-ing, from Magnus Holmberg. - -2007-06-19 Love Hörnquist Åstrand - - * su.c: If not root and not setuid, print warning. - -2006-01-17 Love Hörnquist Åstrand - - * su.c (group_member_p): rename from group_member to avoid name - pollution from glibc headers. Fixed based on report from David Love. - -2006-01-12 Johan Danielsson - - * su.c: fix reversed logic when deciding to print tty or not - -2005-10-22 Love Hörnquist Åstrand - - * su.c: Check return value from asprintf instead of string != NULL - since it undefined behavior on Linux. From Björn Sandell - -2005-05-10 Dave Love - - * su.c: Include . - -2003-09-03 Love Hörnquist Åstrand - - * su.c: s/des_read_pw_string/UI_UTIL_read_pw_string/ - -2003-05-06 Johan Danielsson - - * su.c: remove accidentally committed code that prints the command - being executed - -2003-03-18 Love Hörnquist Åstrand - - * su.c (krb5_start_session): krb5_afslog doesn't depend on KRB4 - any more - -2002-02-19 Johan Danielsson - - * su.c: make this build without krb5 - -2002-01-09 Jacques Vidrine - - * su.c: Don't use getlogin() to determine whether we are root. - Patch by joda. - -2001-06-12 Assar Westerlund - - * su.c: check memory allocations. add some const - -2000-12-31 Assar Westerlund - - * su.c (krb5_verify): handle krb5_init_context failure - consistently - -2000-08-28 Johan Danielsson - - * su.c: set KRBTKFILE - -2000-07-10 Assar Westerlund - - * Makefile.am: actually install su - * su.c (krb5_verify): try harder freeing. do not get upset on - interrupted password read - -2000-06-09 Assar Westerlund - - * su.c (main): work-around for setuid and capabilities bug fixed - in Linux 2.2.16 - -2000-06-03 Assar Westerlund - - * su.c (main): just ignore shadow information if getspnam returns - NULL - -1999-10-20 Assar Westerlund - - * Makefile.am: use LIB_roken - -1999-09-28 Assar Westerlund - - * su.c (krb5_verify): use krb5_verify_user_lrealm - -1999-08-04 Assar Westerlund - - * su.c: add support for shadow passwords and rewrite some logic. - From Miroslav Ruda - - * Makefile.am: add libkafs - -1999-06-15 Assar Westerlund - - * su.c (main): conditionalize `getlogin' - -1999-05-11 Assar Westerlund - - * su.c (verfiy_krb5): get the name out of the ccache before - closing it - -1999-05-05 Assar Westerlund - - * su.c: some more error checking - -Wed Apr 21 21:04:36 1999 Assar Westerlund - - * su.c (-f): implement - - * su.c: implement -i - (verify_krb5): correct the ownership on the credential cache - -Tue Apr 20 13:26:13 1999 Johan Danielsson - - * su.c: don't depend on paths.h - diff --git a/appl/su/Makefile.am b/appl/su/Makefile.am deleted file mode 100644 index 97b0e7a40..000000000 --- a/appl/su/Makefile.am +++ /dev/null @@ -1,18 +0,0 @@ -# $Id$ - -include $(top_srcdir)/Makefile.am.common - -AM_CPPFLAGS += $(INCLUDE_krb4) $(INCLUDE_hcrypto) - -bin_PROGRAMS = su -bin_SUIDS = su -su_SOURCES = su.c supaths.h -man_MANS = su.1 - -LDADD = $(LIB_kafs) \ - $(top_builddir)/lib/krb5/libkrb5.la \ - $(LIB_hcrypto) \ - $(top_builddir)/lib/asn1/libasn1.la \ - $(LIB_roken) - -EXTRA_DIST = $(man_MANS) diff --git a/appl/su/su.1 b/appl/su/su.1 deleted file mode 100644 index 39d46f458..000000000 --- a/appl/su/su.1 +++ /dev/null @@ -1,123 +0,0 @@ -.\" Copyright (c) 2003 - 2006 Kungliga Tekniska Högskolan -.\" (Royal Institute of Technology, Stockholm, Sweden). -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" 3. Neither the name of the Institute nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" $Id$ -.\" -.Dd January 12, 2006 -.Dt SU 1 -.Os HEIMDAL -.Sh NAME -.Nm su -.Nd substitute user identity -.Sh SYNOPSIS -.Nm su -.Op Fl K | Fl -no-kerberos -.Op Fl f -.Op Fl l | Fl -full -.Op Fl m -.Oo Fl i Ar instance \*(Ba Xo -.Fl -instance= Ns Ar instance -.Xc -.Oc -.Oo Fl c Ar command \*(Ba Xo -.Fl -command= Ns Ar command -.Xc -.Oc -.Op Ar login Op Ar "shell arguments" -.Sh DESCRIPTION -.Nm su -will use Kerberos authentication provided that an instance for the -user wanting to change effective UID is present in a file named -.Pa .k5login -in the target user id's home directory -.Pp -A special case exists where -.Ql root Ap s -.Pa ~/.k5login -needs to contain an entry for: -.Ql user Ns / Ns Ao instance Ac Ns @ Ns REALM -for -.Nm su -to succed (where -.Aq instance -is -.Ql root -unless changed with -.Fl i ) . -.Pp -In the absence of either an entry for current user in said file or -other problems like missing -.Ql host/hostname@REALM -keys in the system's -keytab, or user typing the wrong password, -.Nm su -will fall back to traditional -.Pa /etc/passwd -authentication. -.Pp -When using -.Pa /etc/passwd -authentication, -.Nm su -allows -.Ql root -access only to members of the group -.Ql wheel , -or to any user (with knowledge of the -.Ql root -password) if that group -does not exist, or has no members. -.Pp -The options are as follows: -.Bl -item -width Ds -.It -.Fl K , -.Fl -no-kerberos -don't use Kerberos. -.It -.Fl f -don't read .cshrc. -.It -.Fl l , -.Fl -full -simulate full login. -.It -.Fl m -leave environment unmodified. -.It -.Fl i Ar instance , -.Fl -instance= Ns Ar instance -root instance to use. -.It -.Fl c Ar command , -.Fl -command= Ns Ar command -command to execute. -.El diff --git a/appl/su/su.c b/appl/su/su.c deleted file mode 100644 index e61492972..000000000 --- a/appl/su/su.c +++ /dev/null @@ -1,526 +0,0 @@ -/* - * Copyright (c) 1999 - 2008 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of KTH nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -#include - -RCSID("$Id$"); - -#include -#include -#include - -#include - -#ifdef HAVE_PATHS_H -#include -#endif - -#ifdef HAVE_SHADOW_H -#include -#endif - -#include -#ifdef HAVE_CRYPT_H -#include -#endif - -#include "crypto-headers.h" -#ifdef KRB5 -#include -#endif -#include -#include -#include -#include - -#include "supaths.h" - -#if !HAVE_DECL_ENVIRON -extern char **environ; -#endif - -int kerberos_flag = 1; -int csh_f_flag; -int full_login; -int env_flag; -char *kerberos_instance = "root"; -int help_flag; -int version_flag; -char *cmd; -char tkfile[256]; - -struct getargs args[] = { - { "kerberos", 'K', arg_negative_flag, &kerberos_flag, - "don't use kerberos" }, - { NULL, 'f', arg_flag, &csh_f_flag, - "don't read .cshrc" }, - { "full", 'l', arg_flag, &full_login, - "simulate full login" }, - { NULL, 'm', arg_flag, &env_flag, - "leave environment unmodified" }, - { "instance", 'i', arg_string, &kerberos_instance, - "root instance to use" }, - { "command", 'c', arg_string, &cmd, - "command to execute" }, - { "help", 'h', arg_flag, &help_flag }, - { "version", 0, arg_flag, &version_flag }, -}; - - -static void -usage (int ret) -{ - arg_printusage (args, - sizeof(args)/sizeof(*args), - NULL, - "[login [shell arguments]]"); - exit (ret); -} - -static void -free_info(struct passwd *p) -{ - free (p->pw_name); - free (p->pw_passwd); - free (p->pw_dir); - free (p->pw_shell); - free (p); -} - -static struct passwd* -dup_info(const struct passwd *pwd) -{ - struct passwd *info; - - info = malloc(sizeof(*info)); - if(info == NULL) - return NULL; - info->pw_name = strdup(pwd->pw_name); - info->pw_passwd = strdup(pwd->pw_passwd); - info->pw_uid = pwd->pw_uid; - info->pw_gid = pwd->pw_gid; - info->pw_dir = strdup(pwd->pw_dir); - info->pw_shell = strdup(pwd->pw_shell); - if(info->pw_name == NULL || info->pw_passwd == NULL || - info->pw_dir == NULL || info->pw_shell == NULL) { - free_info (info); - return NULL; - } - return info; -} - -#ifdef KRB5 -static krb5_context context; -static krb5_ccache ccache; - -static int -krb5_verify(const struct passwd *login_info, - const struct passwd *su_info, - const char *kerberos_instance) -{ - krb5_error_code ret; - krb5_principal p; - krb5_realm *realms, *r; - char *login_name = NULL; - int user_ok = 0; - -#if defined(HAVE_GETLOGIN) && !defined(POSIX_GETLOGIN) - login_name = getlogin(); -#endif - ret = krb5_init_context (&context); - if (ret) { -#if 0 - warnx("krb5_init_context failed: %d", ret); -#endif - return 1; - } - - ret = krb5_get_default_realms(context, &realms); - if (ret) - return 1; - - /* Check all local realms */ - for (r = realms; *r != NULL && !user_ok; r++) { - - if (login_name == NULL || strcmp (login_name, "root") == 0) - login_name = login_info->pw_name; - if (strcmp (su_info->pw_name, "root") == 0) - ret = krb5_make_principal(context, &p, *r, - login_name, - kerberos_instance, - NULL); - else - ret = krb5_make_principal(context, &p, *r, - su_info->pw_name, - NULL); - if (ret) { - krb5_free_host_realm(context, realms); - return 1; - } - - /* if we are su-ing too root, check with krb5_kuserok */ - if (su_info->pw_uid == 0 && !krb5_kuserok(context, p, su_info->pw_name)) - continue; - - ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache); - if(ret) { - krb5_free_host_realm(context, realms); - krb5_free_principal (context, p); - return 1; - } - ret = krb5_verify_user(context, p, ccache, NULL, TRUE, NULL); - krb5_free_principal (context, p); - switch (ret) { - case 0: - user_ok = 1; - break; - case KRB5_LIBOS_PWDINTR : - krb5_cc_destroy(context, ccache); - break; - case KRB5KRB_AP_ERR_BAD_INTEGRITY: - case KRB5KRB_AP_ERR_MODIFIED: - krb5_cc_destroy(context, ccache); - krb5_warnx(context, "Password incorrect"); - break; - default : - krb5_cc_destroy(context, ccache); - krb5_warn(context, ret, "krb5_verify_user"); - break; - } - } - krb5_free_host_realm(context, realms); - if (!user_ok) - return 1; - return 0; -} - -static int -krb5_start_session(void) -{ - krb5_ccache ccache2; - char *cc_name; - int ret; - - ret = krb5_cc_new_unique(context, krb5_cc_type_file, NULL, &ccache2); - if (ret) { - krb5_cc_destroy(context, ccache); - return 1; - } - - ret = krb5_cc_copy_cache(context, ccache, ccache2); - if (ret) { - krb5_cc_destroy(context, ccache); - krb5_cc_destroy(context, ccache2); - return 1; - } - - ret = asprintf(&cc_name, "%s:%s", krb5_cc_get_type(context, ccache2), - krb5_cc_get_name(context, ccache2)); - if (ret == -1) { - krb5_cc_destroy(context, ccache); - krb5_cc_destroy(context, ccache2); - errx(1, "malloc - out of memory"); - } - esetenv("KRB5CCNAME", cc_name, 1); - - /* convert creds? */ - if(k_hasafs()) { - if (k_setpag() == 0) - krb5_afslog(context, ccache2, NULL, NULL); - } - - krb5_cc_close(context, ccache2); - krb5_cc_destroy(context, ccache); - return 0; -} -#endif - - -#define GROUP_MEMBER 0 -#define GROUP_MISSING 1 -#define GROUP_EMPTY 2 -#define GROUP_NOT_MEMBER 3 - -static int -group_member_p(const char *group, const char *user) -{ - struct group *g; - int i; - g = getgrnam(group); - if(g == NULL) - return GROUP_MISSING; - if(g->gr_mem[0] == NULL) - return GROUP_EMPTY; - for(i = 0; g->gr_mem[i] != NULL; i++) - if(strcmp(user, g->gr_mem[i]) == 0) - return GROUP_MEMBER; - return GROUP_NOT_MEMBER; -} - -static int -verify_unix(struct passwd *login, struct passwd *su) -{ - char prompt[128]; - char pw_buf[1024]; - char *pw; - int r; - if(su->pw_passwd != NULL && *su->pw_passwd != '\0') { - snprintf(prompt, sizeof(prompt), "%s's password: ", su->pw_name); - r = UI_UTIL_read_pw_string(pw_buf, sizeof(pw_buf), prompt, 0); - if(r != 0) - exit(0); - pw = crypt(pw_buf, su->pw_passwd); - memset(pw_buf, 0, sizeof(pw_buf)); - if(strcmp(pw, su->pw_passwd) != 0) { - syslog (LOG_ERR | LOG_AUTH, "%s to %s: incorrect password", - login->pw_name, su->pw_name); - return 1; - } - } - /* if su:ing to root, check membership of group wheel or root; if - that group doesn't exist, or is empty, allow anyone to su - root */ - if(su->pw_uid == 0) { -#ifndef ROOT_GROUP -#define ROOT_GROUP "wheel" -#endif - int gs = group_member_p(ROOT_GROUP, login->pw_name); - if(gs == GROUP_NOT_MEMBER) { - syslog (LOG_ERR | LOG_AUTH, "%s to %s: not in group %s", - login->pw_name, su->pw_name, ROOT_GROUP); - return 1; - } - return 0; - } - return 0; -} - -int -main(int argc, char **argv) -{ - int i, optind = 0; - char *su_user; - struct passwd *su_info; - struct passwd *login_info; - - struct passwd *pwd; - - char *shell; - - int ok = 0; - - setprogname (argv[0]); - - if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optind)) - usage(1); - - for (i=0; i < optind; i++) - if (strcmp(argv[i], "-") == 0) { - full_login = 1; - break; - } - - if(help_flag) - usage(0); - if(version_flag) { - print_version(NULL); - exit(0); - } - if(optind >= argc) - su_user = "root"; - else - su_user = argv[optind++]; - - if (!issuid() && getuid() != 0) - warnx("Not setuid and you are not root, expect this to fail"); - - pwd = k_getpwnam(su_user); - if(pwd == NULL) - errx (1, "unknown login %s", su_user); - if (pwd->pw_uid == 0 && strcmp ("root", su_user) != 0) { - syslog (LOG_ALERT, "NIS attack, user %s has uid 0", su_user); - errx (1, "unknown login %s", su_user); - } - su_info = dup_info(pwd); - if (su_info == NULL) - errx (1, "malloc: out of memory"); - - pwd = getpwuid(getuid()); - if(pwd == NULL) - errx(1, "who are you?"); - login_info = dup_info(pwd); - if (login_info == NULL) - errx (1, "malloc: out of memory"); - if(env_flag) - shell = login_info->pw_shell; - else - shell = su_info->pw_shell; - if(shell == NULL || *shell == '\0') - shell = _PATH_BSHELL; - - -#ifdef KRB5 - if(kerberos_flag && ok == 0 && - krb5_verify(login_info, su_info, kerberos_instance) == 0) - ok = 5; -#endif - - if(ok == 0 && login_info->pw_uid && verify_unix(login_info, su_info) != 0) { - printf("Sorry!\n"); - exit(1); - } - -#ifdef HAVE_GETSPNAM - { struct spwd *sp; - long today; - - sp = getspnam(su_info->pw_name); - if (sp != NULL) { - today = time(0)/(24L * 60 * 60); - if (sp->sp_expire > 0) { - if (today >= sp->sp_expire) { - if (login_info->pw_uid) - errx(1,"Your account has expired."); - else - printf("Your account has expired."); - } - else if (sp->sp_expire - today < 14) - printf("Your account will expire in %d days.\n", - (int)(sp->sp_expire - today)); - } - if (sp->sp_max > 0) { - if (today >= sp->sp_lstchg + sp->sp_max) { - if (login_info->pw_uid) - errx(1,"Your password has expired. Choose a new one."); - else - printf("Your password has expired. Choose a new one."); - } - else if (today >= sp->sp_lstchg + sp->sp_max - sp->sp_warn) - printf("Your account will expire in %d days.\n", - (int)(sp->sp_lstchg + sp->sp_max -today)); - } - } - } -#endif - { - char *tty = ttyname (STDERR_FILENO); - syslog (LOG_NOTICE | LOG_AUTH, tty ? "%s to %s on %s" : "%s to %s", - login_info->pw_name, su_info->pw_name, tty); - } - - - if(!env_flag) { - if(full_login) { - char *t = getenv ("TERM"); - char **newenv = NULL; - int i, j; - - i = read_environment(_PATH_ETC_ENVIRONMENT, &newenv); - - environ = malloc ((10 + i) * sizeof (char *)); - if (environ == NULL) - err (1, "malloc"); - environ[0] = NULL; - - for (j = 0; j < i; j++) { - char *p = strchr(newenv[j], '='); - if (p == NULL) - errx(1, "enviroment '%s' missing '='", newenv[j]); - *p++ = 0; - esetenv (newenv[j], p, 1); - } - free(newenv); - - esetenv ("PATH", _PATH_DEFPATH, 1); - if (t) - esetenv ("TERM", t, 1); - if (chdir (su_info->pw_dir) < 0) - errx (1, "no directory"); - } - if (full_login || su_info->pw_uid) - esetenv ("USER", su_info->pw_name, 1); - esetenv("HOME", su_info->pw_dir, 1); - esetenv("SHELL", shell, 1); - } - - { - int i; - char **args; - char *p; - - p = strrchr(shell, '/'); - if(p) - p++; - else - p = shell; - - if (strcmp(p, "csh") != 0) - csh_f_flag = 0; - - args = malloc(((cmd ? 2 : 0) + 1 + argc - optind + 1 + csh_f_flag) * sizeof(*args)); - if (args == NULL) - err (1, "malloc"); - i = 0; - if(full_login) { - if (asprintf(&args[i++], "-%s", p) == -1) - errx (1, "malloc"); - } else - args[i++] = p; - if (cmd) { - args[i++] = "-c"; - args[i++] = cmd; - } - - if (csh_f_flag) - args[i++] = "-f"; - - for (argv += optind; *argv; ++argv) - args[i++] = *argv; - args[i] = NULL; - - if(setgid(su_info->pw_gid) < 0) - err(1, "setgid"); - if (initgroups (su_info->pw_name, su_info->pw_gid) < 0) - err (1, "initgroups"); - if(setuid(su_info->pw_uid) < 0 - || (su_info->pw_uid != 0 && setuid(0) == 0)) - err(1, "setuid"); - -#ifdef KRB5 - if (ok == 5) - krb5_start_session(); -#endif - execve(shell, args, environ); - } - - exit(1); -} diff --git a/appl/telnet/ChangeLog b/appl/telnet/ChangeLog deleted file mode 100644 index 2d30af8e3..000000000 --- a/appl/telnet/ChangeLog +++ /dev/null @@ -1,831 +0,0 @@ -2008-04-27 Love Hörnquist Åstrand - - * libtelnet/enc_des.c: Use RAND_bytes() + DES_is_weak_key() to - generate random DES key. Introdunce random by feeding the des - session key into the random pool when the keys is recived instead - of encrypt the random key with the kerberos key. - - This avoid depenency on DES_new_random_key() that doesn't exists - in OpenSSL. - -2008-04-18 Love Hörnquist Åstrand - - * libtelnet/enc_des.c: No need to call - DES_init_random_number_generator, hcrypto is sane now. - - * libtelnet/enc_des.c: Use DES_new_random_key(). - -2008-04-10 Love Hörnquist Åstrand - - * telnetd/sys_term.c: Really, mac os uses wtmpx (or asl). - -2008-03-09 Love Hörnquist Åstrand - - * telnetd/sys_term.c: Dont need to set this as the controlling PTY - on steams sockets, don't abort on failure. From Harald Barth and - Ian Delahorne. - -2007-12-31 Love Hörnquist Åstrand - - * telnetd/sys_term.c: Use strlcpy instead of strncpy, thanks to - Antoine Brodin. - -2007-07-31 Love Hörnquist Åstrand - - * telnetd/telnetd.c (usage): use exit_code, add --version and - --help. - - * telnetd/telnetd.c: Add --help, reported by David Love. - -2007-07-30 Love Hörnquist Åstrand - - * telnet/main.c: Catch --help, reported by David Love. - -2007-07-12 Love Hörnquist Åstrand - - * telnetd/sys_term.c: GLIBC made the choice that ut_tv should be - shared between 32 and 64 bit platforms so now we can no longer use - struct timeval functions to compare or set/get data that uses - pointer (gettimeofday for example) since ut_tv is now not a struct - timeval but rather a struct { int32_t tv_sec; int32_t tv_usec; }; - -2006-10-21 Love Hörnquist Åstrand - - * telnet/telnet_locl.h: Include roken.h before the local - headerfiles. - - * telnetd/telnetd.h: HP/UX defines SE in sys/uio.h, #undef it. - - * telnetd/sys_term.c: Dont't include some streamspty headers here. - - * telnetd/telnetd.c: Dont't include some streamspty headers here. - - * telnetd/telnetd.h: includes some STREAMSPTY header here to avoid - ioctl vs socket_wrapper horror. - -2006-10-20 Love Hörnquist Åstrand - - * telnet/Makefile.am: more files - - * telnetd/Makefile.am: more files - -2006-09-19 Love Hörnquist Åstrand - - * telnetd/telnetd.8: Add documentation for -e, require encryption. - - * telnetd/telnetd.h: Add require_encryption. - - * telnetd/telnetd.c: Allow encryption to be required, wait to the - client to turn it on, if failes, refuse the connection. - - * telnetd/state.c: If encryption is required, don't allow it to be - turned off. - -2006-09-04 Love Hörnquist Åstrand - - * libtelnet/kerberos5.c (kerberos5_forward): use KDCOptions2int on - flags before passing them to krb5_get_forwarded_creds. - -2006-05-05 Love Hörnquist Åstrand - - * Rename u_intXX_t to uintXX_t - -2006-03-23 Love Hörnquist Åstrand - - * libtelnet/encrypt.c: Spelling. - -2005-12-01 Love Hörnquist Åstrand - - * telnetd/telnetd.c: Initialize the slc mapping table before its - used. Based on bug report from Russell Sanford - - -2005-11-03 Love Hörnquist Åstrand - - * telnet/telnet.c: Spelling in comments, from Dave Love - - -2005-10-31 Love Hörnquist Åstrand - - * libtelnet/kerberos5.c (Data): Use right variable. From Tomas - Olsson - -2005-10-22 Love Hörnquist Åstrand - - * telnet/commands.c: Check return value from asprintf instead of - string != NULL since it undefined behavior on Linux. From Björn - Sandell - - * libtelnet/kerberos5.c: Check return value from asprintf instead - of string != NULL since it undefined behavior on Linux. From Björn - Sandell - - * libtelnet/kerberos.c: Check return value from asprintf instead - of string != NULL since it undefined behavior on Linux. From Björn - Sandell - -2005-08-08 Love Hörnquist Åstrand - - * telnetd/telnetd.c: Fix printing of /etc/issue{,.net}. - - * telnetd/utility.c: make writenet take const void * and size_t, - abort if size it too large - - * telnetd/state.c: Fix ansi c warning. - - * telnetd/sys_term.c: no need to typecast argument to writenet - - * telnetd/ext.h: make writenet take const void * and size_t - -2005-07-07 Assar Westerlund - - * libtelnet/kerberos.c: Do not assume that des_key_schedule is an - array. - -2005-05-27 Love Hörnquist Åstrand - - * libtelnet/kerberos5.c: case uid_t to unsigned long in printf - format - - * telnetd/sys_term.c (set_termbuf): use {} around if to make else - unambiguous - -2005-05-20 Love Hörnquist Åstrand - - * telnetd/sys_term.c (start_login): put utmpx code into a new - scope to avoid pre c99 problems. - -2005-05-19 Dave Love - - * telnet/telnet.c,telnet_locl.h: Make solaris find tgetent - -2005-05-13 Johan Danielsson - - * telnetd/sys_term.c (start_login): set encryption pointers to - NULL, so we don't try to do either - -2005-05-11 Dave Love - - * telnet/telnet.c: undef ISASCII before we define our own (problem - on Irix) - -2005-04-28 Johan Danielsson - - * telnetd/utility.c (putf): %t: the regular and streamspty case - are functionally equivalent, so merge them, this also makes it - work better on machines that puts their devices in a subdirectory - to /dev - -2005-04-27 Dave Love - - * telnetd/sys_term.c (getpty): Declare p. - -2005-04-25 Love Hörnquist Åstrand - - * telnetd/telnetd.c: use strlcpy - -2005-04-24 Love Hörnquist Åstrand - - * telnetd/global.c, telnetd/state.c, telnetd/telnetd.c, - telentd/ext.h: remove another strcpy - -2005-04-19 Love Hörnquist Åstrand - - * telnetd/sys_term.c: rewrite getpty to make use openpty when its - found, save the slave fd so that cleanopen can use it if its - available - -2005-04-07 Love Hörnquist Åstrand - - * telnetd/sys_term.c: clean_ttyname might be unused, mark it so - with __attribute__ - -2005-04-06 Love Hörnquist Åstrand - - * telnetd/sys_term.c: use NULL as last argument to execl, not 0 - - * telnet/commands.c: use NULL as last argument to execl, not 0 - -2005-03-29 Love Hörnquist Åstrand - - * telnet/telnet.c: From FreeBSD: - - Correct a pair of buffer overflows in the telnet(1) command: - - (CAN-2005-0468) A heap buffer overflow in env_opt_add() and related - functions. - - (CAN-2005-0469) A global uninitialized data section buffer overflow in - slc_add_reply() and related functions. - - As a result of these vulnerabilities, it may be possible for a - malicious telnet server or active network attacker to cause - telnet(1) to execute arbitrary code with the privileges of the - user running it. - - Security: CAN-2005-0468, CAN-2005-0469 Security: - FreeBSD-SA-05:01.telnet Security: - http://www.idefense.com/application/poi/display?id=220&type=vulnerabilities - Security: - http://www.idefense.com/application/poi/display?id=221&type=vulnerabilities - - These fixes are based in part on patches Submitted by: Solar - Designer - -2005-03-23 Love Hörnquist Åstrand - - * telnetd/telnetd.c: remove setting of DES_check_key, all code - uses DES_set_key_checked - - * libtelnet/enc_des.c: use DES_set_key_checked - -2005-01-09 Love Hörnquist Åstrand - - * telnet/telnet.c: cast argument to toupper to unsigned char - - * telnet/commands.c: cast argument to is* to unsigned char - -2004-06-20 Love Hörnquist Åstrand - - * telnet/network.c: make network rings larger From: MAAAAA MOOOR - - - * telnetd/state.c: make subbuffer larger XXX resize dynamicly - From: MAAAAA MOOOR - - * libtelnet/kerberos5.c (Data): allocate the data needed to be - send From: MAAAAA MOOOR - -2004-04-02 Love Hörnquist Åstrand - - * telnet/main.c: make encrypt, forwardable, forward use appdefault - (that also searches libdefaults), prompted by Thomas Nystrom - - -2004-03-22 Love Hörnquist Åstrand - - * telnetd/telnetd.c: call setprogname to make libvers happy - - * telnet/main.c: call setprogname to make libvers happy - -2003-09-25 Love Hörnquist Åstrand - - * telnet/externs.h: export Scheduler and scheduler_lockout_tty - - * telnet/telnet.c (my_telnet): if telnet_spin returns failure, - complain that the server disconnected and exit - - * telnet/authenc.c (telnet_spin): if Scheduler() returns failure - (-1) propagate to higher level - -2003-09-03 Love Hörnquist Åstrand - - * telnetd/telnetd.c: use new DES_ api - - * libtelnet/enc_des.c: use new DES_ api - -2003-04-22 Love Hörnquist Åstrand - - * telnet/telnet.1: replace <,> with \*[Lt],\*[Gt] - -2002-09-02 Johan Danielsson - - * libtelnet/kerberos5.c: set AP_OPTS_USE_SUBKEY - -2002-08-28 Johan Danielsson - - * telnet/commands.c: remove extra "Toggle"'s - - * telnet/commands.c: IRIX == 4 -> IRIX4 - - * telnet/main.c: rename functions to what they're really called - - * telnet/commands.c: kill some might be uninitialized warnings - - * telnet/commands.c: add forward and forwardable toggle options, - and call set_forward_options() after parsing .telnetrc - - * telnet/externs.h: proto for set_forward_options - - * telnet/main.c: only register what forwarding options are asked - for when parsing command line, we have to set the actual flags - later after we have read .telnetrc - - * libtelnet/auth-proto.h: kerberos5_set_forward{,able} protos - - * libtelnet/kerberos5.c: add kerberos5_set_forward{,able} - functions suitable for the command parser - -2002-08-23 Assar Westerlund - - * telnetd/telnetd.c: add --version as a special case - * telnet/main.c: add --version as a special case - -2002-05-03 Johan Danielsson - - * telnet/telnet.c: only try to negotiate encryption if we're - talking to a real telnet - -2002-03-31 Johan Danielsson - - * telnet/commands.c: fix an old cut-n-paste typo (via debian) - -2002-02-07 Johan Danielsson - - * telnet/telnet.c: print a more informative message than "done" - after negotiating encryption - -2001-09-17 Assar Westerlund - - * telnetd/telnetd.c: add a kludge to make it build on aix (that - defines NOERROR in both sys/stream.h and arpa/nameser.h and - considers that a fatal error) - - * telnet/telnet.c: undef PUTSHORT to avoid conflict - -2001-08-26 Assar Westerlund - - * telnetd/Makefile.am: also link with the library for logout - -2001-08-22 Assar Westerlund - - * telnetd/sys_term.c: include libutil.h if it exists - -2001-08-10 Assar Westerlund - - * telnetd/sys_term.c (getpty): call openpty if it exists - -2001-07-19 Assar Westerlund - - * telnetd/global.c (output_data): make sure of not forwarding - `nfrontp' too far, thereby allowing writes after the end of - `netobuf' - -2001-06-18 Assar Westerlund - - * libtelnet/kerberos5.c: update to new krb5_auth_con* names - -2001-04-25 Assar Westerlund - - * telnetd/sys_term.c (start_login): give the correct error if exec - fails - * telnetd/utility.c (fatalperror_errno): add a new function with - explicit errno parameter - -2001-03-07 Assar Westerlund - - * telnetd/sys_term.c: some minimal more amount of - const-correctness - -2001-02-24 Assar Westerlund - - * libtelnet/enc_des.c: learn to live with libcrypto (from openssl) - -2001-02-20 Assar Westerlund - - * telnet/commands.c (tn): copy the hostname so it doesn't get - overwritten while reading ~/.telnetrc - (*): removed some unneeded externs - -2001-02-08 Assar Westerlund - - * telnetd/sys_term.c (startslave, start_login): re-write code to - keep track both of remote hostname and utmp string to be used - * telnetd/telnetd.c (doit, my_telnet): re-write code to keep track - both of remote hostname and utmp string to be used - -2001-02-07 Assar Westerlund - - * telnet/Makefile.am, telnetd/Makefile.am: add LIB_kdfs - -2001-01-09 Assar Westerlund - - * libtelnet/kerberos5.c (kerberos5_is): use krb5_rd_cred2 instead - of krb5_rd_cred - -2000-12-31 Assar Westerlund - - * telnet/main.c (krb5_init): check krb5_init_context for success - * libtelnet/kerberos5.c (kerberos5_init): check krb5_init_context - for success - -2000-12-11 Assar Westerlund - - * telnet/commands.c (sourceroute): make it not break if the - rfc2292 api does not exist - -2000-12-09 Assar Westerlund - - * telnetd/sys_term.c (scrub_env): add supporting non-file TERMCAP - variables - -2000-12-07 Assar Westerlund - - * telnetd/telnetd.h: move include files around to avoid getting SE - from sys/*.h on HP to override SE from telnet.h - - * telnetd/sys_term.c (scrub_env): remove some const-ness - * telnetd/sys_term.c (scrub_env): add LOGNAME and POSIXLY_CORRECT - to the list of authorized environment variables to be compatible - with linux-telnetd - - * telnetd/sys_term.c (scrub_env): change filtering algoritm from - allowing everything except a few bad cases to not allowing - anything except a few non-dangerous cases - -2000-12-06 Johan Danielsson - - * libtelnet/kerberos5.c: de-pointerise auth_context parameter to - krb5_mk_rep - -2000-11-23 Johan Danielsson - - * libtelnet/kerberos5.c: print the principal we're trying to use - - * libtelnet/kerberos.c: print the principal we're trying to use - -2000-11-16 Assar Westerlund - - * libtelnet/misc-proto.h (telnet_getenv): const-ize some - -2000-11-08 Johan Danielsson - - * telnet/telnet.c: fake entry if no tgetent - -2000-10-08 Assar Westerlund - - * telnetd/utility.c (stilloob): check that fds are not too large - to select on - (ttloop): remove confusing output of errno - * telnetd/telnetd.c (my_telnet): check that fds are not too large - to select on - * telnet/utilities.c (EmptyTerminal): check that fds are not too - large to select on - * telnet/sys_bsd.c (process_rings): check that fds are not too - large to select on - * telnet/network.c (stilloob): check that fds are not too large to - select on - -2000-06-09 Assar Westerlund - - * telnet/commands.c: remove all setuid(getuid()). we do not - support telnet being setuid root - -2000-05-05 Assar Westerlund - - * telnet/externs.h (sourceroute): update prototype - * telnet/commands.c (tn): re-enable source routing - (sourceroute): make it work again based on the code from - itojun@kame.net - -2000-03-28 Assar Westerlund - - * telnet/commands.c (tn): clean-up a tiny little bit. give-up if - we do not manage to connect to any address - -2000-03-26 Assar Westerlund - - * telnetd/sys_term.c (*): make sure to always call time, ctime, - and gmtime with `time_t's. there were some types (like in - lastlog) that we believed to always be time_t. this has proven - wrong on Solaris 8 in 64-bit mode, where they are stored as 32-bit - quantities but time_t has gone up to 64 bits - -2000-03-03 Assar Westerlund - - * libtelnet/kerberos5.c (kerberos5_init): check that we do have a - keytab before saying that we will support KERBEROS5 - -2000-02-12 Assar Westerlund - - * telnet/commands.c (tn): only set tos for AF_INET. From - itojun@iijlab.net - -2000-02-07 Assar Westerlund - - * libtelnet/kerberos.c (kerberos4_is): send a reject back to the - client when we're not authorized - -2000-02-06 Assar Westerlund - - * telnet/ring.h (ring_encrypt): better proto - * telnet/ring.c (ring_encrypt): better proto - -2000-02-04 Assar Westerlund - - * telnet/telnet_locl.h: klduge-around KLUDGELINEMODE - -2000-01-18 Assar Westerlund - - * libtelnet/misc.c (auth_encrypt_user): const-ify - * libtelnet/misc.h (RemoteHostName, LocalHostName): const-ify - * libtelnet/misc.c (auth_encrypt_init, RemoteHostName, - LocalHostName): const-ify - * libtelnet/misc-proto.h (auth_encrypt_init, auth_encrypt_user): - const-ify - * libtelnet/encrypt.c (encrypt_init, Name): const-ify - * libtelnet/enc-proto.h (encrypt_init): const-ify - * libtelnet/auth.c (auth_init, Name): const-ify - * libtelnet/auth-proto.h (auth_init): const-ify - -2000-01-08 Assar Westerlund - - * telnet/commands.c (tn): handle ai_canonname being set in any of - the addresses returnedby getaddrinfo. glibc apparently returns - the reverse lookup of every address in ai_canonname. remove some - unused variables. - -2000-01-01 Assar Westerlund - - * telnetd/sys_term.c (addarg): make void (return value isn't check - anyway). fatal error when malloc fails - -1999-12-16 Assar Westerlund - - * telnet/commands.c (*): handle ai_canonname not being set - -1999-12-04 Assar Westerlund - - * telnetd/telnetd.c (doit): use getnameinfo_verified - * telnetd/telnetd.c: use getnameinfo - * telnet/commands.c: re-write to using getaddrinfo. disable - source-routing for the moment, it doesn't seem to be used anyways. - -1999-09-16 Assar Westerlund - - * telnet/commands.c: revert 1.54, get_default_username should DTRT - now - -1999-09-05 Assar Westerlund - - * telnetd/utility.c (ttloop): make it return 1 if interrupted by a - signal, which must have been what was meant from the beginning - - * telnetd/ext.h (ttloop): update prototype - - * telnetd/authenc.c (telnet_spin): actually return the value from - ttloop (otherwise it's kind of bogus) - -1999-08-05 Assar Westerlund - - * telnetd/sys_term.c (rmut): free utxp - -1999-08-04 Assar Westerlund - - * telnet/main.c: add -G and config file support. From Miroslav - Ruda - - * telnetd/sys_term.c (rmut): work around utmpx strangness. From - Miroslav Ruda - -1999-08-02 Assar Westerlund - - * telnetd/telnetd.c (doit): only free hp if != NULL. From: Jonas - Oberg - -1999-07-29 Assar Westerlund - - * telnetd/telnetd.c (doit): remove unused variable mapped_sin - -1999-07-26 Assar Westerlund - - * telnetd/ext.h: update prototypes - - * telnetd/telnetd.c: make it handle v4 and v6 sockets. (it - doesn't handle being given a v6 socket that's really talking to an - v4 adress (mapped) because the rest of the code in telnetd is not - able to handle it anyway). please run two telnetd from your - inetd, one for v4 and one for v6. - -1999-07-07 Assar Westerlund - - * telnet/commands.c (tn): extra bogus const-cast - -1999-07-06 Assar Westerlund - - * telnetd/sys_term.c (start_login): print a different warning with - `-a otp' - -1999-06-24 Assar Westerlund - - * libtelnet/kerberos5.c (kerberos5_send): set the addresses in the - auth_context - -1999-06-23 Assar Westerlund - - * telnet/Makefile.am (INCLUDES): add $(INCLUDE_krb4) - - * telnet/commands.c (togkrbdebug): conditionalize on - krb_disable_debug - -1999-06-16 Johan Danielsson - - * telnet/commands.c: add kerberos debugging option - -1999-06-15 Assar Westerlund - - * telnet/commands.c (tn): use get_default_username - -1999-05-14 Assar Westerlund - - * telnetd/state.c (telrcv): magic patch to make it work against - DOS Clarkson Telnet. From Miroslav Ruda - -1999-04-25 Assar Westerlund - - * libtelnet/kerberos5.c (kerberos5_send): use - `krb5_auth_setkeytype' instead of `krb5_auth_setenctype' to make - sure we get a DES session key. - -Thu Apr 1 16:59:27 1999 Johan Danielsson - - * telnetd/Makefile.am: don't run check-local - - * telnet/Makefile.am: don't run check-local - -Mon Mar 29 16:11:33 1999 Johan Danielsson - - * telnetd/sys_term.c: _CRAY -> HAVE_STRUCT_UTMP_UT_ID - -Sat Mar 20 00:12:54 1999 Assar Westerlund - - * telnet/authenc.c (telnet_gets): remove old extern declarations - -Thu Mar 18 11:20:16 1999 Johan Danielsson - - * telnetd/Makefile.am: include Makefile.am.common - - * telnet/Makefile.am: include Makefile.am.common - - * libtelnet/Makefile.am: include Makefile.am.common - - * Makefile.am: include Makefile.am.common - -Mon Mar 15 17:40:53 1999 Johan Danielsson - - * telnetd/telnetd.c: replace perror/exit with fatalperror - -Sat Mar 13 22:18:57 1999 Assar Westerlund - - * telnetd/telnetd.c (main): 0 -> STDIN_FILENO. remove abs - - * libtelnet/kerberos.c (kerberos4_is): syslog root logins - -Thu Mar 11 14:48:54 1999 Johan Danielsson - - * telnetd/Makefile.in: add WFLAGS - - * telnet/Makefile.in: add WFLAGS - - * libtelnet/Makefile.in: add WFLAGS - - * telnetd/sys_term.c: remove unused variables - - * telnet/telnet.c: fix some warnings - - * telnet/main.c: fix some warnings - - * telnet/commands.c: fix types in format string - - * libtelnet/auth.c: fix types in format string - -Mon Mar 1 10:50:30 1999 Johan Danielsson - - * telnetd/sys_term.c: HAVE_UT_* -> HAVE_STRUCT_UTMP*_UT_* - -Mon Feb 1 04:08:36 1999 Assar Westerlund - - * telnet/commands.c (tn): only call gethostbyname2 with AF_INET6 - if we actually have IPv6. From "Brandon S. Allbery KF8NH" - - -Sat Nov 21 16:51:00 1998 Johan Danielsson - - * telnetd/sys_term.c (cleanup): don't call vhangup() on sgi:s - -Fri Aug 14 16:29:18 1998 Johan Danielsson - - * libtelnet/kerberos.c: krb_put_int -> KRB_PUT_INT - -Thu Jul 23 20:29:05 1998 Johan Danielsson - - * libtelnet/kerberos5.c: use krb5_verify_authenticator_checksum - -Mon Jul 13 22:00:09 1998 Assar Westerlund - - * telnet/commands.c (tn): don't advance hostent->h_addr_list, use - a copy instead - -Wed May 27 04:19:17 1998 Assar Westerlund - - * telnet/sys_bsd.c (process_rings): correct call to `stilloob' - -Fri May 15 19:38:19 1998 Johan Danielsson - - * libtelnet/kerberos5.c: Always print errors from mk_req. - -Fri May 1 07:16:59 1998 Assar Westerlund - - * telnet/commands.c: unifdef -DHAVE_H_ERRNO - -Sat Apr 4 15:00:29 1998 Assar Westerlund - - * telnet/commands.c (tn): moved the printing of `trying...' to the - loop - -Thu Mar 12 02:33:48 1998 Assar Westerlund - - * telnet/telnet_locl.h: include . From Gregory S. Stark - - -Sat Feb 21 15:12:38 1998 Assar Westerlund - - * telnetd/ext.h: add prototype for login_tty - - * telnet/utilities.c (printsub): `direction' is now an int. - - * libtelnet/misc-proto.h: add prototype for `printsub' - -Tue Feb 17 02:45:01 1998 Assar Westerlund - - * libtelnet/kerberos.c (kerberos4_is): cred.pname should be - cred.pinst. From - -Sun Feb 15 02:46:39 1998 Assar Westerlund - - * telnet/*/*.c: renamed `telnet' to `my_telnet' to avoid - conflicts with system header files on mklinux. - -Tue Feb 10 02:09:03 1998 Assar Westerlund - - * telnetd/telnetd.c: new signature for `getterminaltype' and - `auth_wait' - - * libtelnet: changed the signature of the authentication method - `status' - -Sat Feb 7 07:21:29 1998 Assar Westerlund - - * */*.c: replace HAS_GETTOS by HAVE_PARSETOS and HAVE_GETTOSBYNAME - -Fri Dec 26 16:17:10 1997 Assar Westerlund - - * telnet/commands.c (tn): repair support for numeric addresses - -Sun Dec 21 09:40:31 1997 Assar Westerlund - - * libtelnet/kerberos.c: fix up lots of stuff related to the - forwarding of v4 tickets. - - * libtelnet/kerberos5.c (kerberos5_forward): zero out `creds'. - -Mon Dec 15 20:53:13 1997 Johan Danielsson - - * telnet/sys_bsd.c: Don't turn off OPOST in 8bit-mode. - -Tue Dec 9 19:26:50 1997 Assar Westerlund - - * telnet/main.c (main): add 'b' to getopt - -Sat Nov 29 03:28:54 1997 Johan Danielsson - - * telnet/telnet.c: Change binary mode to do just that, and add a - eight-bit mode for just passing all characters. - -Sun Nov 16 04:37:02 1997 Assar Westerlund - - * libtelnet/kerberos5.c (kerberos5_send): always ask for a session - key of type DES - - * libtelnet/kerberos5.c: remove old garbage and fix call to - krb5_auth_con_setaddrs_from_fd - -Fri Nov 14 20:35:18 1997 Johan Danielsson - - * telnetd/telnetd.c: Output contents of /etc/issue. - -Mon Nov 3 07:09:16 1997 Assar Westerlund - - * telnet/telnet_locl.h: only include iff - !defined(HAVE_TERMIOS_H) - - * libtelnet/kerberos.c (kerberos4_is): send the peer address to - krb_rd_req - - * telnetd/telnetd.c (terminaltypeok): always return OK. It used - to call `tgetent' to figure if it was a defined terminal type. - It's possible to overflow tgetent so that's a bad idea. The worst - that could happen by saying yes to all terminals is that the user - ends up with a terminal that has no definition on the local - system. And besides, most telnet client has no support for - falling back to a different terminal type. - -Mon Oct 20 05:47:19 1997 Assar Westerlund - - * libtelnet/kerberos5.c: remove lots of old junk. clean-up. - better error checking and reporting. tell the user permission - denied much earlier. - - * libtelnet/kerberos.c (kerberos4_is): only print - UserNameRequested if != NULL - diff --git a/appl/telnet/Makefile.am b/appl/telnet/Makefile.am deleted file mode 100644 index 88493594d..000000000 --- a/appl/telnet/Makefile.am +++ /dev/null @@ -1,11 +0,0 @@ -# $Id$ - -include $(top_srcdir)/Makefile.am.common - -SUBDIRS = libtelnet telnet telnetd - -dist-hook: - $(mkinstalldirs) $(distdir)/arpa - $(INSTALL_DATA) $(srcdir)/arpa/telnet.h $(distdir)/arpa - -EXTRA_DIST = README.ORIG telnet.state diff --git a/appl/telnet/README.ORIG b/appl/telnet/README.ORIG deleted file mode 100644 index 37b588faf..000000000 --- a/appl/telnet/README.ORIG +++ /dev/null @@ -1,743 +0,0 @@ - -This is a distribution of both client and server telnet. These programs -have been compiled on: - telnet telnetd - 4.4 BSD-Lite x x - 4.3 BSD Reno X X - UNICOS 9.1 X X - UNICOS 9.0 X X - UNICOS 8.0 X X - BSDI 2.0 X X - Solaris 2.4 x x (no linemode in server) - SunOs 4.1.4 X X (no linemode in server) - Ultrix 4.3 X X (no linemode in server) - Ultrix 4.1 X X (no linemode in server) - -In addition, previous versions have been compiled on the following -machines, but were not available for testing this version. - telnet telnetd - Next1.0 X X - UNICOS 8.3 X X - UNICOS 7.C X X - UNICOS 7.0 X X - SunOs 4.0.3c X X (no linemode in server) - 4.3 BSD X X (no linemode in server) - DYNIX V3.0.12 X X (no linemode in server) - Ultrix 3.1 X X (no linemode in server) - Ultrix 4.0 X X (no linemode in server) - SunOs 3.5 X X (no linemode in server) - SunOs 4.1.3 X X (no linemode in server) - Solaris 2.2 x x (no linemode in server) - Solaris 2.3 x x (no linemode in server) - BSDI 1.0 X X - BSDI 1.1 X X - DYNIX V3.0.17.9 X X (no linemode in server) - HP-UX 8.0 x x (no linemode in server) - -This code should work, but there are no guarantees. - -May 30, 1995 - -This release represents what is on the 4.4BSD-Lite2 release, which -should be the final BSD release. I will continue to support of -telnet, The code (without encryption) is available via anonymous ftp -from ftp.cray.com, in src/telnet/telnet.YY.MM.DD.NE.tar.Z, where -YY.MM.DD is replaced with the year, month and day of the release. -If you can't find it at one of these places, at some point in the -near future information about the latest releases should be available -from ftp.borman.com. - -In addition, the version with the encryption code is available via -ftp from net-dist.mit.edu, in the directory /pub/telnet. There -is a README file there that gives further information on how -to get the distribution. - -Questions, comments, bug reports and bug fixes can be sent to -one of these addresses: - dab@borman.com - dab@cray.com - dab@bsdi.com - -This release is mainly bug fixes and code cleanup. - - Replace all calls to bcopy()/bzero() with calls to - memmove()/memset() and all calls to index()/rindex() - with calls to strchr()/strrchr(). - - Add some missing diagnostics for option tracing - to telnetd. - - Add support for BSDI 2.0 and Solaris 2.4. - - Add support for UNICOS 8.0 - - Get rid of expanded tabs and trailing white spaces. - - From Paul Vixie: - Fix for telnet going into an endless spin - when the session dies abnormally. - - From Jef Poskanzer: - Changes to allow telnet to compile - under SunOS 3.5. - - From Philip Guenther: - makeutx() doesn't expand utmpx, - use pututxline() instead. - - From Chris Torek: - Add a sleep(1) before execing login - to avoid race condition that can eat - up the login prompt. - Use terminal speed directly if it is - not an encoded value. - - From Steve Parker: - Fix to realloc() call. Fix for execing - login on solaris with no user name. - -January 19, 1994 - -This is a list of some of the changes since the last tar release -of telnet/telnetd. There are probably other changes that aren't -listed here, but this should hit a lot of the main ones. - - General: - Changed #define for AUTHENTICATE to AUTHENTICATION - Changed #define for ENCRYPT to ENCRYPTION - Changed #define for DES_ENCRYPT to DES_ENCRYPTION - - Added support for SPX authentication: -DSPX - - Added support for Kerberos Version 5 authentication: -DKRB5 - - Added support for ANSI C function prototypes - - Added support for the NEW-ENVIRON option (RFC-1572) - including support for USERVAR. - - Made support for the old Environment Option (RFC-1408) - conditional on -DOLD_ENVIRON - - Added #define ENV_HACK - support for RFC 1571 - - The encryption code is removed from the public distributions. - Domestic 4.4 BSD distributions contain the encryption code. - - ENV_HACK: Code to deal with systems that only implement - the old ENVIRON option, and have reversed definitions - of ENV_VAR and ENV_VAL. Also fixes ENV processing in - client to handle things besides just the default set... - - NO_BSD_SETJMP: UNICOS configuration for - UNICOS 6.1/6.0/5.1/5.0 systems. - - STREAMSPTY: Use /dev/ptmx to get a clean pty. This - is for SVr4 derivatives (Like Solaris) - - UTMPX: For systems that have /etc/utmpx. This is for - SVr4 derivatives (Like Solaris) - - Definitions for BSDI 1.0 - - Definitions for 4.3 Reno and 4.4 BSD. - - Definitions for UNICOS 8.0 and UNICOS 7.C - - Definitions for Solaris 2.0 - - Definitions for HP-UX 8.0 - - Latest Copyright notices from Berkeley. - - FLOW-CONTROL: support for RFC-XXXx - - - Client Specific: - - Fix the "send" command to not send garbage... - - Fix status message for "skiprc" - - Make sure to send NAWS after telnet has been suspended - or an external command has been run, if the window size - has changed. - - sysV88 support. - - Server Specific: - - Support flowcontrol option in non-linemode servers. - - -k Server supports Kludge Linemode, but will default to - either single character mode or real Linemode support. - The user will have to explicitly ask to switch into - kludge linemode. ("stty extproc", or escape back to - to telnet and say "mode line".) - - -u Specify the length of the hostname field in the utmp - file. Hostname longer than this length will be put - into the utmp file in dotted decimal notation, rather - than putting in a truncated hostname. - - -U Registered hosts only. If a reverse hostname lookup - fails, the connection will be refused. - - -f/-F - Allows forwarding of credentials for KRB5. - -Februrary 22, 1991: - - Features: - - This version of telnet/telnetd has support for both - the AUTHENTICATION and ENCRYPTION options. The - AUTHENTICATION option is fairly well defined, and - an option number has been assigned to it. The - ENCRYPTION option is still in a state of flux; an - option number has been assigned to, but it is still - subject to change. The code is provided in this release - for experimental and testing purposes. - - The telnet "send" command can now be used to send - do/dont/will/wont commands, with any telnet option - name. The rules for when do/dont/will/wont are sent - are still followed, so just because the user requests - that one of these be sent doesn't mean that it will - be sent... - - The telnet "getstatus" command no longer requires - that option printing be enabled to see the response - to the "DO STATUS" command. - - A -n flag has been added to telnetd to disable - keepalives. - - A new telnet command, "auth" has been added (if - AUTHENTICATE is defined). It has four sub-commands, - "status", "disable", "enable" and "help". - - A new telnet command, "encrypt" has been added (if - ENCRYPT is defined). It has many sub-commands: - "enable", "type", "start", "stop", "input", - "-input", "output", "-output", "status", and "help". - - The LOGOUT option is now supported by both telnet - and telnetd, a new command, "logout", was added - to support this. - - Several new toggle options were added: - "autoencrypt", "autodecrypt", "autologin", "authdebug", - "encdebug", "skiprc", "verbose_encrypt" - - An "rlogin" interface has been added. If the program - is named "rlogin", or the "-r" flag is given, then - an rlogin type of interface will be used. - ~. Terminates the session - ~ Suspend the session - ~^] Escape to telnet command mode - ~~ Pass through the ~. - BUG: If you type the rlogin escape character - in the middle of a line while in rlogin - mode, you cannot erase it or any characters - before it. Hopefully this can be fixed - in a future release... - - General changes: - - A "libtelnet.a" has now been created. This libraray - contains code that is common to both telnet and - telnetd. This is also where library routines that - are needed, but are not in the standard C library, - are placed. - - The makefiles have been re-done. All of the site - specific configuration information has now been put - into a single "Config.generic" file, in the top level - directory. Changing this one file will take care of - all three subdirectories. Also, to add a new/local - definition, a "Config.local" file may be created - at the top level; if that file exists, the subdirectories - will use that file instead of "Config.generic". - - Many 1-2 line functions in commands.c have been - removed, and just inserted in-line, or replaced - with a macro. - - Bug Fixes: - - The non-termio code in both telnet and telnetd was - setting/clearing CTLECH in the sg_flags word. This - was incorrect, and has been changed to set/clear the - LCTLECH bit in the local mode word. - - The SRCRT #define has been removed. If IP_OPTIONS - and IPPROTO_IP are defined on the system, then the - source route code is automatically enabled. - - The NO_GETTYTAB #define has been removed; there - is a compatability routine that can be built into - libtelnet to achive the same results. - - The server, telnetd, has been switched to use getopt() - for parsing the argument list. - - The code for getting the input/output speeds via - cfgetispeed()/cfgetospeed() was still not quite - right in telnet. Posix says if the ispeed is 0, - then it is really equal to the ospeed. - - The suboption processing code in telnet now has - explicit checks to make sure that we received - the entire suboption (telnetd was already doing this). - - The telnet code for processing the terminal type - could cause a core dump if an existing connection - was closed, and a new connection opened without - exiting telnet. - - Telnetd was doing a TCSADRAIN when setting the new - terminal settings; This is not good, because it means - that the tcsetattr() will hang waiting for output to - drain, and telnetd is the only one that will drain - the output... The fix is to use TCSANOW which does - not wait. - - Telnetd was improperly setting/clearing the ISTRIP - flag in the c_lflag field, it should be using the - c_iflag field. - - When the child process of telnetd was opening the - slave side of the pty, it was re-setting the EXTPROC - bit too early, and some of the other initialization - code was wiping it out. This would cause telnetd - to go out of linemode and into single character mode. - - One instance of leaving linemode in telnetd forgot - to send a WILL ECHO to the client, the net result - would be that the user would see double character - echo. - - If the MODE was being changed several times very - quickly, telnetd could get out of sync with the - state changes and the returning acks; and wind up - being left in the wrong state. - -September 14, 1990: - - Switch the client to use getopt() for parsing the - argument list. The 4.3Reno getopt.c is included for - systems that don't have getopt(). - - Use the posix _POSIX_VDISABLE value for what value - to use when disabling special characters. If this - is undefined, it defaults to 0x3ff. - - For non-termio systems, TIOCSETP was being used to - change the state of the terminal. This causes the - input queue to be flushed, which we don't want. This - is now changed to TIOCSETN. - - Take out the "#ifdef notdef" around the code in the - server that generates a "sync" when the pty oputput - is flushed. The potential problem is that some older - telnet clients may go into an infinate loop when they - receive a "sync", if so, the server can be compiled - with "NO_URGENT" defined. - - Fix the client where it was setting/clearing the OPOST - bit in the c_lflag field, not the c_oflag field. - - Fix the client where it was setting/clearing the ISTRIP - bit in the c_lflag field, not the c_iflag field. (On - 4.3Reno, this is the ECHOPRT bit in the c_lflag field.) - The client also had its interpretation of WILL BINARY - and DO BINARY reversed. - - Fix a bug in client that would cause a core dump when - attempting to remove the last environment variable. - - In the client, there were a few places were switch() - was being passed a character, and if it was a negative - value, it could get sign extended, and not match - the 8 bit case statements. The fix is to and the - switch value with 0xff. - - Add a couple more printoption() calls in the client, I - don't think there are any more places were a telnet - command can be received and not printed out when - "options" is on. - - A new flag has been added to the client, "-a". Currently, - this just causes the USER name to be sent across, in - the future this may be used to signify that automatic - authentication is requested. - - The USER variable is now only sent by the client if - the "-a" or "-l user" options are explicity used, or - if the user explicitly asks for the "USER" environment - variable to be exported. In the server, if it receives - the "USER" environment variable, it won't print out the - banner message, so that only "Password:" will be printed. - This makes the symantics more like rlogin, and should be - more familiar to the user. (People are not used to - getting a banner message, and then getting just a - "Password:" prompt.) - - Re-vamp the code for starting up the child login - process. The code was getting ugly, and it was - hard to tell what was really going on. What we - do now is after the fork(), in the child: - 1) make sure we have no controlling tty - 2) open and initialize the tty - 3) do a setsid()/setpgrp() - 4) makes the tty our controlling tty. - On some systems, #2 makes the tty our controlling - tty, and #4 is a no-op. The parent process does - a gets rid of any controlling tty after the child - is fork()ed. - - Use the strdup() library routine in telnet, instead - of the local savestr() routine. If you don't have - strdup(), you need to define NO_STRDUP. - - Add support for ^T (SIGINFO/VSTATUS), found in the - 4.3Reno distribution. This maps to the AYT character. - You need a 4-line bugfix in the kernel to get this - to work properly: - - > *** tty_pty.c.ORG Tue Sep 11 09:41:53 1990 - > --- tty_pty.c Tue Sep 11 17:48:03 1990 - > *************** - > *** 609,613 **** - > if ((tp->t_lflag&NOFLSH) == 0) - > ttyflush(tp, FREAD|FWRITE); - > ! pgsignal(tp->t_pgrp, *(unsigned int *)data); - > return(0); - > } - > --- 609,616 ---- - > if ((tp->t_lflag&NOFLSH) == 0) - > ttyflush(tp, FREAD|FWRITE); - > ! pgsignal(tp->t_pgrp, *(unsigned int *)data, 1); - > ! if ((*(unsigned int *)data == SIGINFO) && - > ! ((tp->t_lflag&NOKERNINFO) == 0)) - > ! ttyinfo(tp); - > return(0); - > } - - The client is now smarter when setting the telnet escape - character; it only sets it to one of VEOL and VEOL2 if - one of them is undefined, and the other one is not already - defined to the telnet escape character. - - Handle TERMIOS systems that have seperate input and output - line speed settings imbedded in the flags. - - Many other minor bug fixes. - -June 20, 1990: - Re-organize makefiles and source tree. The telnet/Source - directory is now gone, and all the source that was in - telnet/Source is now just in the telnet directory. - - Seperate makefile for each system are now gone. There - are two makefiles, Makefile and Makefile.generic. - The "Makefile" has the definitions for the various - system, and "Makefile.generic" does all the work. - There is a variable called "WHAT" that is used to - specify what to make. For example, in the telnet - directory, you might say: - make 4.4bsd WHAT=clean - to clean out the directory. - - Add support for the ENVIRON and XDISPLOC options. - In order for the server to work, login has to have - the "-p" option to preserve environment variables. - - Add the SOFT_TAB and LIT_ECHO modes in the LINEMODE support. - - Add the "-l user" option to command line and open command - (This is passed through the ENVIRON option). - - Add the "-e" command line option, for setting the escape - character. - - Add the "-D", diagnostic, option to the server. This allows - the server to print out debug information, which is very - useful when trying to debug a telnet that doesn't have any - debugging ability. - - Turn off the literal next character when not in LINEMODE. - - Don't recognize ^Y locally, just pass it through. - - Make minor modifications for Sun4.0 and Sun4.1 - - Add support for both FORW1 and FORW2 characters. The - telnet escpape character is set to whichever of the - two is not being used. If both are in use, the escape - character is not set, so when in linemode the user will - have to follow the escape character with a or - -libtelnet/Makefile.4.4: -telnet/Makefile.4.4: -telnetd/Makefile.4.4: - These are the makefiles that can be used on a 4.3Reno - system when this software is installed in /usr/src/lib/libtelnet, - /usr/src/libexec/telnetd, and /usr/src/usr.bin/telnet. - - -The following TELNET options are supported: - - LINEMODE: - The LINEMODE option is supported as per RFC1116. The - FORWARDMASK option is not currently supported. - - BINARY: The client has the ability to turn on/off the BINARY - option in each direction. Turning on BINARY from - server to client causes the LITOUT bit to get set in - the terminal driver on both ends, turning on BINARY - from the client to the server causes the PASS8 bit - to get set in the terminal driver on both ends. - - TERMINAL-TYPE: - This is supported as per RFC1091. On the server side, - when a terminal type is received, termcap/terminfo - is consulted to determine if it is a known terminal - type. It keeps requesting terminal types until it - gets one that it recongnizes, or hits the end of the - list. The server side looks up the entry in the - termcap/terminfo data base, and generates a list of - names which it then passes one at a time to each - request for a terminal type, duplicating the last - entry in the list before cycling back to the beginning. - - NAWS: The Negotiate about Window Size, as per RFC 1073. - - TERMINAL-SPEED: - Implemented as per RFC 1079 - - TOGGLE-FLOW-CONTROL: - Implemented as per RFC 1080 - - TIMING-MARK: - As per RFC 860 - - SGA: As per RFC 858 - - ECHO: As per RFC 857 - - LOGOUT: As per RFC 727 - - STATUS: - The server will send its current status upon - request. It does not ask for the clients status. - The client will request the servers current status - from the "send getstatus" command. - - ENVIRON: - This option is currently being defined by the IETF - Telnet Working Group, and an RFC has not yet been - issued, but should be in the near future... - - X-DISPLAY-LOCATION: - This functionality can be done through the ENVIRON - option, it is added here for completeness. - - AUTHENTICATION: - This option is currently being defined by the IETF - Telnet Working Group, and an RFC has not yet been - issued. The basic framework is pretty much decided, - but the definitions for the specific authentication - schemes is still in a state of flux. - - ENCRYPTION: - This option is currently being defined by the IETF - Telnet Working Group, and an RFC has not yet been - issued. The draft RFC is still in a state of flux, - so this code may change in the future. diff --git a/appl/telnet/arpa/telnet.h b/appl/telnet/arpa/telnet.h deleted file mode 100644 index 5d9ef6001..000000000 --- a/appl/telnet/arpa/telnet.h +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright (c) 1983, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)telnet.h 8.2 (Berkeley) 12/15/93 - */ - -#ifndef _TELNET_H_ -#define _TELNET_H_ - -/* - * Definitions for the TELNET protocol. - */ -#define IAC 255 /* interpret as command: */ -#define DONT 254 /* you are not to use option */ -#define DO 253 /* please, you use option */ -#define WONT 252 /* I won't use option */ -#define WILL 251 /* I will use option */ -#define SB 250 /* interpret as subnegotiation */ -#define GA 249 /* you may reverse the line */ -#define EL 248 /* erase the current line */ -#define EC 247 /* erase the current character */ -#define AYT 246 /* are you there */ -#define AO 245 /* abort output--but let prog finish */ -#define IP 244 /* interrupt process--permanently */ -#define BREAK 243 /* break */ -#define DM 242 /* data mark--for connect. cleaning */ -#define NOP 241 /* nop */ -#define SE 240 /* end sub negotiation */ -#define EOR 239 /* end of record (transparent mode) */ -#define ABORT 238 /* Abort process */ -#define SUSP 237 /* Suspend process */ -#define xEOF 236 /* End of file: EOF is already used... */ - -#define SYNCH 242 /* for telfunc calls */ - -#ifdef TELCMDS -char *telcmds[] = { - "EOF", "SUSP", "ABORT", "EOR", - "SE", "NOP", "DMARK", "BRK", "IP", "AO", "AYT", "EC", - "EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC", 0, -}; -#else -extern char *telcmds[]; -#endif - -#define TELCMD_FIRST xEOF -#define TELCMD_LAST IAC -#define TELCMD_OK(x) ((unsigned int)(x) <= TELCMD_LAST && \ - (unsigned int)(x) >= TELCMD_FIRST) -#define TELCMD(x) telcmds[(x)-TELCMD_FIRST] - -/* telnet options */ -#define TELOPT_BINARY 0 /* 8-bit data path */ -#define TELOPT_ECHO 1 /* echo */ -#define TELOPT_RCP 2 /* prepare to reconnect */ -#define TELOPT_SGA 3 /* suppress go ahead */ -#define TELOPT_NAMS 4 /* approximate message size */ -#define TELOPT_STATUS 5 /* give status */ -#define TELOPT_TM 6 /* timing mark */ -#define TELOPT_RCTE 7 /* remote controlled transmission and echo */ -#define TELOPT_NAOL 8 /* negotiate about output line width */ -#define TELOPT_NAOP 9 /* negotiate about output page size */ -#define TELOPT_NAOCRD 10 /* negotiate about CR disposition */ -#define TELOPT_NAOHTS 11 /* negotiate about horizontal tabstops */ -#define TELOPT_NAOHTD 12 /* negotiate about horizontal tab disposition */ -#define TELOPT_NAOFFD 13 /* negotiate about formfeed disposition */ -#define TELOPT_NAOVTS 14 /* negotiate about vertical tab stops */ -#define TELOPT_NAOVTD 15 /* negotiate about vertical tab disposition */ -#define TELOPT_NAOLFD 16 /* negotiate about output LF disposition */ -#define TELOPT_XASCII 17 /* extended ascic character set */ -#define TELOPT_LOGOUT 18 /* force logout */ -#define TELOPT_BM 19 /* byte macro */ -#define TELOPT_DET 20 /* data entry terminal */ -#define TELOPT_SUPDUP 21 /* supdup protocol */ -#define TELOPT_SUPDUPOUTPUT 22 /* supdup output */ -#define TELOPT_SNDLOC 23 /* send location */ -#define TELOPT_TTYPE 24 /* terminal type */ -#define TELOPT_EOR 25 /* end or record */ -#define TELOPT_TUID 26 /* TACACS user identification */ -#define TELOPT_OUTMRK 27 /* output marking */ -#define TELOPT_TTYLOC 28 /* terminal location number */ -#define TELOPT_3270REGIME 29 /* 3270 regime */ -#define TELOPT_X3PAD 30 /* X.3 PAD */ -#define TELOPT_NAWS 31 /* window size */ -#define TELOPT_TSPEED 32 /* terminal speed */ -#define TELOPT_LFLOW 33 /* remote flow control */ -#define TELOPT_LINEMODE 34 /* Linemode option */ -#define TELOPT_XDISPLOC 35 /* X Display Location */ -#define TELOPT_OLD_ENVIRON 36 /* Old - Environment variables */ -#define TELOPT_AUTHENTICATION 37/* Authenticate */ -#define TELOPT_ENCRYPT 38 /* Encryption option */ -#define TELOPT_NEW_ENVIRON 39 /* New - Environment variables */ -#define TELOPT_EXOPL 255 /* extended-options-list */ - - -#define NTELOPTS (1+TELOPT_NEW_ENVIRON) -#ifdef TELOPTS -char *telopts[NTELOPTS+1] = { - "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME", - "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP", - "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS", - "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO", - "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT", - "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD", - "TACACS UID", "OUTPUT MARKING", "TTYLOC", - "3270 REGIME", "X.3 PAD", "NAWS", "TSPEED", "LFLOW", - "LINEMODE", "XDISPLOC", "OLD-ENVIRON", "AUTHENTICATION", - "ENCRYPT", "NEW-ENVIRON", - 0, -}; -#define TELOPT_FIRST TELOPT_BINARY -#define TELOPT_LAST TELOPT_NEW_ENVIRON -#define TELOPT_OK(x) ((unsigned int)(x) <= TELOPT_LAST) -#define TELOPT(x) telopts[(x)-TELOPT_FIRST] -#endif - -/* sub-option qualifiers */ -#define TELQUAL_IS 0 /* option is... */ -#define TELQUAL_SEND 1 /* send option */ -#define TELQUAL_INFO 2 /* ENVIRON: informational version of IS */ -#define TELQUAL_REPLY 2 /* AUTHENTICATION: client version of IS */ -#define TELQUAL_NAME 3 /* AUTHENTICATION: client version of IS */ - -#define LFLOW_OFF 0 /* Disable remote flow control */ -#define LFLOW_ON 1 /* Enable remote flow control */ -#define LFLOW_RESTART_ANY 2 /* Restart output on any char */ -#define LFLOW_RESTART_XON 3 /* Restart output only on XON */ - -/* - * LINEMODE suboptions - */ - -#define LM_MODE 1 -#define LM_FORWARDMASK 2 -#define LM_SLC 3 - -#define MODE_EDIT 0x01 -#define MODE_TRAPSIG 0x02 -#define MODE_ACK 0x04 -#define MODE_SOFT_TAB 0x08 -#define MODE_LIT_ECHO 0x10 - -#define MODE_MASK 0x1f - -/* Not part of protocol, but needed to simplify things... */ -#define MODE_FLOW 0x0100 -#define MODE_ECHO 0x0200 -#define MODE_INBIN 0x0400 -#define MODE_OUTBIN 0x0800 -#define MODE_FORCE 0x1000 - -#define SLC_SYNCH 1 -#define SLC_BRK 2 -#define SLC_IP 3 -#define SLC_AO 4 -#define SLC_AYT 5 -#define SLC_EOR 6 -#define SLC_ABORT 7 -#define SLC_EOF 8 -#define SLC_SUSP 9 -#define SLC_EC 10 -#define SLC_EL 11 -#define SLC_EW 12 -#define SLC_RP 13 -#define SLC_LNEXT 14 -#define SLC_XON 15 -#define SLC_XOFF 16 -#define SLC_FORW1 17 -#define SLC_FORW2 18 - -#define NSLC 18 - -/* - * For backwards compatability, we define SLC_NAMES to be the - * list of names if SLC_NAMES is not defined. - */ -#define SLC_NAMELIST "0", "SYNCH", "BRK", "IP", "AO", "AYT", "EOR", \ - "ABORT", "EOF", "SUSP", "EC", "EL", "EW", "RP", \ - "LNEXT", "XON", "XOFF", "FORW1", "FORW2", 0, -#ifdef SLC_NAMES -char *slc_names[] = { - SLC_NAMELIST -}; -#else -extern char *slc_names[]; -#define SLC_NAMES SLC_NAMELIST -#endif - -#define SLC_NAME_OK(x) ((unsigned int)(x) <= NSLC) -#define SLC_NAME(x) slc_names[x] - -#define SLC_NOSUPPORT 0 -#define SLC_CANTCHANGE 1 -#define SLC_VARIABLE 2 -#define SLC_DEFAULT 3 -#define SLC_LEVELBITS 0x03 - -#define SLC_FUNC 0 -#define SLC_FLAGS 1 -#define SLC_VALUE 2 - -#define SLC_ACK 0x80 -#define SLC_FLUSHIN 0x40 -#define SLC_FLUSHOUT 0x20 - -#define OLD_ENV_VAR 1 -#define OLD_ENV_VALUE 0 -#define NEW_ENV_VAR 0 -#define NEW_ENV_VALUE 1 -#define ENV_ESC 2 -#define ENV_USERVAR 3 - -/* - * AUTHENTICATION suboptions - */ - -/* - * Who is authenticating who ... - */ -#define AUTH_WHO_CLIENT 0 /* Client authenticating server */ -#define AUTH_WHO_SERVER 1 /* Server authenticating client */ -#define AUTH_WHO_MASK 1 - -/* - * amount of authentication done - */ -#define AUTH_HOW_ONE_WAY 0 -#define AUTH_HOW_MUTUAL 2 -#define AUTH_HOW_MASK 2 - -#define AUTHTYPE_NULL 0 -#define AUTHTYPE_KERBEROS_V4 1 -#define AUTHTYPE_KERBEROS_V5 2 -#define AUTHTYPE_SPX 3 -#define AUTHTYPE_MINK 4 -#define AUTHTYPE_SRA 5 -#define AUTHTYPE_CNT 6 -/* #define AUTHTYPE_UNSECURE 6 */ - -#define AUTHTYPE_TEST 99 - -#ifdef AUTH_NAMES -char *authtype_names[] = { - "NULL", "KERBEROS_V4", "KERBEROS_V5", "SPX", "MINK", - "SRA", 0, -}; -#else -extern char *authtype_names[]; -#endif - -#define AUTHTYPE_NAME_OK(x) ((unsigned int)(x) < AUTHTYPE_CNT) -#define AUTHTYPE_NAME(x) authtype_names[x] - -/* - * ENCRYPTion suboptions - */ -#define ENCRYPT_IS 0 /* I pick encryption type ... */ -#define ENCRYPT_SUPPORT 1 /* I support encryption types ... */ -#define ENCRYPT_REPLY 2 /* Initial setup response */ -#define ENCRYPT_START 3 /* Am starting to send encrypted */ -#define ENCRYPT_END 4 /* Am ending encrypted */ -#define ENCRYPT_REQSTART 5 /* Request you start encrypting */ -#define ENCRYPT_REQEND 6 /* Request you send encrypting */ -#define ENCRYPT_ENC_KEYID 7 -#define ENCRYPT_DEC_KEYID 8 -#define ENCRYPT_CNT 9 - -#define ENCTYPE_ANY 0 -#define ENCTYPE_DES_CFB64 1 -#define ENCTYPE_DES_OFB64 2 -#define ENCTYPE_CNT 3 - -#ifdef ENCRYPT_NAMES -char *encrypt_names[] = { - "IS", "SUPPORT", "REPLY", "START", "END", - "REQUEST-START", "REQUEST-END", "ENC-KEYID", "DEC-KEYID", - 0, -}; -char *enctype_names[] = { - "ANY", "DES_CFB64", "DES_OFB64", 0, -}; -#else -extern char *encrypt_names[]; -extern char *enctype_names[]; -#endif - - -#define ENCRYPT_NAME_OK(x) ((unsigned int)(x) < ENCRYPT_CNT) -#define ENCRYPT_NAME(x) encrypt_names[x] - -#define ENCTYPE_NAME_OK(x) ((unsigned int)(x) < ENCTYPE_CNT) -#define ENCTYPE_NAME(x) enctype_names[x] - -#endif /* !_TELNET_H_ */ diff --git a/appl/telnet/libtelnet/Makefile.am b/appl/telnet/libtelnet/Makefile.am deleted file mode 100644 index 929578681..000000000 --- a/appl/telnet/libtelnet/Makefile.am +++ /dev/null @@ -1,23 +0,0 @@ -# $Id$ - -include $(top_srcdir)/Makefile.am.common - -AM_CPPFLAGS += -I$(srcdir)/.. $(INCLUDE_hcrypto) - -noinst_LIBRARIES = libtelnet.a - -libtelnet_a_SOURCES = \ - auth-proto.h \ - auth.c \ - auth.h \ - enc-proto.h \ - enc_des.c \ - encrypt.c \ - encrypt.h \ - genget.c \ - kerberos5.c \ - misc-proto.h \ - misc.c \ - misc.h - -EXTRA_DIST = rsaencpwd.c spx.c diff --git a/appl/telnet/libtelnet/auth-proto.h b/appl/telnet/libtelnet/auth-proto.h deleted file mode 100644 index 511a5ab71..000000000 --- a/appl/telnet/libtelnet/auth-proto.h +++ /dev/null @@ -1,111 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)auth-proto.h 8.1 (Berkeley) 6/4/93 - */ - -/* - * Copyright (C) 1990 by the Massachusetts Institute of Technology - * - * Export of this software from the United States of America is assumed - * to require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. - * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. - */ - -/* $Id$ */ - -#ifdef AUTHENTICATION -Authenticator *findauthenticator (int, int); - -int auth_wait (char *, size_t); -void auth_disable_name (char *); -void auth_finished (Authenticator *, int); -void auth_gen_printsub (unsigned char *, size_t, unsigned char *, size_t); -void auth_init (const char *, int); -void auth_is (unsigned char *, int); -void auth_name(unsigned char*, int); -void auth_reply (unsigned char *, int); -void auth_request (void); -void auth_send (unsigned char *, int); -void auth_send_retry (void); -void auth_printsub(unsigned char*, size_t, unsigned char*, size_t); -int getauthmask(char *type, int *maskp); -int auth_enable(char *type); -int auth_disable(char *type); -int auth_onoff(char *type, int on); -int auth_togdebug(int on); -int auth_status(void); -int auth_sendname(unsigned char *cp, int len); -void auth_debug(int mode); - -#ifdef UNSAFE -int unsafe_init (Authenticator *, int); -int unsafe_send (Authenticator *); -void unsafe_is (Authenticator *, unsigned char *, int); -void unsafe_reply (Authenticator *, unsigned char *, int); -int unsafe_status (Authenticator *, char *, int); -void unsafe_printsub (unsigned char *, size_t, unsigned char *, size_t); -#endif - -#ifdef SRA -int sra_init (Authenticator *, int); -int sra_send (Authenticator *); -void sra_is (Authenticator *, unsigned char *, int); -void sra_reply (Authenticator *, unsigned char *, int); -int sra_status (Authenticator *, char *, int); -void sra_printsub (unsigned char *, size_t, unsigned char *, size_t); -#endif - -#ifdef KRB5 -int kerberos5_init (Authenticator *, int); -int kerberos5_send_mutual (Authenticator *); -int kerberos5_send_oneway (Authenticator *); -void kerberos5_is (Authenticator *, unsigned char *, int); -void kerberos5_reply (Authenticator *, unsigned char *, int); -int kerberos5_status (Authenticator *, char *, size_t, int); -void kerberos5_printsub (unsigned char *, size_t, unsigned char *, size_t); -int kerberos5_set_forward(int); -int kerberos5_set_forwardable(int); -#endif -#endif diff --git a/appl/telnet/libtelnet/auth.c b/appl/telnet/libtelnet/auth.c deleted file mode 100644 index 1c01245d1..000000000 --- a/appl/telnet/libtelnet/auth.c +++ /dev/null @@ -1,628 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Copyright (C) 1990 by the Massachusetts Institute of Technology - * - * Export of this software from the United States of America is assumed - * to require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. - * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. - */ - -#include - -RCSID("$Id$"); - -#if defined(AUTHENTICATION) -#include -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#include -#define AUTH_NAMES -#ifdef HAVE_ARPA_TELNET_H -#include -#endif -#include -#include - -#include - -#ifdef SOCKS -#include -#endif - -#include "encrypt.h" -#include "auth.h" -#include "misc-proto.h" -#include "auth-proto.h" - -#define typemask(x) (1<<((x)-1)) - -#ifdef RSA_ENCPWD -extern rsaencpwd_init(); -extern rsaencpwd_send(); -extern rsaencpwd_is(); -extern rsaencpwd_reply(); -extern rsaencpwd_status(); -extern rsaencpwd_printsub(); -#endif - -int auth_debug_mode = 0; -int auth_has_failed = 0; -int auth_enable_encrypt = 0; -static const char *Name = "Noname"; -static int Server = 0; -static Authenticator *authenticated = 0; -static int authenticating = 0; -static int validuser = 0; -static unsigned char _auth_send_data[256]; -static unsigned char *auth_send_data; -static int auth_send_cnt = 0; - -/* - * Authentication types supported. Plese note that these are stored - * in priority order, i.e. try the first one first. - */ -Authenticator authenticators[] = { -#ifdef UNSAFE - { AUTHTYPE_UNSAFE, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY, - unsafe_init, - unsafe_send, - unsafe_is, - unsafe_reply, - unsafe_status, - unsafe_printsub }, -#endif -#ifdef SRA - { AUTHTYPE_SRA, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY, - sra_init, - sra_send, - sra_is, - sra_reply, - sra_status, - sra_printsub }, -#endif -#ifdef SPX - { AUTHTYPE_SPX, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL, - spx_init, - spx_send, - spx_is, - spx_reply, - spx_status, - spx_printsub }, - { AUTHTYPE_SPX, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY, - spx_init, - spx_send, - spx_is, - spx_reply, - spx_status, - spx_printsub }, -#endif -#ifdef KRB5 - { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL, - kerberos5_init, - kerberos5_send_mutual, - kerberos5_is, - kerberos5_reply, - kerberos5_status, - kerberos5_printsub }, - { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY, - kerberos5_init, - kerberos5_send_oneway, - kerberos5_is, - kerberos5_reply, - kerberos5_status, - kerberos5_printsub }, -#endif -#ifdef RSA_ENCPWD - { AUTHTYPE_RSA_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY, - rsaencpwd_init, - rsaencpwd_send, - rsaencpwd_is, - rsaencpwd_reply, - rsaencpwd_status, - rsaencpwd_printsub }, -#endif - { 0, }, -}; - -static Authenticator NoAuth = { 0 }; - -static int i_support = 0; -static int i_wont_support = 0; - -Authenticator * -findauthenticator(int type, int way) -{ - Authenticator *ap = authenticators; - - while (ap->type && (ap->type != type || ap->way != way)) - ++ap; - return(ap->type ? ap : 0); -} - -void -auth_init(const char *name, int server) -{ - Authenticator *ap = authenticators; - - Server = server; - Name = name; - - i_support = 0; - authenticated = 0; - authenticating = 0; - while (ap->type) { - if (!ap->init || (*ap->init)(ap, server)) { - i_support |= typemask(ap->type); - if (auth_debug_mode) - printf(">>>%s: I support auth type %d %d\r\n", - Name, - ap->type, ap->way); - } - else if (auth_debug_mode) - printf(">>>%s: Init failed: auth type %d %d\r\n", - Name, ap->type, ap->way); - ++ap; - } -} - -void -auth_disable_name(char *name) -{ - int x; - for (x = 0; x < AUTHTYPE_CNT; ++x) { - if (!strcasecmp(name, AUTHTYPE_NAME(x))) { - i_wont_support |= typemask(x); - break; - } - } -} - -int -getauthmask(char *type, int *maskp) -{ - int x; - - if (!strcasecmp(type, AUTHTYPE_NAME(0))) { - *maskp = -1; - return(1); - } - - for (x = 1; x < AUTHTYPE_CNT; ++x) { - if (!strcasecmp(type, AUTHTYPE_NAME(x))) { - *maskp = typemask(x); - return(1); - } - } - return(0); -} - -int -auth_enable(char *type) -{ - return(auth_onoff(type, 1)); -} - -int -auth_disable(char *type) -{ - return(auth_onoff(type, 0)); -} - -int -auth_onoff(char *type, int on) -{ - int i, mask = -1; - Authenticator *ap; - - if (!strcasecmp(type, "?") || !strcasecmp(type, "help")) { - printf("auth %s 'type'\n", on ? "enable" : "disable"); - printf("Where 'type' is one of:\n"); - printf("\t%s\n", AUTHTYPE_NAME(0)); - mask = 0; - for (ap = authenticators; ap->type; ap++) { - if ((mask & (i = typemask(ap->type))) != 0) - continue; - mask |= i; - printf("\t%s\n", AUTHTYPE_NAME(ap->type)); - } - return(0); - } - - if (!getauthmask(type, &mask)) { - printf("%s: invalid authentication type\n", type); - return(0); - } - if (on) - i_wont_support &= ~mask; - else - i_wont_support |= mask; - return(1); -} - -int -auth_togdebug(int on) -{ - if (on < 0) - auth_debug_mode ^= 1; - else - auth_debug_mode = on; - printf("auth debugging %s\n", auth_debug_mode ? "enabled" : "disabled"); - return(1); -} - -int -auth_status(void) -{ - Authenticator *ap; - int i, mask; - - if (i_wont_support == -1) - printf("Authentication disabled\n"); - else - printf("Authentication enabled\n"); - - mask = 0; - for (ap = authenticators; ap->type; ap++) { - if ((mask & (i = typemask(ap->type))) != 0) - continue; - mask |= i; - printf("%s: %s\n", AUTHTYPE_NAME(ap->type), - (i_wont_support & typemask(ap->type)) ? - "disabled" : "enabled"); - } - return(1); -} - -/* - * This routine is called by the server to start authentication - * negotiation. - */ -void -auth_request(void) -{ - static unsigned char str_request[64] = { IAC, SB, - TELOPT_AUTHENTICATION, - TELQUAL_SEND, }; - Authenticator *ap = authenticators; - unsigned char *e = str_request + 4; - - if (!authenticating) { - authenticating = 1; - while (ap->type) { - if (i_support & ~i_wont_support & typemask(ap->type)) { - if (auth_debug_mode) { - printf(">>>%s: Sending type %d %d\r\n", - Name, ap->type, ap->way); - } - *e++ = ap->type; - *e++ = ap->way; - } - ++ap; - } - *e++ = IAC; - *e++ = SE; - telnet_net_write(str_request, e - str_request); - printsub('>', &str_request[2], e - str_request - 2); - } -} - -/* - * This is called when an AUTH SEND is received. - * It should never arrive on the server side (as only the server can - * send an AUTH SEND). - * You should probably respond to it if you can... - * - * If you want to respond to the types out of order (i.e. even - * if he sends LOGIN KERBEROS and you support both, you respond - * with KERBEROS instead of LOGIN (which is against what the - * protocol says)) you will have to hack this code... - */ -void -auth_send(unsigned char *data, int cnt) -{ - Authenticator *ap; - static unsigned char str_none[] = { IAC, SB, TELOPT_AUTHENTICATION, - TELQUAL_IS, AUTHTYPE_NULL, 0, - IAC, SE }; - if (Server) { - if (auth_debug_mode) { - printf(">>>%s: auth_send called!\r\n", Name); - } - return; - } - - if (auth_debug_mode) { - printf(">>>%s: auth_send got:", Name); - printd(data, cnt); printf("\r\n"); - } - - /* - * Save the data, if it is new, so that we can continue looking - * at it if the authorization we try doesn't work - */ - if (data < _auth_send_data || - data > _auth_send_data + sizeof(_auth_send_data)) { - auth_send_cnt = cnt > sizeof(_auth_send_data) - ? sizeof(_auth_send_data) - : cnt; - memmove(_auth_send_data, data, auth_send_cnt); - auth_send_data = _auth_send_data; - } else { - /* - * This is probably a no-op, but we just make sure - */ - auth_send_data = data; - auth_send_cnt = cnt; - } - while ((auth_send_cnt -= 2) >= 0) { - if (auth_debug_mode) - printf(">>>%s: He supports %d\r\n", - Name, *auth_send_data); - if ((i_support & ~i_wont_support) & typemask(*auth_send_data)) { - ap = findauthenticator(auth_send_data[0], - auth_send_data[1]); - if (ap && ap->send) { - if (auth_debug_mode) - printf(">>>%s: Trying %d %d\r\n", - Name, auth_send_data[0], - auth_send_data[1]); - if ((*ap->send)(ap)) { - /* - * Okay, we found one we like - * and did it. - * we can go home now. - */ - if (auth_debug_mode) - printf(">>>%s: Using type %d\r\n", - Name, *auth_send_data); - auth_send_data += 2; - return; - } - } - /* else - * just continue on and look for the - * next one if we didn't do anything. - */ - } - auth_send_data += 2; - } - telnet_net_write(str_none, sizeof(str_none)); - printsub('>', &str_none[2], sizeof(str_none) - 2); - if (auth_debug_mode) - printf(">>>%s: Sent failure message\r\n", Name); - auth_finished(0, AUTH_REJECT); - auth_has_failed = 1; -#ifdef KANNAN - /* - * We requested strong authentication, however no mechanisms worked. - * Therefore, exit on client end. - */ - printf("Unable to securely authenticate user ... exit\n"); - exit(0); -#endif /* KANNAN */ -} - -void -auth_send_retry(void) -{ - /* - * if auth_send_cnt <= 0 then auth_send will end up rejecting - * the authentication and informing the other side of this. - */ - auth_send(auth_send_data, auth_send_cnt); -} - -void -auth_is(unsigned char *data, int cnt) -{ - Authenticator *ap; - - if (cnt < 2) - return; - - if (data[0] == AUTHTYPE_NULL) { - auth_finished(0, AUTH_REJECT); - return; - } - - if ((ap = findauthenticator(data[0], data[1]))) { - if (ap->is) - (*ap->is)(ap, data+2, cnt-2); - } else if (auth_debug_mode) - printf(">>>%s: Invalid authentication in IS: %d\r\n", - Name, *data); -} - -void -auth_reply(unsigned char *data, int cnt) -{ - Authenticator *ap; - - if (cnt < 2) - return; - - if ((ap = findauthenticator(data[0], data[1]))) { - if (ap->reply) - (*ap->reply)(ap, data+2, cnt-2); - } else if (auth_debug_mode) - printf(">>>%s: Invalid authentication in SEND: %d\r\n", - Name, *data); -} - -void -auth_name(unsigned char *data, int cnt) -{ - char savename[256]; - - if (cnt < 1) { - if (auth_debug_mode) - printf(">>>%s: Empty name in NAME\r\n", Name); - return; - } - if (cnt > sizeof(savename) - 1) { - if (auth_debug_mode) - printf(">>>%s: Name in NAME (%d) exceeds %lu length\r\n", - Name, cnt, (unsigned long)(sizeof(savename)-1)); - return; - } - memmove(savename, data, cnt); - savename[cnt] = '\0'; /* Null terminate */ - if (auth_debug_mode) - printf(">>>%s: Got NAME [%s]\r\n", Name, savename); - auth_encrypt_user(savename); -} - -int -auth_sendname(unsigned char *cp, int len) -{ - static unsigned char str_request[256+6] - = { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_NAME, }; - unsigned char *e = str_request + 4; - unsigned char *ee = &str_request[sizeof(str_request)-2]; - - while (--len >= 0) { - if ((*e++ = *cp++) == IAC) - *e++ = IAC; - if (e >= ee) - return(0); - } - *e++ = IAC; - *e++ = SE; - telnet_net_write(str_request, e - str_request); - printsub('>', &str_request[2], e - &str_request[2]); - return(1); -} - -void -auth_finished(Authenticator *ap, int result) -{ - if (!(authenticated = ap)) - authenticated = &NoAuth; - validuser = result; -} - -/* ARGSUSED */ -static void -auth_intr(int sig) -{ - auth_finished(0, AUTH_REJECT); -} - -int -auth_wait(char *name, size_t name_sz) -{ - if (auth_debug_mode) - printf(">>>%s: in auth_wait.\r\n", Name); - - if (Server && !authenticating) - return(0); - - signal(SIGALRM, auth_intr); - alarm(30); - while (!authenticated) - if (telnet_spin()) - break; - alarm(0); - signal(SIGALRM, SIG_DFL); - - /* - * Now check to see if the user is valid or not - */ - if (!authenticated || authenticated == &NoAuth) - return(AUTH_REJECT); - - if (validuser == AUTH_VALID) - validuser = AUTH_USER; - - if (authenticated->status) - validuser = (*authenticated->status)(authenticated, - name, name_sz, - validuser); - return(validuser); -} - -void -auth_debug(int mode) -{ - auth_debug_mode = mode; -} - -void -auth_printsub(unsigned char *data, size_t cnt, - unsigned char *buf, size_t buflen) -{ - Authenticator *ap; - - if ((ap = findauthenticator(data[1], data[2])) && ap->printsub) - (*ap->printsub)(data, cnt, buf, buflen); - else - auth_gen_printsub(data, cnt, buf, buflen); -} - -void -auth_gen_printsub(unsigned char *data, size_t cnt, - unsigned char *buf, size_t buflen) -{ - unsigned char *cp; - unsigned char tbuf[16]; - - cnt -= 3; - data += 3; - buf[buflen-1] = '\0'; - buf[buflen-2] = '*'; - buflen -= 2; - for (; cnt > 0; cnt--, data++) { - snprintf((char*)tbuf, sizeof(tbuf), " %d", *data); - for (cp = tbuf; *cp && buflen > 0; --buflen) - *buf++ = *cp++; - if (buflen <= 0) - return; - } - *buf = '\0'; -} -#endif diff --git a/appl/telnet/libtelnet/auth.h b/appl/telnet/libtelnet/auth.h deleted file mode 100644 index bb793459d..000000000 --- a/appl/telnet/libtelnet/auth.h +++ /dev/null @@ -1,81 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)auth.h 8.1 (Berkeley) 6/4/93 - */ - -/* - * Copyright (C) 1990 by the Massachusetts Institute of Technology - * - * Export of this software from the United States of America is assumed - * to require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. - * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. - */ - -/* $Id$ */ - -#ifndef __AUTH__ -#define __AUTH__ - -#define AUTH_REJECT 0 /* Rejected */ -#define AUTH_UNKNOWN 1 /* We don't know who he is, but he's okay */ -#define AUTH_OTHER 2 /* We know him, but not his name */ -#define AUTH_USER 3 /* We know he name */ -#define AUTH_VALID 4 /* We know him, and he needs no password */ - -typedef struct XauthP { - int type; - int way; - int (*init) (struct XauthP *, int); - int (*send) (struct XauthP *); - void (*is) (struct XauthP *, unsigned char *, int); - void (*reply) (struct XauthP *, unsigned char *, int); - int (*status) (struct XauthP *, char *, size_t, int); - void (*printsub) (unsigned char *, size_t, unsigned char *, size_t); -} Authenticator; - -#include "auth-proto.h" - -extern int auth_debug_mode; -#endif diff --git a/appl/telnet/libtelnet/enc-proto.h b/appl/telnet/libtelnet/enc-proto.h deleted file mode 100644 index b3e909bcf..000000000 --- a/appl/telnet/libtelnet/enc-proto.h +++ /dev/null @@ -1,133 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)enc-proto.h 8.1 (Berkeley) 6/4/93 - * - * @(#)enc-proto.h 5.2 (Berkeley) 3/22/91 - */ - -/* - * Copyright (C) 1990 by the Massachusetts Institute of Technology - * - * Export of this software from the United States of America is assumed - * to require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. - * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. - */ - -/* $Id$ */ - -#if defined(ENCRYPTION) -Encryptions *findencryption (int); -Encryptions *finddecryption(int); -int EncryptAutoDec(int); -int EncryptAutoEnc(int); -int EncryptDebug(int); -int EncryptDisable(char*, char*); -int EncryptEnable(char*, char*); -int EncryptStart(char*); -int EncryptStartInput(void); -int EncryptStartOutput(void); -int EncryptStatus(void); -int EncryptStop(char*); -int EncryptStopInput(void); -int EncryptStopOutput(void); -int EncryptType(char*, char*); -int EncryptVerbose(int); -void decrypt_auto(int); -void encrypt_auto(int); -void encrypt_debug(int); -void encrypt_dec_keyid(unsigned char*, int); -void encrypt_display(void); -void encrypt_enc_keyid(unsigned char*, int); -void encrypt_end(void); -void encrypt_gen_printsub(unsigned char*, size_t, unsigned char*, size_t); -void encrypt_init(const char*, int); -void encrypt_is(unsigned char*, int); -void encrypt_list_types(void); -void encrypt_not(void); -void encrypt_printsub(unsigned char*, size_t, unsigned char*, size_t); -void encrypt_reply(unsigned char*, int); -void encrypt_request_end(void); -void encrypt_request_start(unsigned char*, int); -void encrypt_send_end(void); -void encrypt_send_keyid(int, unsigned char*, int, int); -void encrypt_send_request_end(void); -int encrypt_is_encrypting(void); -void encrypt_send_request_start(void); -void encrypt_send_support(void); -void encrypt_session_key(Session_Key*, int); -void encrypt_start(unsigned char*, int); -void encrypt_start_output(int); -void encrypt_support(unsigned char*, int); -void encrypt_verbose_quiet(int); -void encrypt_wait(void); -int encrypt_delay(void); - -#ifdef TELENTD -void encrypt_wait (void); -#else -void encrypt_display (void); -#endif - -void cfb64_encrypt (unsigned char *, int); -int cfb64_decrypt (int); -void cfb64_init (int); -int cfb64_start (int, int); -int cfb64_is (unsigned char *, int); -int cfb64_reply (unsigned char *, int); -void cfb64_session (Session_Key *, int); -int cfb64_keyid (int, unsigned char *, int *); -void cfb64_printsub (unsigned char *, size_t, unsigned char *, size_t); - -void ofb64_encrypt (unsigned char *, int); -int ofb64_decrypt (int); -void ofb64_init (int); -int ofb64_start (int, int); -int ofb64_is (unsigned char *, int); -int ofb64_reply (unsigned char *, int); -void ofb64_session (Session_Key *, int); -int ofb64_keyid (int, unsigned char *, int *); -void ofb64_printsub (unsigned char *, size_t, unsigned char *, size_t); - -#endif diff --git a/appl/telnet/libtelnet/enc_des.c b/appl/telnet/libtelnet/enc_des.c deleted file mode 100644 index 67ae3f9e5..000000000 --- a/appl/telnet/libtelnet/enc_des.c +++ /dev/null @@ -1,660 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -RCSID("$Id$"); - -#if defined(AUTHENTICATION) && defined(ENCRYPTION) && defined(DES_ENCRYPTION) -#include -#include -#ifdef __STDC__ -#include -#include -#endif -#include -#ifdef SOCKS -#include -#endif - -#include "encrypt.h" -#include "misc-proto.h" - -#include "crypto-headers.h" - -extern int encrypt_debug_mode; - -#define CFB 0 -#define OFB 1 - -#define NO_SEND_IV 1 -#define NO_RECV_IV 2 -#define NO_KEYID 4 -#define IN_PROGRESS (NO_SEND_IV|NO_RECV_IV|NO_KEYID) -#define SUCCESS 0 -#define FAILED -1 - - -struct stinfo { - DES_cblock str_output; - DES_cblock str_feed; - DES_cblock str_iv; - DES_cblock str_ikey; - DES_key_schedule str_sched; - int str_index; - int str_flagshift; -}; - -struct fb { - DES_cblock krbdes_key; - DES_key_schedule krbdes_sched; - DES_cblock temp_feed; - unsigned char fb_feed[64]; - int need_start; - int state[2]; - int keyid[2]; - struct stinfo streams[2]; -}; - -static struct fb fb[2]; - -struct keyidlist { - char *keyid; - int keyidlen; - char *key; - int keylen; - int flags; -} keyidlist [] = { - { "\0", 1, 0, 0, 0 }, /* default key of zero */ - { 0, 0, 0, 0, 0 } -}; - -#define KEYFLAG_MASK 03 - -#define KEYFLAG_NOINIT 00 -#define KEYFLAG_INIT 01 -#define KEYFLAG_OK 02 -#define KEYFLAG_BAD 03 - -#define KEYFLAG_SHIFT 2 - -#define SHIFT_VAL(a,b) (KEYFLAG_SHIFT*((a)+((b)*2))) - -#define FB64_IV 1 -#define FB64_IV_OK 2 -#define FB64_IV_BAD 3 - - -void fb64_stream_iv (DES_cblock, struct stinfo *); -void fb64_init (struct fb *); -static int fb64_start (struct fb *, int, int); -int fb64_is (unsigned char *, int, struct fb *); -int fb64_reply (unsigned char *, int, struct fb *); -static void fb64_session (Session_Key *, int, struct fb *); -void fb64_stream_key (DES_cblock, struct stinfo *); -int fb64_keyid (int, unsigned char *, int *, struct fb *); -void fb64_printsub(unsigned char *, size_t , - unsigned char *, size_t , char *); - -void cfb64_init(int server) -{ - fb64_init(&fb[CFB]); - fb[CFB].fb_feed[4] = ENCTYPE_DES_CFB64; - fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB); - fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB); -} - - -void ofb64_init(int server) -{ - fb64_init(&fb[OFB]); - fb[OFB].fb_feed[4] = ENCTYPE_DES_OFB64; - fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB); - fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB); -} - -void fb64_init(struct fb *fbp) -{ - memset(fbp,0, sizeof(*fbp)); - fbp->state[0] = fbp->state[1] = FAILED; - fbp->fb_feed[0] = IAC; - fbp->fb_feed[1] = SB; - fbp->fb_feed[2] = TELOPT_ENCRYPT; - fbp->fb_feed[3] = ENCRYPT_IS; -} - -/* - * Returns: - * -1: some error. Negotiation is done, encryption not ready. - * 0: Successful, initial negotiation all done. - * 1: successful, negotiation not done yet. - * 2: Not yet. Other things (like getting the key from - * Kerberos) have to happen before we can continue. - */ -int cfb64_start(int dir, int server) -{ - return(fb64_start(&fb[CFB], dir, server)); -} - -int ofb64_start(int dir, int server) -{ - return(fb64_start(&fb[OFB], dir, server)); -} - -static int fb64_start(struct fb *fbp, int dir, int server) -{ - int x; - unsigned char *p; - int state; - - switch (dir) { - case DIR_DECRYPT: - /* - * This is simply a request to have the other side - * start output (our input). He will negotiate an - * IV so we need not look for it. - */ - state = fbp->state[dir-1]; - if (state == FAILED) - state = IN_PROGRESS; - break; - - case DIR_ENCRYPT: - state = fbp->state[dir-1]; - if (state == FAILED) - state = IN_PROGRESS; - else if ((state & NO_SEND_IV) == 0) { - break; - } - - if (!VALIDKEY(fbp->krbdes_key)) { - fbp->need_start = 1; - break; - } - - state &= ~NO_SEND_IV; - state |= NO_RECV_IV; - if (encrypt_debug_mode) - printf("Creating new feed\r\n"); - /* - * Create a random feed and send it over. - */ - do { - if (RAND_bytes(fbp->temp_feed, - sizeof(*fbp->temp_feed)) != 1) - abort(); - DES_set_odd_parity(&fbp->temp_feed); - } while(DES_is_weak_key(&fbp->temp_feed)); - - p = fbp->fb_feed + 3; - *p++ = ENCRYPT_IS; - p++; - *p++ = FB64_IV; - for (x = 0; x < sizeof(DES_cblock); ++x) { - if ((*p++ = fbp->temp_feed[x]) == IAC) - *p++ = IAC; - } - *p++ = IAC; - *p++ = SE; - printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]); - telnet_net_write(fbp->fb_feed, p - fbp->fb_feed); - break; - default: - return(FAILED); - } - return(fbp->state[dir-1] = state); -} - -/* - * Returns: - * -1: some error. Negotiation is done, encryption not ready. - * 0: Successful, initial negotiation all done. - * 1: successful, negotiation not done yet. - */ - -int cfb64_is(unsigned char *data, int cnt) -{ - return(fb64_is(data, cnt, &fb[CFB])); -} - -int ofb64_is(unsigned char *data, int cnt) -{ - return(fb64_is(data, cnt, &fb[OFB])); -} - - -int fb64_is(unsigned char *data, int cnt, struct fb *fbp) -{ - unsigned char *p; - int state = fbp->state[DIR_DECRYPT-1]; - - if (cnt-- < 1) - goto failure; - - switch (*data++) { - case FB64_IV: - if (cnt != sizeof(DES_cblock)) { - if (encrypt_debug_mode) - printf("CFB64: initial vector failed on size\r\n"); - state = FAILED; - goto failure; - } - - if (encrypt_debug_mode) - printf("CFB64: initial vector received\r\n"); - - if (encrypt_debug_mode) - printf("Initializing Decrypt stream\r\n"); - - fb64_stream_iv(data, &fbp->streams[DIR_DECRYPT-1]); - - p = fbp->fb_feed + 3; - *p++ = ENCRYPT_REPLY; - p++; - *p++ = FB64_IV_OK; - *p++ = IAC; - *p++ = SE; - printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]); - telnet_net_write(fbp->fb_feed, p - fbp->fb_feed); - - state = fbp->state[DIR_DECRYPT-1] = IN_PROGRESS; - break; - - default: - if (encrypt_debug_mode) { - printf("Unknown option type: %d\r\n", *(data-1)); - printd(data, cnt); - printf("\r\n"); - } - /* FALL THROUGH */ - failure: - /* - * We failed. Send an FB64_IV_BAD option - * to the other side so it will know that - * things failed. - */ - p = fbp->fb_feed + 3; - *p++ = ENCRYPT_REPLY; - p++; - *p++ = FB64_IV_BAD; - *p++ = IAC; - *p++ = SE; - printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]); - telnet_net_write(fbp->fb_feed, p - fbp->fb_feed); - - break; - } - return(fbp->state[DIR_DECRYPT-1] = state); -} - -/* - * Returns: - * -1: some error. Negotiation is done, encryption not ready. - * 0: Successful, initial negotiation all done. - * 1: successful, negotiation not done yet. - */ - -int cfb64_reply(unsigned char *data, int cnt) -{ - return(fb64_reply(data, cnt, &fb[CFB])); -} - -int ofb64_reply(unsigned char *data, int cnt) -{ - return(fb64_reply(data, cnt, &fb[OFB])); -} - - -int fb64_reply(unsigned char *data, int cnt, struct fb *fbp) -{ - int state = fbp->state[DIR_ENCRYPT-1]; - - if (cnt-- < 1) - goto failure; - - switch (*data++) { - case FB64_IV_OK: - fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]); - if (state == FAILED) - state = IN_PROGRESS; - state &= ~NO_RECV_IV; - encrypt_send_keyid(DIR_ENCRYPT, (unsigned char *)"\0", 1, 1); - break; - - case FB64_IV_BAD: - memset(fbp->temp_feed, 0, sizeof(DES_cblock)); - fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]); - state = FAILED; - break; - - default: - if (encrypt_debug_mode) { - printf("Unknown option type: %d\r\n", data[-1]); - printd(data, cnt); - printf("\r\n"); - } - /* FALL THROUGH */ - failure: - state = FAILED; - break; - } - return(fbp->state[DIR_ENCRYPT-1] = state); -} - -void cfb64_session(Session_Key *key, int server) -{ - fb64_session(key, server, &fb[CFB]); -} - -void ofb64_session(Session_Key *key, int server) -{ - fb64_session(key, server, &fb[OFB]); -} - -static void fb64_session(Session_Key *key, int server, struct fb *fbp) -{ - - if (!key || key->type != SK_DES) { - if (encrypt_debug_mode) - printf("Can't set krbdes's session key (%d != %d)\r\n", - key ? key->type : -1, SK_DES); - return; - } - memcpy(fbp->krbdes_key, key->data, sizeof(DES_cblock)); - - fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_ENCRYPT-1]); - fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_DECRYPT-1]); - - RAND_seed(key->data, key->length); - - DES_set_key_checked((DES_cblock *)&fbp->krbdes_key, - &fbp->krbdes_sched); - /* - * Now look to see if krbdes_start() was was waiting for - * the key to show up. If so, go ahead an call it now - * that we have the key. - */ - if (fbp->need_start) { - fbp->need_start = 0; - fb64_start(fbp, DIR_ENCRYPT, server); - } -} - -/* - * We only accept a keyid of 0. If we get a keyid of - * 0, then mark the state as SUCCESS. - */ - -int cfb64_keyid(int dir, unsigned char *kp, int *lenp) -{ - return(fb64_keyid(dir, kp, lenp, &fb[CFB])); -} - -int ofb64_keyid(int dir, unsigned char *kp, int *lenp) -{ - return(fb64_keyid(dir, kp, lenp, &fb[OFB])); -} - -int fb64_keyid(int dir, unsigned char *kp, int *lenp, struct fb *fbp) -{ - int state = fbp->state[dir-1]; - - if (*lenp != 1 || (*kp != '\0')) { - *lenp = 0; - return(state); - } - - if (state == FAILED) - state = IN_PROGRESS; - - state &= ~NO_KEYID; - - return(fbp->state[dir-1] = state); -} - -void fb64_printsub(unsigned char *data, size_t cnt, - unsigned char *buf, size_t buflen, char *type) -{ - char lbuf[32]; - int i; - char *cp; - - buf[buflen-1] = '\0'; /* make sure it's NULL terminated */ - buflen -= 1; - - switch(data[2]) { - case FB64_IV: - snprintf(lbuf, sizeof(lbuf), "%s_IV", type); - cp = lbuf; - goto common; - - case FB64_IV_OK: - snprintf(lbuf, sizeof(lbuf), "%s_IV_OK", type); - cp = lbuf; - goto common; - - case FB64_IV_BAD: - snprintf(lbuf, sizeof(lbuf), "%s_IV_BAD", type); - cp = lbuf; - goto common; - - default: - snprintf(lbuf, sizeof(lbuf), " %d (unknown)", data[2]); - cp = lbuf; - common: - for (; (buflen > 0) && (*buf = *cp++); buf++) - buflen--; - for (i = 3; i < cnt; i++) { - snprintf(lbuf, sizeof(lbuf), " %d", data[i]); - for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++) - buflen--; - } - break; - } -} - -void cfb64_printsub(unsigned char *data, size_t cnt, - unsigned char *buf, size_t buflen) -{ - fb64_printsub(data, cnt, buf, buflen, "CFB64"); -} - -void ofb64_printsub(unsigned char *data, size_t cnt, - unsigned char *buf, size_t buflen) -{ - fb64_printsub(data, cnt, buf, buflen, "OFB64"); -} - -void fb64_stream_iv(DES_cblock seed, struct stinfo *stp) -{ - - memcpy(stp->str_iv, seed,sizeof(DES_cblock)); - memcpy(stp->str_output, seed, sizeof(DES_cblock)); - - DES_set_key_checked(&stp->str_ikey, &stp->str_sched); - - stp->str_index = sizeof(DES_cblock); -} - -void fb64_stream_key(DES_cblock key, struct stinfo *stp) -{ - memcpy(stp->str_ikey, key, sizeof(DES_cblock)); - DES_set_key_checked((DES_cblock*)key, &stp->str_sched); - - memcpy(stp->str_output, stp->str_iv, sizeof(DES_cblock)); - - stp->str_index = sizeof(DES_cblock); -} - -/* - * DES 64 bit Cipher Feedback - * - * key --->+-----+ - * +->| DES |--+ - * | +-----+ | - * | v - * INPUT --(--------->(+)+---> DATA - * | | - * +-------------+ - * - * - * Given: - * iV: Initial vector, 64 bits (8 bytes) long. - * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt). - * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output. - * - * V0 = DES(iV, key) - * On = Dn ^ Vn - * V(n+1) = DES(On, key) - */ - -void cfb64_encrypt(unsigned char *s, int c) -{ - struct stinfo *stp = &fb[CFB].streams[DIR_ENCRYPT-1]; - int index; - - index = stp->str_index; - while (c-- > 0) { - if (index == sizeof(DES_cblock)) { - DES_cblock b; - DES_ecb_encrypt(&stp->str_output, &b,&stp->str_sched, 1); - memcpy(stp->str_feed, b, sizeof(DES_cblock)); - index = 0; - } - - /* On encryption, we store (feed ^ data) which is cypher */ - *s = stp->str_output[index] = (stp->str_feed[index] ^ *s); - s++; - index++; - } - stp->str_index = index; -} - -int cfb64_decrypt(int data) -{ - struct stinfo *stp = &fb[CFB].streams[DIR_DECRYPT-1]; - int index; - - if (data == -1) { - /* - * Back up one byte. It is assumed that we will - * never back up more than one byte. If we do, this - * may or may not work. - */ - if (stp->str_index) - --stp->str_index; - return(0); - } - - index = stp->str_index++; - if (index == sizeof(DES_cblock)) { - DES_cblock b; - DES_ecb_encrypt(&stp->str_output,&b, &stp->str_sched, 1); - memcpy(stp->str_feed, b, sizeof(DES_cblock)); - stp->str_index = 1; /* Next time will be 1 */ - index = 0; /* But now use 0 */ - } - - /* On decryption we store (data) which is cypher. */ - stp->str_output[index] = data; - return(data ^ stp->str_feed[index]); -} - -/* - * DES 64 bit Output Feedback - * - * key --->+-----+ - * +->| DES |--+ - * | +-----+ | - * +-----------+ - * v - * INPUT -------->(+) ----> DATA - * - * Given: - * iV: Initial vector, 64 bits (8 bytes) long. - * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt). - * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output. - * - * V0 = DES(iV, key) - * V(n+1) = DES(Vn, key) - * On = Dn ^ Vn - */ - -void ofb64_encrypt(unsigned char *s, int c) -{ - struct stinfo *stp = &fb[OFB].streams[DIR_ENCRYPT-1]; - int index; - - index = stp->str_index; - while (c-- > 0) { - if (index == sizeof(DES_cblock)) { - DES_cblock b; - DES_ecb_encrypt(&stp->str_feed,&b, &stp->str_sched, 1); - memcpy(stp->str_feed, b, sizeof(DES_cblock)); - index = 0; - } - *s++ ^= stp->str_feed[index]; - index++; - } - stp->str_index = index; -} - -int ofb64_decrypt(int data) -{ - struct stinfo *stp = &fb[OFB].streams[DIR_DECRYPT-1]; - int index; - - if (data == -1) { - /* - * Back up one byte. It is assumed that we will - * never back up more than one byte. If we do, this - * may or may not work. - */ - if (stp->str_index) - --stp->str_index; - return(0); - } - - index = stp->str_index++; - if (index == sizeof(DES_cblock)) { - DES_cblock b; - DES_ecb_encrypt(&stp->str_feed,&b,&stp->str_sched, 1); - memcpy(stp->str_feed, b, sizeof(DES_cblock)); - stp->str_index = 1; /* Next time will be 1 */ - index = 0; /* But now use 0 */ - } - - return(data ^ stp->str_feed[index]); -} -#endif - diff --git a/appl/telnet/libtelnet/encrypt.c b/appl/telnet/libtelnet/encrypt.c deleted file mode 100644 index bec94ce6d..000000000 --- a/appl/telnet/libtelnet/encrypt.c +++ /dev/null @@ -1,1003 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Copyright (C) 1990 by the Massachusetts Institute of Technology - * - * Export of this software from the United States of America is assumed - * to require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. - * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. - */ - - -#include - -RCSID("$Id$"); - -#if defined(ENCRYPTION) - -#define ENCRYPT_NAMES -#include - -#include -#include -#include -#include -#ifdef SOCKS -#include -#endif - -#include "encrypt.h" -#include "misc.h" - - -/* - * These functions pointers point to the current routines - * for encrypting and decrypting data. - */ -void (*encrypt_output) (unsigned char *, int); -int (*decrypt_input) (int); -char *nclearto; - -int encrypt_debug_mode = 0; -static int decrypt_mode = 0; -static int encrypt_mode = 0; -static int encrypt_verbose = 0; -static int autoencrypt = 0; -static int autodecrypt = 0; -static int havesessionkey = 0; -static int Server = 0; -static const char *Name = "Noname"; - -#define typemask(x) ((x) > 0 ? 1 << ((x)-1) : 0) - -static long i_support_encrypt = typemask(ENCTYPE_DES_CFB64) - | typemask(ENCTYPE_DES_OFB64); - static long i_support_decrypt = typemask(ENCTYPE_DES_CFB64) - | typemask(ENCTYPE_DES_OFB64); - static long i_wont_support_encrypt = 0; - static long i_wont_support_decrypt = 0; -#define I_SUPPORT_ENCRYPT (i_support_encrypt & ~i_wont_support_encrypt) -#define I_SUPPORT_DECRYPT (i_support_decrypt & ~i_wont_support_decrypt) - - static long remote_supports_encrypt = 0; - static long remote_supports_decrypt = 0; - - static Encryptions encryptions[] = { -#if defined(DES_ENCRYPTION) - { "DES_CFB64", ENCTYPE_DES_CFB64, - cfb64_encrypt, - cfb64_decrypt, - cfb64_init, - cfb64_start, - cfb64_is, - cfb64_reply, - cfb64_session, - cfb64_keyid, - cfb64_printsub }, - { "DES_OFB64", ENCTYPE_DES_OFB64, - ofb64_encrypt, - ofb64_decrypt, - ofb64_init, - ofb64_start, - ofb64_is, - ofb64_reply, - ofb64_session, - ofb64_keyid, - ofb64_printsub }, -#endif - { 0, }, - }; - -static unsigned char str_send[64] = { IAC, SB, TELOPT_ENCRYPT, - ENCRYPT_SUPPORT }; -static unsigned char str_suplen = 0; -static unsigned char str_start[72] = { IAC, SB, TELOPT_ENCRYPT }; -static unsigned char str_end[] = { IAC, SB, TELOPT_ENCRYPT, 0, IAC, SE }; - -Encryptions * -findencryption(int type) -{ - Encryptions *ep = encryptions; - - if (!(I_SUPPORT_ENCRYPT & remote_supports_decrypt & typemask(type))) - return(0); - while (ep->type && ep->type != type) - ++ep; - return(ep->type ? ep : 0); -} - -Encryptions * -finddecryption(int type) -{ - Encryptions *ep = encryptions; - - if (!(I_SUPPORT_DECRYPT & remote_supports_encrypt & typemask(type))) - return(0); - while (ep->type && ep->type != type) - ++ep; - return(ep->type ? ep : 0); -} - -#define MAXKEYLEN 64 - -static struct key_info { - unsigned char keyid[MAXKEYLEN]; - int keylen; - int dir; - int *modep; - Encryptions *(*getcrypt)(); -} ki[2] = { - { { 0 }, 0, DIR_ENCRYPT, &encrypt_mode, findencryption }, - { { 0 }, 0, DIR_DECRYPT, &decrypt_mode, finddecryption }, -}; - -void -encrypt_init(const char *name, int server) -{ - Encryptions *ep = encryptions; - - Name = name; - Server = server; - i_support_encrypt = i_support_decrypt = 0; - remote_supports_encrypt = remote_supports_decrypt = 0; - encrypt_mode = 0; - decrypt_mode = 0; - encrypt_output = 0; - decrypt_input = 0; -#ifdef notdef - encrypt_verbose = !server; -#endif - - str_suplen = 4; - - while (ep->type) { - if (encrypt_debug_mode) - printf(">>>%s: I will support %s\r\n", - Name, ENCTYPE_NAME(ep->type)); - i_support_encrypt |= typemask(ep->type); - i_support_decrypt |= typemask(ep->type); - if ((i_wont_support_decrypt & typemask(ep->type)) == 0) - if ((str_send[str_suplen++] = ep->type) == IAC) - str_send[str_suplen++] = IAC; - if (ep->init) - (*ep->init)(Server); - ++ep; - } - str_send[str_suplen++] = IAC; - str_send[str_suplen++] = SE; -} - -void -encrypt_list_types(void) -{ - Encryptions *ep = encryptions; - - printf("Valid encryption types:\n"); - while (ep->type) { - printf("\t%s (%d)\r\n", ENCTYPE_NAME(ep->type), ep->type); - ++ep; - } -} - -int -EncryptEnable(char *type, char *mode) -{ - if (isprefix(type, "help") || isprefix(type, "?")) { - printf("Usage: encrypt enable [input|output]\n"); - encrypt_list_types(); - return(0); - } - if (EncryptType(type, mode)) - return(EncryptStart(mode)); - return(0); -} - -int -EncryptDisable(char *type, char *mode) -{ - Encryptions *ep; - int ret = 0; - - if (isprefix(type, "help") || isprefix(type, "?")) { - printf("Usage: encrypt disable [input|output]\n"); - encrypt_list_types(); - } else if ((ep = (Encryptions *)genget(type, (char**)encryptions, - sizeof(Encryptions))) == 0) { - printf("%s: invalid encryption type\n", type); - } else if (Ambiguous(ep)) { - printf("Ambiguous type '%s'\n", type); - } else { - if ((mode == 0) || (isprefix(mode, "input") ? 1 : 0)) { - if (decrypt_mode == ep->type) - EncryptStopInput(); - i_wont_support_decrypt |= typemask(ep->type); - ret = 1; - } - if ((mode == 0) || (isprefix(mode, "output"))) { - if (encrypt_mode == ep->type) - EncryptStopOutput(); - i_wont_support_encrypt |= typemask(ep->type); - ret = 1; - } - if (ret == 0) - printf("%s: invalid encryption mode\n", mode); - } - return(ret); -} - -int -EncryptType(char *type, char *mode) -{ - Encryptions *ep; - int ret = 0; - - if (isprefix(type, "help") || isprefix(type, "?")) { - printf("Usage: encrypt type [input|output]\n"); - encrypt_list_types(); - } else if ((ep = (Encryptions *)genget(type, (char**)encryptions, - sizeof(Encryptions))) == 0) { - printf("%s: invalid encryption type\n", type); - } else if (Ambiguous(ep)) { - printf("Ambiguous type '%s'\n", type); - } else { - if ((mode == 0) || isprefix(mode, "input")) { - decrypt_mode = ep->type; - i_wont_support_decrypt &= ~typemask(ep->type); - ret = 1; - } - if ((mode == 0) || isprefix(mode, "output")) { - encrypt_mode = ep->type; - i_wont_support_encrypt &= ~typemask(ep->type); - ret = 1; - } - if (ret == 0) - printf("%s: invalid encryption mode\n", mode); - } - return(ret); -} - -int -EncryptStart(char *mode) -{ - int ret = 0; - if (mode) { - if (isprefix(mode, "input")) - return(EncryptStartInput()); - if (isprefix(mode, "output")) - return(EncryptStartOutput()); - if (isprefix(mode, "help") || isprefix(mode, "?")) { - printf("Usage: encrypt start [input|output]\n"); - return(0); - } - printf("%s: invalid encryption mode 'encrypt start ?' for help\n", mode); - return(0); - } - ret += EncryptStartInput(); - ret += EncryptStartOutput(); - return(ret); -} - -int -EncryptStartInput(void) -{ - if (decrypt_mode) { - encrypt_send_request_start(); - return(1); - } - printf("No previous decryption mode, decryption not enabled\r\n"); - return(0); -} - -int -EncryptStartOutput(void) -{ - if (encrypt_mode) { - encrypt_start_output(encrypt_mode); - return(1); - } - printf("No previous encryption mode, encryption not enabled\r\n"); - return(0); -} - -int -EncryptStop(char *mode) -{ - int ret = 0; - if (mode) { - if (isprefix(mode, "input")) - return(EncryptStopInput()); - if (isprefix(mode, "output")) - return(EncryptStopOutput()); - if (isprefix(mode, "help") || isprefix(mode, "?")) { - printf("Usage: encrypt stop [input|output]\n"); - return(0); - } - printf("%s: invalid encryption mode 'encrypt stop ?' for help\n", mode); - return(0); - } - ret += EncryptStopInput(); - ret += EncryptStopOutput(); - return(ret); -} - -int -EncryptStopInput(void) -{ - encrypt_send_request_end(); - return(1); -} - -int -EncryptStopOutput(void) -{ - encrypt_send_end(); - return(1); -} - -void -encrypt_display(void) -{ - printf("Autoencrypt for output is %s. Autodecrypt for input is %s.\r\n", - autoencrypt?"on":"off", autodecrypt?"on":"off"); - - if (encrypt_output) - printf("Currently encrypting output with %s\r\n", - ENCTYPE_NAME(encrypt_mode)); - else - printf("Currently not encrypting output\r\n"); - - if (decrypt_input) - printf("Currently decrypting input with %s\r\n", - ENCTYPE_NAME(decrypt_mode)); - else - printf("Currently not decrypting input\r\n"); -} - -int -EncryptStatus(void) -{ - printf("Autoencrypt for output is %s. Autodecrypt for input is %s.\r\n", - autoencrypt?"on":"off", autodecrypt?"on":"off"); - - if (encrypt_output) - printf("Currently encrypting output with %s\r\n", - ENCTYPE_NAME(encrypt_mode)); - else if (encrypt_mode) { - printf("Currently output is clear text.\r\n"); - printf("Last encryption mode was %s\r\n", - ENCTYPE_NAME(encrypt_mode)); - } else - printf("Currently not encrypting output\r\n"); - - if (decrypt_input) { - printf("Currently decrypting input with %s\r\n", - ENCTYPE_NAME(decrypt_mode)); - } else if (decrypt_mode) { - printf("Currently input is clear text.\r\n"); - printf("Last decryption mode was %s\r\n", - ENCTYPE_NAME(decrypt_mode)); - } else - printf("Currently not decrypting input\r\n"); - - return 1; -} - -void -encrypt_send_support(void) -{ - if (str_suplen) { - /* - * If the user has requested that decryption start - * immediatly, then send a "REQUEST START" before - * we negotiate the type. - */ - if (!Server && autodecrypt) - encrypt_send_request_start(); - telnet_net_write(str_send, str_suplen); - printsub('>', &str_send[2], str_suplen - 2); - str_suplen = 0; - } -} - -int -EncryptDebug(int on) -{ - if (on < 0) - encrypt_debug_mode ^= 1; - else - encrypt_debug_mode = on; - printf("Encryption debugging %s\r\n", - encrypt_debug_mode ? "enabled" : "disabled"); - return(1); -} - -/* turn on verbose encryption, but dont keep telling the whole world - */ -void encrypt_verbose_quiet(int on) -{ - if(on < 0) - encrypt_verbose ^= 1; - else - encrypt_verbose = on ? 1 : 0; -} - -int -EncryptVerbose(int on) -{ - encrypt_verbose_quiet(on); - printf("Encryption %s verbose\r\n", - encrypt_verbose ? "is" : "is not"); - return(1); -} - -int -EncryptAutoEnc(int on) -{ - encrypt_auto(on); - printf("Automatic encryption of output is %s\r\n", - autoencrypt ? "enabled" : "disabled"); - return(1); -} - -int -EncryptAutoDec(int on) -{ - decrypt_auto(on); - printf("Automatic decryption of input is %s\r\n", - autodecrypt ? "enabled" : "disabled"); - return(1); -} - -/* Called when we receive a WONT or a DONT ENCRYPT after we sent a DO - encrypt */ -void -encrypt_not(void) -{ - if (encrypt_verbose) - printf("[ Connection is NOT encrypted ]\r\n"); - else - printf("\r\n*** Connection not encrypted! " - "Communication may be eavesdropped. ***\r\n"); -} - -/* - * Called when ENCRYPT SUPPORT is received. - */ -void -encrypt_support(unsigned char *typelist, int cnt) -{ - int type, use_type = 0; - Encryptions *ep; - - /* - * Forget anything the other side has previously told us. - */ - remote_supports_decrypt = 0; - - while (cnt-- > 0) { - type = *typelist++; - if (encrypt_debug_mode) - printf(">>>%s: He is supporting %s (%d)\r\n", - Name, - ENCTYPE_NAME(type), type); - if ((type < ENCTYPE_CNT) && - (I_SUPPORT_ENCRYPT & typemask(type))) { - remote_supports_decrypt |= typemask(type); - if (use_type == 0) - use_type = type; - } - } - if (use_type) { - ep = findencryption(use_type); - if (!ep) - return; - type = ep->start ? (*ep->start)(DIR_ENCRYPT, Server) : 0; - if (encrypt_debug_mode) - printf(">>>%s: (*ep->start)() returned %d\r\n", - Name, type); - if (type < 0) - return; - encrypt_mode = use_type; - if (type == 0) - encrypt_start_output(use_type); - } -} - -void -encrypt_is(unsigned char *data, int cnt) -{ - Encryptions *ep; - int type, ret; - - if (--cnt < 0) - return; - type = *data++; - if (type < ENCTYPE_CNT) - remote_supports_encrypt |= typemask(type); - if (!(ep = finddecryption(type))) { - if (encrypt_debug_mode) - printf(">>>%s: Can't find type %s (%d) for initial negotiation\r\n", - Name, - ENCTYPE_NAME_OK(type) - ? ENCTYPE_NAME(type) : "(unknown)", - type); - return; - } - if (!ep->is) { - if (encrypt_debug_mode) - printf(">>>%s: No initial negotiation needed for type %s (%d)\r\n", - Name, - ENCTYPE_NAME_OK(type) - ? ENCTYPE_NAME(type) : "(unknown)", - type); - ret = 0; - } else { - ret = (*ep->is)(data, cnt); - if (encrypt_debug_mode) - printf("(*ep->is)(%p, %d) returned %s(%d)\n", data, cnt, - (ret < 0) ? "FAIL " : - (ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret); - } - if (ret < 0) { - autodecrypt = 0; - } else { - decrypt_mode = type; - if (ret == 0 && autodecrypt) - encrypt_send_request_start(); - } -} - -void -encrypt_reply(unsigned char *data, int cnt) -{ - Encryptions *ep; - int ret, type; - - if (--cnt < 0) - return; - type = *data++; - if (!(ep = findencryption(type))) { - if (encrypt_debug_mode) - printf(">>>%s: Can't find type %s (%d) for initial negotiation\r\n", - Name, - ENCTYPE_NAME_OK(type) - ? ENCTYPE_NAME(type) : "(unknown)", - type); - return; - } - if (!ep->reply) { - if (encrypt_debug_mode) - printf(">>>%s: No initial negotiation needed for type %s (%d)\r\n", - Name, - ENCTYPE_NAME_OK(type) - ? ENCTYPE_NAME(type) : "(unknown)", - type); - ret = 0; - } else { - ret = (*ep->reply)(data, cnt); - if (encrypt_debug_mode) - printf("(*ep->reply)(%p, %d) returned %s(%d)\n", - data, cnt, - (ret < 0) ? "FAIL " : - (ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret); - } - if (encrypt_debug_mode) - printf(">>>%s: encrypt_reply returned %d\n", Name, ret); - if (ret < 0) { - autoencrypt = 0; - } else { - encrypt_mode = type; - if (ret == 0 && autoencrypt) - encrypt_start_output(type); - } -} - -/* - * Called when ENCRYPT START is received. - */ -void -encrypt_start(unsigned char *data, int cnt) -{ - Encryptions *ep; - - if (!decrypt_mode) { - /* - * Something is wrong. We should not get a START - * command without having already picked our - * decryption scheme. Send a REQUEST-END to - * attempt to clear the channel... - */ - printf("%s: Warning, Cannot decrypt input stream!!!\r\n", Name); - encrypt_send_request_end(); - return; - } - - if ((ep = finddecryption(decrypt_mode))) { - decrypt_input = ep->input; - if (encrypt_verbose) - printf("[ Input is now decrypted with type %s ]\r\n", - ENCTYPE_NAME(decrypt_mode)); - if (encrypt_debug_mode) - printf(">>>%s: Start to decrypt input with type %s\r\n", - Name, ENCTYPE_NAME(decrypt_mode)); - } else { - printf("%s: Warning, Cannot decrypt type %s (%d)!!!\r\n", - Name, - ENCTYPE_NAME_OK(decrypt_mode) - ? ENCTYPE_NAME(decrypt_mode) - : "(unknown)", - decrypt_mode); - encrypt_send_request_end(); - } -} - -void -encrypt_session_key(Session_Key *key, int server) -{ - Encryptions *ep = encryptions; - - havesessionkey = 1; - - while (ep->type) { - if (ep->session) - (*ep->session)(key, server); - ++ep; - } -} - -/* - * Called when ENCRYPT END is received. - */ -void -encrypt_end(void) -{ - decrypt_input = 0; - if (encrypt_debug_mode) - printf(">>>%s: Input is back to clear text\r\n", Name); - if (encrypt_verbose) - printf("[ Input is now clear text ]\r\n"); -} - -/* - * Called when ENCRYPT REQUEST-END is received. - */ -void -encrypt_request_end(void) -{ - encrypt_send_end(); -} - -/* - * Called when ENCRYPT REQUEST-START is received. If we receive - * this before a type is picked, then that indicates that the - * other side wants us to start encrypting data as soon as we - * can. - */ -void -encrypt_request_start(unsigned char *data, int cnt) -{ - if (encrypt_mode == 0) { - if (Server) - autoencrypt = 1; - return; - } - encrypt_start_output(encrypt_mode); -} - -static unsigned char str_keyid[(MAXKEYLEN*2)+5] = { IAC, SB, TELOPT_ENCRYPT }; - -static void -encrypt_keyid(struct key_info *kp, unsigned char *keyid, int len) -{ - Encryptions *ep; - int dir = kp->dir; - int ret = 0; - - if (!(ep = (*kp->getcrypt)(*kp->modep))) { - if (len == 0) - return; - kp->keylen = 0; - } else if (len == 0) { - /* - * Empty option, indicates a failure. - */ - if (kp->keylen == 0) - return; - kp->keylen = 0; - if (ep->keyid) - (void)(*ep->keyid)(dir, kp->keyid, &kp->keylen); - - } else if ((len != kp->keylen) || (memcmp(keyid,kp->keyid,len) != 0)) { - /* - * Length or contents are different - */ - kp->keylen = len; - memcpy(kp->keyid,keyid, len); - if (ep->keyid) - (void)(*ep->keyid)(dir, kp->keyid, &kp->keylen); - } else { - if (ep->keyid) - ret = (*ep->keyid)(dir, kp->keyid, &kp->keylen); - if ((ret == 0) && (dir == DIR_ENCRYPT) && autoencrypt) - encrypt_start_output(*kp->modep); - return; - } - - encrypt_send_keyid(dir, kp->keyid, kp->keylen, 0); -} - -void encrypt_enc_keyid(unsigned char *keyid, int len) -{ - encrypt_keyid(&ki[1], keyid, len); -} - -void encrypt_dec_keyid(unsigned char *keyid, int len) -{ - encrypt_keyid(&ki[0], keyid, len); -} - - -void encrypt_send_keyid(int dir, unsigned char *keyid, int keylen, int saveit) -{ - unsigned char *strp; - - str_keyid[3] = (dir == DIR_ENCRYPT) - ? ENCRYPT_ENC_KEYID : ENCRYPT_DEC_KEYID; - if (saveit) { - struct key_info *kp = &ki[(dir == DIR_ENCRYPT) ? 0 : 1]; - memcpy(kp->keyid,keyid, keylen); - kp->keylen = keylen; - } - - for (strp = &str_keyid[4]; keylen > 0; --keylen) { - if ((*strp++ = *keyid++) == IAC) - *strp++ = IAC; - } - *strp++ = IAC; - *strp++ = SE; - telnet_net_write(str_keyid, strp - str_keyid); - printsub('>', &str_keyid[2], strp - str_keyid - 2); -} - -void -encrypt_auto(int on) -{ - if (on < 0) - autoencrypt ^= 1; - else - autoencrypt = on ? 1 : 0; -} - -void -decrypt_auto(int on) -{ - if (on < 0) - autodecrypt ^= 1; - else - autodecrypt = on ? 1 : 0; -} - -void -encrypt_start_output(int type) -{ - Encryptions *ep; - unsigned char *p; - int i; - - if (!(ep = findencryption(type))) { - if (encrypt_debug_mode) { - printf(">>>%s: Can't encrypt with type %s (%d)\r\n", - Name, - ENCTYPE_NAME_OK(type) - ? ENCTYPE_NAME(type) : "(unknown)", - type); - } - return; - } - if (ep->start) { - i = (*ep->start)(DIR_ENCRYPT, Server); - if (encrypt_debug_mode) { - printf(">>>%s: Encrypt start: %s (%d) %s\r\n", - Name, - (i < 0) ? "failed" : - "initial negotiation in progress", - i, ENCTYPE_NAME(type)); - } - if (i) - return; - } - p = str_start + 3; - *p++ = ENCRYPT_START; - for (i = 0; i < ki[0].keylen; ++i) { - if ((*p++ = ki[0].keyid[i]) == IAC) - *p++ = IAC; - } - *p++ = IAC; - *p++ = SE; - telnet_net_write(str_start, p - str_start); - net_encrypt(); - printsub('>', &str_start[2], p - &str_start[2]); - /* - * If we are already encrypting in some mode, then - * encrypt the ring (which includes our request) in - * the old mode, mark it all as "clear text" and then - * switch to the new mode. - */ - encrypt_output = ep->output; - encrypt_mode = type; - if (encrypt_debug_mode) - printf(">>>%s: Started to encrypt output with type %s\r\n", - Name, ENCTYPE_NAME(type)); - if (encrypt_verbose) - printf("[ Output is now encrypted with type %s ]\r\n", - ENCTYPE_NAME(type)); -} - -void -encrypt_send_end(void) -{ - if (!encrypt_output) - return; - - str_end[3] = ENCRYPT_END; - telnet_net_write(str_end, sizeof(str_end)); - net_encrypt(); - printsub('>', &str_end[2], sizeof(str_end) - 2); - /* - * Encrypt the output buffer now because it will not be done by - * netflush... - */ - encrypt_output = 0; - if (encrypt_debug_mode) - printf(">>>%s: Output is back to clear text\r\n", Name); - if (encrypt_verbose) - printf("[ Output is now clear text ]\r\n"); -} - -void -encrypt_send_request_start(void) -{ - unsigned char *p; - int i; - - p = &str_start[3]; - *p++ = ENCRYPT_REQSTART; - for (i = 0; i < ki[1].keylen; ++i) { - if ((*p++ = ki[1].keyid[i]) == IAC) - *p++ = IAC; - } - *p++ = IAC; - *p++ = SE; - telnet_net_write(str_start, p - str_start); - printsub('>', &str_start[2], p - &str_start[2]); - if (encrypt_debug_mode) - printf(">>>%s: Request input to be encrypted\r\n", Name); -} - -void -encrypt_send_request_end(void) -{ - str_end[3] = ENCRYPT_REQEND; - telnet_net_write(str_end, sizeof(str_end)); - printsub('>', &str_end[2], sizeof(str_end) - 2); - - if (encrypt_debug_mode) - printf(">>>%s: Request input to be clear text\r\n", Name); -} - - -void encrypt_wait(void) -{ - if (encrypt_debug_mode) - printf(">>>%s: in encrypt_wait\r\n", Name); - if (!havesessionkey || !(I_SUPPORT_ENCRYPT & remote_supports_decrypt)) - return; - while (autoencrypt && !encrypt_output) - if (telnet_spin()) - return; -} - -int -encrypt_delay(void) -{ - if(!havesessionkey || - (I_SUPPORT_ENCRYPT & remote_supports_decrypt) == 0 || - (I_SUPPORT_DECRYPT & remote_supports_encrypt) == 0) - return 0; - if(!(encrypt_output && decrypt_input)) - return 1; - return 0; -} - -int encrypt_is_encrypting() -{ - if (encrypt_output && decrypt_input) - return 1; - return 0; -} - -void -encrypt_debug(int mode) -{ - encrypt_debug_mode = mode; -} - -void encrypt_gen_printsub(unsigned char *data, size_t cnt, - unsigned char *buf, size_t buflen) -{ - char tbuf[16], *cp; - - cnt -= 2; - data += 2; - buf[buflen-1] = '\0'; - buf[buflen-2] = '*'; - buflen -= 2;; - for (; cnt > 0; cnt--, data++) { - snprintf(tbuf, sizeof(tbuf), " %d", *data); - for (cp = tbuf; *cp && buflen > 0; --buflen) - *buf++ = *cp++; - if (buflen <= 0) - return; - } - *buf = '\0'; -} - -void -encrypt_printsub(unsigned char *data, size_t cnt, - unsigned char *buf, size_t buflen) -{ - Encryptions *ep; - int type = data[1]; - - for (ep = encryptions; ep->type && ep->type != type; ep++) - ; - - if (ep->printsub) - (*ep->printsub)(data, cnt, buf, buflen); - else - encrypt_gen_printsub(data, cnt, buf, buflen); -} -#endif diff --git a/appl/telnet/libtelnet/encrypt.h b/appl/telnet/libtelnet/encrypt.h deleted file mode 100644 index 3b2785c3f..000000000 --- a/appl/telnet/libtelnet/encrypt.h +++ /dev/null @@ -1,103 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)encrypt.h 8.1 (Berkeley) 6/4/93 - * - * @(#)encrypt.h 5.2 (Berkeley) 3/22/91 - */ - -/* - * Copyright (C) 1990 by the Massachusetts Institute of Technology - * - * Export of this software from the United States of America is assumed - * to require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. - * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. - */ - -/* $Id$ */ - -#ifndef __ENCRYPT__ -#define __ENCRYPT__ - -#define DIR_DECRYPT 1 -#define DIR_ENCRYPT 2 - -#define VALIDKEY(key) ( key[0] | key[1] | key[2] | key[3] | \ - key[4] | key[5] | key[6] | key[7]) - -#define SAMEKEY(k1, k2) (!memcmp(k1, k2, sizeof(des_cblock))) - -typedef struct { - short type; - int length; - unsigned char *data; -} Session_Key; - -typedef struct { - char *name; - int type; - void (*output) (unsigned char *, int); - int (*input) (int); - void (*init) (int); - int (*start) (int, int); - int (*is) (unsigned char *, int); - int (*reply) (unsigned char *, int); - void (*session) (Session_Key *, int); - int (*keyid) (int, unsigned char *, int *); - void (*printsub) (unsigned char *, size_t, unsigned char *, size_t); -} Encryptions; - -#define SK_DES 1 /* Matched Kerberos v5 KEYTYPE_DES */ - -#include "crypto-headers.h" -#ifdef HAVE_OPENSSL -#define des_new_random_key des_random_key -#endif - -#include "enc-proto.h" - -extern int encrypt_debug_mode; -extern int (*decrypt_input) (int); -extern void (*encrypt_output) (unsigned char *, int); -#endif diff --git a/appl/telnet/libtelnet/genget.c b/appl/telnet/libtelnet/genget.c deleted file mode 100644 index 4dd5e2949..000000000 --- a/appl/telnet/libtelnet/genget.c +++ /dev/null @@ -1,106 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#include -#include "misc-proto.h" - -RCSID("$Id$"); - - -#define LOWER(x) (isupper(x) ? tolower(x) : (x)) -/* - * The prefix function returns 0 if *s1 is not a prefix - * of *s2. If *s1 exactly matches *s2, the negative of - * the length is returned. If *s1 is a prefix of *s2, - * the length of *s1 is returned. - */ - -int -isprefix(char *s1, char *s2) -{ - char *os1; - char c1, c2; - - if (*s1 == '\0') - return(-1); - os1 = s1; - c1 = *s1; - c2 = *s2; - while (tolower((unsigned char)c1) == tolower((unsigned char)c2)) { - if (c1 == '\0') - break; - c1 = *++s1; - c2 = *++s2; - } - return(*s1 ? 0 : (*s2 ? (s1 - os1) : (os1 - s1))); -} - -static char *ambiguous; /* special return value for command routines */ - -char ** -genget(char *name, char **table, int stlen) - /* name to match */ - /* name entry in table */ - -{ - char **c, **found; - int n; - - if (name == 0) - return 0; - - found = 0; - for (c = table; *c != 0; c = (char **)((char *)c + stlen)) { - if ((n = isprefix(name, *c)) == 0) - continue; - if (n < 0) /* exact match */ - return(c); - if (found) - return(&ambiguous); - found = c; - } - return(found); -} - -/* - * Function call version of Ambiguous() - */ -int -Ambiguous(void *s) -{ - return((char **)s == &ambiguous); -} diff --git a/appl/telnet/libtelnet/kerberos5.c b/appl/telnet/libtelnet/kerberos5.c deleted file mode 100644 index e89eb9508..000000000 --- a/appl/telnet/libtelnet/kerberos5.c +++ /dev/null @@ -1,897 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Copyright (C) 1990 by the Massachusetts Institute of Technology - * - * Export of this software from the United States of America may - * require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. - * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. - */ - -#include - -RCSID("$Id$"); - -#ifdef KRB5 - -#include -#include -#include -#include -#include -#include -#include -#include -#define Authenticator k5_Authenticator -#include -#undef Authenticator -#include -#ifdef SOCKS -#include -#endif - - -#include "encrypt.h" -#include "auth.h" -#include "misc.h" - -#if defined(DCE) -int dfsk5ok = 0; -int dfspag = 0; -int dfsfwd = 0; -#endif - -int forward_flags = 0; /* Flags get set in telnet/main.c on -f and -F */ - -int forward(int); -int forwardable(int); - -/* These values need to be the same as those defined in telnet/main.c. */ -/* Either define them in both places, or put in some common header file. */ -#define OPTS_FORWARD_CREDS 0x00000002 -#define OPTS_FORWARDABLE_CREDS 0x00000001 - - -void kerberos5_forward (Authenticator *); - -static unsigned char str_data[4] = { IAC, SB, TELOPT_AUTHENTICATION, 0 }; - -#define KRB_AUTH 0 /* Authentication data follows */ -#define KRB_REJECT 1 /* Rejected (reason might follow) */ -#define KRB_ACCEPT 2 /* Accepted */ -#define KRB_RESPONSE 3 /* Response for mutual auth. */ - -#define KRB_FORWARD 4 /* Forwarded credentials follow */ -#define KRB_FORWARD_ACCEPT 5 /* Forwarded credentials accepted */ -#define KRB_FORWARD_REJECT 6 /* Forwarded credentials rejected */ - -static krb5_data auth; -static krb5_ticket *ticket; - -static krb5_context context; -static krb5_auth_context auth_context; - -static int -Data(Authenticator *ap, int type, const void *d, int c) -{ - const unsigned char *cp, *cd = d; - unsigned char *p0, *p; - size_t len = sizeof(str_data) + 3 + 2; - int ret; - - if (c == -1) - c = strlen((const char*)cd); - - for (cp = cd; cp - cd < c; cp++, len++) - if (*cp == IAC) - len++; - - p0 = malloc(len); - if (p0 == NULL) - return 0; - - memcpy(p0, str_data, sizeof(str_data)); - p = p0 + sizeof(str_data); - - if (auth_debug_mode) { - printf("%s:%d: [%d] (%d)", - str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", - str_data[3], - type, c); - printd(d, c); - printf("\r\n"); - } - *p++ = ap->type; - *p++ = ap->way; - *p++ = type; - while (c-- > 0) { - if ((*p++ = *cd++) == IAC) - *p++ = IAC; - } - *p++ = IAC; - *p++ = SE; - if (str_data[3] == TELQUAL_IS) - printsub('>', &p0[2], len - 2); - ret = telnet_net_write(p0, len); - free(p0); - return ret; -} - -int -kerberos5_init(Authenticator *ap, int server) -{ - krb5_error_code ret; - - ret = krb5_init_context(&context); - if (ret) - return 0; - if (server) { - krb5_keytab kt; - krb5_kt_cursor cursor; - - ret = krb5_kt_default(context, &kt); - if (ret) - return 0; - - ret = krb5_kt_start_seq_get (context, kt, &cursor); - if (ret) { - krb5_kt_close (context, kt); - return 0; - } - krb5_kt_end_seq_get (context, kt, &cursor); - krb5_kt_close (context, kt); - - str_data[3] = TELQUAL_REPLY; - } else - str_data[3] = TELQUAL_IS; - return(1); -} - -extern int net; -static int -kerberos5_send(char *name, Authenticator *ap) -{ - krb5_error_code ret; - krb5_ccache ccache; - int ap_opts; - krb5_data cksum_data; - char ap_msg[2]; - - if (!UserNameRequested) { - if (auth_debug_mode) { - printf("Kerberos V5: no user name supplied\r\n"); - } - return(0); - } - - ret = krb5_cc_default(context, &ccache); - if (ret) { - if (auth_debug_mode) { - printf("Kerberos V5: could not get default ccache: %s\r\n", - krb5_get_err_text (context, ret)); - } - return 0; - } - - if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) - ap_opts = AP_OPTS_MUTUAL_REQUIRED; - else - ap_opts = 0; - - ap_opts |= AP_OPTS_USE_SUBKEY; - - ret = krb5_auth_con_init (context, &auth_context); - if (ret) { - if (auth_debug_mode) { - printf("Kerberos V5: krb5_auth_con_init failed (%s)\r\n", - krb5_get_err_text(context, ret)); - } - return(0); - } - - ret = krb5_auth_con_setaddrs_from_fd (context, - auth_context, - &net); - if (ret) { - if (auth_debug_mode) { - printf ("Kerberos V5:" - " krb5_auth_con_setaddrs_from_fd failed (%s)\r\n", - krb5_get_err_text(context, ret)); - } - return(0); - } - - krb5_auth_con_setkeytype (context, auth_context, KEYTYPE_DES); - - ap_msg[0] = ap->type; - ap_msg[1] = ap->way; - - cksum_data.length = sizeof(ap_msg); - cksum_data.data = ap_msg; - - - { - krb5_principal service; - char sname[128]; - - - ret = krb5_sname_to_principal (context, - RemoteHostName, - NULL, - KRB5_NT_SRV_HST, - &service); - if(ret) { - if (auth_debug_mode) { - printf ("Kerberos V5:" - " krb5_sname_to_principal(%s) failed (%s)\r\n", - RemoteHostName, krb5_get_err_text(context, ret)); - } - return 0; - } - ret = krb5_unparse_name_fixed(context, service, sname, sizeof(sname)); - if(ret) { - if (auth_debug_mode) { - printf ("Kerberos V5:" - " krb5_unparse_name_fixed failed (%s)\r\n", - krb5_get_err_text(context, ret)); - } - return 0; - } - printf("[ Trying %s (%s)... ]\r\n", name, sname); - ret = krb5_mk_req_exact(context, &auth_context, ap_opts, - service, - &cksum_data, ccache, &auth); - krb5_free_principal (context, service); - - } - if (ret) { - if (1 || auth_debug_mode) { - printf("Kerberos V5: mk_req failed (%s)\r\n", - krb5_get_err_text(context, ret)); - } - return(0); - } - - if (!auth_sendname((unsigned char *)UserNameRequested, - strlen(UserNameRequested))) { - if (auth_debug_mode) - printf("Not enough room for user name\r\n"); - return(0); - } - if (!Data(ap, KRB_AUTH, auth.data, auth.length)) { - if (auth_debug_mode) - printf("Not enough room for authentication data\r\n"); - return(0); - } - if (auth_debug_mode) { - printf("Sent Kerberos V5 credentials to server\r\n"); - } - return(1); -} - -int -kerberos5_send_mutual(Authenticator *ap) -{ - return kerberos5_send("mutual KERBEROS5", ap); -} - -int -kerberos5_send_oneway(Authenticator *ap) -{ - return kerberos5_send("KERBEROS5", ap); -} - -static void log_message(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - if (auth_debug_mode) { - va_start(ap, fmt); - vfprintf(stdout, fmt, ap); - va_end(ap); - fprintf(stdout, "\r\n"); - } - va_start(ap, fmt); - vsyslog(LOG_NOTICE, fmt, ap); - va_end(ap); -} - -void -kerberos5_is(Authenticator *ap, unsigned char *data, int cnt) -{ - krb5_error_code ret; - krb5_data outbuf; - krb5_keyblock *key_block; - char *name; - krb5_principal server; - int zero = 0; - - if (cnt-- < 1) - return; - switch (*data++) { - case KRB_AUTH: - auth.data = (char *)data; - auth.length = cnt; - - auth_context = NULL; - - ret = krb5_auth_con_init (context, &auth_context); - if (ret) { - Data(ap, KRB_REJECT, "krb5_auth_con_init failed", -1); - auth_finished(ap, AUTH_REJECT); - log_message("Kerberos V5: krb5_auth_con_init failed (%s)", - krb5_get_err_text(context, ret)); - return; - } - - ret = krb5_auth_con_setaddrs_from_fd (context, - auth_context, - &zero); - if (ret) { - Data(ap, KRB_REJECT, "krb5_auth_con_setaddrs_from_fd failed", -1); - auth_finished(ap, AUTH_REJECT); - log_message("Kerberos V5: " - "krb5_auth_con_setaddrs_from_fd failed (%s)", - krb5_get_err_text(context, ret)); - return; - } - - ret = krb5_sock_to_principal (context, - 0, - "host", - KRB5_NT_SRV_HST, - &server); - if (ret) { - Data(ap, KRB_REJECT, "krb5_sock_to_principal failed", -1); - auth_finished(ap, AUTH_REJECT); - log_message("Kerberos V5: " - "krb5_sock_to_principal failed (%s)", - krb5_get_err_text(context, ret)); - return; - } - - ret = krb5_rd_req(context, - &auth_context, - &auth, - server, - NULL, - NULL, - &ticket); - - krb5_free_principal (context, server); - if (ret) { - const char *errbuf2 = "Read req failed"; - char *errbuf; - int ret2; - - ret2 = asprintf(&errbuf, - "Read req failed: %s", - krb5_get_err_text(context, ret)); - if (ret2 != -1) - errbuf2 = errbuf; - Data(ap, KRB_REJECT, errbuf2, -1); - log_message("%s", errbuf2); - if (ret2 != -1) - free (errbuf); - return; - } - - { - char ap_msg[2]; - - ap_msg[0] = ap->type; - ap_msg[1] = ap->way; - - ret = krb5_verify_authenticator_checksum(context, - auth_context, - ap_msg, - sizeof(ap_msg)); - - if (ret) { - const char *errbuf2 = "Bad checksum"; - char *errbuf; - int ret2; - - ret2 = asprintf(&errbuf, "Bad checksum: %s", - krb5_get_err_text(context, ret)); - if (ret2 != -1) - errbuf2 = errbuf; - Data(ap, KRB_REJECT, errbuf2, -1); - log_message("%s", errbuf2); - if (ret2 != -1) - free(errbuf); - return; - } - } - ret = krb5_auth_con_getremotesubkey (context, - auth_context, - &key_block); - - if (ret) { - Data(ap, KRB_REJECT, "krb5_auth_con_getremotesubkey failed", -1); - auth_finished(ap, AUTH_REJECT); - log_message("Kerberos V5: " - "krb5_auth_con_getremotesubkey failed (%s)", - krb5_get_err_text(context, ret)); - return; - } - - if (key_block == NULL) { - ret = krb5_auth_con_getkey(context, - auth_context, - &key_block); - } - if (ret) { - Data(ap, KRB_REJECT, "krb5_auth_con_getkey failed", -1); - auth_finished(ap, AUTH_REJECT); - log_message("Kerberos V5: " - "krb5_auth_con_getkey failed (%s)", - krb5_get_err_text(context, ret)); - return; - } - if (key_block == NULL) { - Data(ap, KRB_REJECT, "no subkey received", -1); - auth_finished(ap, AUTH_REJECT); - log_message("Kerberos V5: " - "krb5_auth_con_getremotesubkey returned NULL key"); - return; - } - - if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { - ret = krb5_mk_rep(context, auth_context, &outbuf); - if (ret) { - Data(ap, KRB_REJECT, - "krb5_mk_rep failed", -1); - auth_finished(ap, AUTH_REJECT); - log_message("Kerberos V5: " - "krb5_mk_rep failed (%s)", - krb5_get_err_text(context, ret)); - krb5_free_keyblock(context, key_block); - return; - } - Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length); - } - if (krb5_unparse_name(context, ticket->client, &name)) - name = 0; - - if(UserNameRequested && krb5_kuserok(context, - ticket->client, - UserNameRequested)) { - Data(ap, KRB_ACCEPT, name, name ? -1 : 0); - log_message("%s accepted as user %s from %s", - name ? name : "", - UserNameRequested ? UserNameRequested : "", - RemoteHostName ? RemoteHostName : ""); - - if(key_block->keytype == ETYPE_DES_CBC_MD5 || - key_block->keytype == ETYPE_DES_CBC_MD4 || - key_block->keytype == ETYPE_DES_CBC_CRC) { - Session_Key skey; - - skey.type = SK_DES; - skey.length = 8; - skey.data = key_block->keyvalue.data; - encrypt_session_key(&skey, 0); - } - - } else { - const char *msg2 = "user is not authorized to login"; - char *msg; - - ret = asprintf (&msg, "user `%s' is not authorized to " - "login as `%s'", - name ? name : "", - UserNameRequested ? UserNameRequested : ""); - if (ret != -1) - msg2 = msg; - Data(ap, KRB_REJECT, (void *)msg2, -1); - if (ret != -1) - free(msg); - auth_finished (ap, AUTH_REJECT); - krb5_free_keyblock(context, key_block); - break; - } - auth_finished(ap, AUTH_USER); - krb5_free_keyblock(context, key_block); - - break; - case KRB_FORWARD: { - struct passwd *pwd; - char ccname[1024]; /* XXX */ - krb5_data inbuf; - krb5_ccache ccache; - inbuf.data = (char *)data; - inbuf.length = cnt; - - pwd = getpwnam (UserNameRequested); - if (pwd == NULL) - break; - - snprintf (ccname, sizeof(ccname), - "FILE:/tmp/krb5cc_%lu", (unsigned long)pwd->pw_uid); - - ret = krb5_cc_resolve (context, ccname, &ccache); - if (ret) { - log_message("Kerberos V5: could not get ccache: %s", - krb5_get_err_text(context, ret)); - break; - } - - ret = krb5_cc_initialize (context, - ccache, - ticket->client); - if (ret) { - log_message("Kerberos V5: could not init ccache: %s", - krb5_get_err_text(context, ret)); - break; - } - -#if defined(DCE) - esetenv("KRB5CCNAME", ccname, 1); -#endif - ret = krb5_rd_cred2 (context, - auth_context, - ccache, - &inbuf); - if(ret) { - const char *errbuf2 = "Read forwarded creds failed"; - char *errbuf; - int ret2; - - ret2 = asprintf (&errbuf, - "Read forwarded creds failed: %s", - krb5_get_err_text (context, ret)); - if (ret2 != -1) - errbuf2 = errbuf; - Data(ap, KRB_FORWARD_REJECT, errbuf, -1); - log_message("Could not read forwarded credentials: %s", errbuf); - - if (ret2 != -1) - free (errbuf); - } else { - Data(ap, KRB_FORWARD_ACCEPT, 0, 0); -#if defined(DCE) - dfsfwd = 1; -#endif - } - chown (ccname + 5, pwd->pw_uid, -1); - log_message("Forwarded credentials obtained"); - break; - } - default: - log_message("Unknown Kerberos option %d", data[-1]); - Data(ap, KRB_REJECT, 0, 0); - break; - } -} - -void -kerberos5_reply(Authenticator *ap, unsigned char *data, int cnt) -{ - static int mutual_complete = 0; - - if (cnt-- < 1) - return; - switch (*data++) { - case KRB_REJECT: - if (cnt > 0) { - printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n", - cnt, data); - } else - printf("[ Kerberos V5 refuses authentication ]\r\n"); - auth_send_retry(); - return; - case KRB_ACCEPT: { - krb5_error_code ret; - Session_Key skey; - krb5_keyblock *keyblock; - - if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && - !mutual_complete) { - printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n"); - auth_send_retry(); - return; - } - if (cnt) - printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data); - else - printf("[ Kerberos V5 accepts you ]\r\n"); - - ret = krb5_auth_con_getlocalsubkey (context, - auth_context, - &keyblock); - if (ret) - ret = krb5_auth_con_getkey (context, - auth_context, - &keyblock); - if(ret) { - printf("[ krb5_auth_con_getkey: %s ]\r\n", - krb5_get_err_text(context, ret)); - auth_send_retry(); - return; - } - - skey.type = SK_DES; - skey.length = 8; - skey.data = keyblock->keyvalue.data; - encrypt_session_key(&skey, 0); - krb5_free_keyblock (context, keyblock); - auth_finished(ap, AUTH_USER); - if (forward_flags & OPTS_FORWARD_CREDS) - kerberos5_forward(ap); - break; - } - case KRB_RESPONSE: - if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { - /* the rest of the reply should contain a krb_ap_rep */ - krb5_ap_rep_enc_part *reply; - krb5_data inbuf; - krb5_error_code ret; - - inbuf.length = cnt; - inbuf.data = (char *)data; - - ret = krb5_rd_rep(context, auth_context, &inbuf, &reply); - if (ret) { - printf("[ Mutual authentication failed: %s ]\r\n", - krb5_get_err_text (context, ret)); - auth_send_retry(); - return; - } - krb5_free_ap_rep_enc_part(context, reply); - mutual_complete = 1; - } - return; - case KRB_FORWARD_ACCEPT: - printf("[ Kerberos V5 accepted forwarded credentials ]\r\n"); - return; - case KRB_FORWARD_REJECT: - printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n", - cnt, data); - return; - default: - if (auth_debug_mode) - printf("Unknown Kerberos option %d\r\n", data[-1]); - return; - } -} - -int -kerberos5_status(Authenticator *ap, char *name, size_t name_sz, int level) -{ - if (level < AUTH_USER) - return(level); - - if (UserNameRequested && - krb5_kuserok(context, - ticket->client, - UserNameRequested)) - { - strlcpy(name, UserNameRequested, name_sz); -#if defined(DCE) - dfsk5ok = 1; -#endif - return(AUTH_VALID); - } else - return(AUTH_USER); -} - -#define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} -#define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);} - -void -kerberos5_printsub(unsigned char *data, size_t cnt, - unsigned char *buf, size_t buflen) -{ - int i; - - buf[buflen-1] = '\0'; /* make sure it's NULL terminated */ - buflen -= 1; - - switch(data[3]) { - case KRB_REJECT: /* Rejected (reason might follow) */ - strlcpy((char *)buf, " REJECT ", buflen); - goto common; - - case KRB_ACCEPT: /* Accepted (name might follow) */ - strlcpy((char *)buf, " ACCEPT ", buflen); - common: - BUMP(buf, buflen); - if (cnt <= 4) - break; - ADDC(buf, buflen, '"'); - for (i = 4; i < cnt; i++) - ADDC(buf, buflen, data[i]); - ADDC(buf, buflen, '"'); - ADDC(buf, buflen, '\0'); - break; - - - case KRB_AUTH: /* Authentication data follows */ - strlcpy((char *)buf, " AUTH", buflen); - goto common2; - - case KRB_RESPONSE: - strlcpy((char *)buf, " RESPONSE", buflen); - goto common2; - - case KRB_FORWARD: /* Forwarded credentials follow */ - strlcpy((char *)buf, " FORWARD", buflen); - goto common2; - - case KRB_FORWARD_ACCEPT: /* Forwarded credentials accepted */ - strlcpy((char *)buf, " FORWARD_ACCEPT", buflen); - goto common2; - - case KRB_FORWARD_REJECT: /* Forwarded credentials rejected */ - /* (reason might follow) */ - strlcpy((char *)buf, " FORWARD_REJECT", buflen); - goto common2; - - default: - snprintf((char*)buf, buflen, " %d (unknown)", data[3]); - common2: - BUMP(buf, buflen); - for (i = 4; i < cnt; i++) { - snprintf((char*)buf, buflen, " %d", data[i]); - BUMP(buf, buflen); - } - break; - } -} - -void -kerberos5_forward(Authenticator *ap) -{ - krb5_error_code ret; - krb5_ccache ccache; - krb5_creds creds; - KDCOptions flags; - krb5_data out_data; - krb5_principal principal; - - ret = krb5_cc_default (context, &ccache); - if (ret) { - if (auth_debug_mode) - printf ("KerberosV5: could not get default ccache: %s\r\n", - krb5_get_err_text (context, ret)); - return; - } - - ret = krb5_cc_get_principal (context, ccache, &principal); - if (ret) { - if (auth_debug_mode) - printf ("KerberosV5: could not get principal: %s\r\n", - krb5_get_err_text (context, ret)); - return; - } - - memset (&creds, 0, sizeof(creds)); - - creds.client = principal; - - ret = krb5_build_principal (context, - &creds.server, - strlen(principal->realm), - principal->realm, - "krbtgt", - principal->realm, - NULL); - - if (ret) { - if (auth_debug_mode) - printf ("KerberosV5: could not get principal: %s\r\n", - krb5_get_err_text (context, ret)); - return; - } - - creds.times.endtime = 0; - - memset(&flags, 0, sizeof(flags)); - flags.forwarded = 1; - if (forward_flags & OPTS_FORWARDABLE_CREDS) - flags.forwardable = 1; - - ret = krb5_get_forwarded_creds (context, - auth_context, - ccache, - KDCOptions2int(flags), - RemoteHostName, - &creds, - &out_data); - if (ret) { - if (auth_debug_mode) - printf ("Kerberos V5: error getting forwarded creds: %s\r\n", - krb5_get_err_text (context, ret)); - return; - } - - if(!Data(ap, KRB_FORWARD, out_data.data, out_data.length)) { - if (auth_debug_mode) - printf("Not enough room for authentication data\r\n"); - } else { - if (auth_debug_mode) - printf("Forwarded local Kerberos V5 credentials to server\r\n"); - } -} - -#if defined(DCE) -/* if this was a K5 authentication try and join a PAG for the user. */ -void -kerberos5_dfspag(void) -{ - if (dfsk5ok) { - dfspag = krb5_dfs_pag(context, dfsfwd, ticket->client, - UserNameRequested); - } -} -#endif - -int -kerberos5_set_forward(int on) -{ - if(on == 0) - forward_flags &= ~OPTS_FORWARD_CREDS; - if(on == 1) - forward_flags |= OPTS_FORWARD_CREDS; - if(on == -1) - forward_flags ^= OPTS_FORWARD_CREDS; - return 0; -} - -int -kerberos5_set_forwardable(int on) -{ - if(on == 0) - forward_flags &= ~OPTS_FORWARDABLE_CREDS; - if(on == 1) - forward_flags |= OPTS_FORWARDABLE_CREDS; - if(on == -1) - forward_flags ^= OPTS_FORWARDABLE_CREDS; - return 0; -} - -#endif /* KRB5 */ diff --git a/appl/telnet/libtelnet/misc-proto.h b/appl/telnet/libtelnet/misc-proto.h deleted file mode 100644 index 1f496a8f7..000000000 --- a/appl/telnet/libtelnet/misc-proto.h +++ /dev/null @@ -1,79 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)misc-proto.h 8.1 (Berkeley) 6/4/93 - */ - -/* - * Copyright (C) 1990 by the Massachusetts Institute of Technology - * - * Export of this software from the United States of America is assumed - * to require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. - * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. - */ - -/* $Id$ */ - -#ifndef __MISC_PROTO__ -#define __MISC_PROTO__ - -void auth_encrypt_init (const char *, const char *, const char *, int); -void auth_encrypt_user(const char *name); -void auth_encrypt_connect (int); -void printd (const unsigned char *, int); - -char** genget (char *name, char **table, int stlen); -int isprefix(char *s1, char *s2); -int Ambiguous(void *s); - -/* - * These functions are imported from the application - */ -int telnet_net_write (unsigned char *, int); -void net_encrypt (void); -int telnet_spin (void); -char *telnet_getenv (const char *); -char *telnet_gets (char *, char *, int, int); -void printsub(int direction, unsigned char *pointer, size_t); -#endif diff --git a/appl/telnet/libtelnet/misc.c b/appl/telnet/libtelnet/misc.c deleted file mode 100644 index a5a14e000..000000000 --- a/appl/telnet/libtelnet/misc.c +++ /dev/null @@ -1,95 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -RCSID("$Id$"); - -#include -#include -#include -#include -#ifdef SOCKS -#include -#endif -#include "misc.h" -#include "auth.h" -#include "encrypt.h" - - -const char *RemoteHostName; -const char *LocalHostName; -char *UserNameRequested = 0; -int ConnectedCount = 0; - -void -auth_encrypt_init(const char *local, const char *remote, const char *name, - int server) -{ - RemoteHostName = remote; - LocalHostName = local; -#ifdef AUTHENTICATION - auth_init(name, server); -#endif -#ifdef ENCRYPTION - encrypt_init(name, server); -#endif - if (UserNameRequested) { - free(UserNameRequested); - UserNameRequested = 0; - } -} - -void -auth_encrypt_user(const char *name) -{ - if (UserNameRequested) - free(UserNameRequested); - UserNameRequested = name ? strdup(name) : 0; -} - -void -auth_encrypt_connect(int cnt) -{ -} - -void -printd(const unsigned char *data, int cnt) -{ - if (cnt > 16) - cnt = 16; - while (cnt-- > 0) { - printf(" %02x", *data); - ++data; - } -} diff --git a/appl/telnet/libtelnet/rsaencpwd.c b/appl/telnet/libtelnet/rsaencpwd.c deleted file mode 100644 index b30e6ea7d..000000000 --- a/appl/telnet/libtelnet/rsaencpwd.c +++ /dev/null @@ -1,486 +0,0 @@ -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -RCSID("$Id$"); - -#ifdef RSA_ENCPWD -/* - * COPYRIGHT (C) 1990 DIGITAL EQUIPMENT CORPORATION - * ALL RIGHTS RESERVED - * - * "Digital Equipment Corporation authorizes the reproduction, - * distribution and modification of this software subject to the following - * restrictions: - * - * 1. Any partial or whole copy of this software, or any modification - * thereof, must include this copyright notice in its entirety. - * - * 2. This software is supplied "as is" with no warranty of any kind, - * expressed or implied, for any purpose, including any warranty of fitness - * or merchantibility. DIGITAL assumes no responsibility for the use or - * reliability of this software, nor promises to provide any form of - * support for it on any basis. - * - * 3. Distribution of this software is authorized only if no profit or - * remuneration of any kind is received in exchange for such distribution. - * - * 4. This software produces public key authentication certificates - * bearing an expiration date established by DIGITAL and RSA Data - * Security, Inc. It may cease to generate certificates after the expiration - * date. Any modification of this software that changes or defeats - * the expiration date or its effect is unauthorized. - * - * 5. Software that will renew or extend the expiration date of - * authentication certificates produced by this software may be obtained - * from RSA Data Security, Inc., 10 Twin Dolphin Drive, Redwood City, CA - * 94065, (415)595-8782, or from DIGITAL" - * - */ - -#include -#ifdef HAVE_ARPA_TELNET_H -#include -#endif -#include -#include - -#include -#include -#ifdef SOCKS -#include -#endif - -#include "encrypt.h" -#include "auth.h" -#include "misc.h" -#include "cdc.h" - -extern auth_debug_mode; - -static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0, - AUTHTYPE_RSA_ENCPWD, }; -static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION, - TELQUAL_NAME, }; - -#define RSA_ENCPWD_AUTH 0 /* Authentication data follows */ -#define RSA_ENCPWD_REJECT 1 /* Rejected (reason might follow) */ -#define RSA_ENCPWD_ACCEPT 2 /* Accepted */ -#define RSA_ENCPWD_CHALLENGEKEY 3 /* Challenge and public key */ - -#define NAME_SZ 40 -#define CHAL_SZ 20 -#define PWD_SZ 40 - -static KTEXT_ST auth; -static char name[NAME_SZ]; -static char user_passwd[PWD_SZ]; -static char key_file[2*NAME_SZ]; -static char lhostname[NAME_SZ]; -static char challenge[CHAL_SZ]; -static int challenge_len; - - static int -Data(ap, type, d, c) - Authenticator *ap; - int type; - void *d; - int c; -{ - unsigned char *p = str_data + 4; - unsigned char *cd = (unsigned char *)d; - - if (c == -1) - c = strlen((char *)cd); - - if (0) { - printf("%s:%d: [%d] (%d)", - str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", - str_data[3], - type, c); - printd(d, c); - printf("\r\n"); - } - *p++ = ap->type; - *p++ = ap->way; - if (type != NULL) *p++ = type; - while (c-- > 0) { - if ((*p++ = *cd++) == IAC) - *p++ = IAC; - } - *p++ = IAC; - *p++ = SE; - if (str_data[3] == TELQUAL_IS) - printsub('>', &str_data[2], p - (&str_data[2])); - return(telnet_net_write(str_data, p - str_data)); -} - - int -rsaencpwd_init(ap, server) - Authenticator *ap; - int server; -{ - char *cp; - FILE *fp; - - if (server) { - str_data[3] = TELQUAL_REPLY; - memset(key_file, 0, sizeof(key_file)); - gethostname(lhostname, sizeof(lhostname)); - if ((cp = strchr(lhostname, '.')) != 0) *cp = '\0'; - snprintf(key_file, sizeof(key_file), - SYSCONFDIR "/.%s_privkey", lhostname); - if ((fp=fopen(key_file, "r"))==NULL) return(0); - fclose(fp); - } else { - str_data[3] = TELQUAL_IS; - } - return(1); -} - - int -rsaencpwd_send(ap) - Authenticator *ap; -{ - - printf("[ Trying RSAENCPWD ... ]\r\n"); - if (!UserNameRequested) { - return(0); - } - if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) { - return(0); - } - if (!Data(ap, NULL, NULL, 0)) { - return(0); - } - - - return(1); -} - - void -rsaencpwd_is(ap, data, cnt) - Authenticator *ap; - unsigned char *data; - int cnt; -{ - Session_Key skey; - des_cblock datablock; - char r_passwd[PWD_SZ], r_user[NAME_SZ]; - char *cp, key[160]; - char chalkey[160], *ptr; - FILE *fp; - int r, i, j, chalkey_len, len; - time_t now; - - cnt--; - switch (*data++) { - case RSA_ENCPWD_AUTH: - memmove(auth.dat, data, auth.length = cnt); - - if ((fp=fopen(key_file, "r"))==NULL) { - Data(ap, RSA_ENCPWD_REJECT, "Auth failed", -1); - auth_finished(ap, AUTH_REJECT); - return; - } - /* - * get privkey - */ - fscanf(fp, "%x;", &len); - for (i=0;iway & AUTH_HOW_MASK) == AUTH_HOW_ONE_WAY) { - int i; - - - time(&now); - if ((now % 2) == 0) { - snprintf(challenge, sizeof(challenge), "%x", now); - challenge_len = strlen(challenge); - } else { - strlcpy(challenge, "randchal", sizeof(challenge)); - challenge_len = 8; - } - - if ((fp=fopen(key_file, "r"))==NULL) { - Data(ap, RSA_ENCPWD_REJECT, "Auth failed", -1); - auth_finished(ap, AUTH_REJECT); - return; - } - /* - * skip privkey - */ - fscanf(fp, "%x;", &len); - for (i=0;i 0) { - printf("[ RSA_ENCPWD refuses authentication because %.*s ]\r\n", - cnt, data); - } else - printf("[ RSA_ENCPWD refuses authentication ]\r\n"); - auth_send_retry(); - return; - case RSA_ENCPWD_ACCEPT: - printf("[ RSA_ENCPWD accepts you ]\r\n"); - auth_finished(ap, AUTH_USER); - return; - case RSA_ENCPWD_CHALLENGEKEY: - /* - * Verify that the response to the challenge is correct. - */ - - memmove(chalkey, data, cnt); - ptr = (char *) &chalkey[0]; - ptr += DecodeHeaderLength(chalkey); - if (*ptr != 0x04) { - return; - } - *ptr++; - challenge_len = DecodeValueLength(ptr); - ptr += NumEncodeLengthOctets(challenge_len); - memmove(challenge, ptr, challenge_len); - ptr += challenge_len; - if (*ptr != 0x04) { - return; - } - *ptr++; - pubkey_len = DecodeValueLength(ptr); - ptr += NumEncodeLengthOctets(pubkey_len); - memmove(pubkey, ptr, pubkey_len); - memset(user_passwd, 0, sizeof(user_passwd)); - des_read_pw_string(user_passwd, sizeof(user_passwd)-1, "Password: ", 0); - UserPassword = user_passwd; - Challenge = challenge; - r = init_rsa_encpwd(&token, user_passwd, challenge, challenge_len, pubkey); - if (r < 0) { - token.length = 1; - } - - if (!Data(ap, RSA_ENCPWD_AUTH, token.dat, token.length)) { - return; - } - - break; - - default: - return; - } -} - - int -rsaencpwd_status(ap, name, name_sz, level) - Authenticator *ap; - char *name; - size_t name_sz; - int level; -{ - - if (level < AUTH_USER) - return(level); - - if (UserNameRequested && rsaencpwd_passwdok(UserNameRequested, UserPassword)) { - strlcpy(name, UserNameRequested, name_sz); - return(AUTH_VALID); - } else { - return(AUTH_USER); - } -} - -#define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} -#define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);} - - void -rsaencpwd_printsub(unsigned char *data, size_t cnt, - unsigned char * buf, size_t buflen) -{ - size_t i; - - buf[buflen-1] = '\0'; /* make sure it's NULL terminated */ - buflen -= 1; - - switch(data[3]) { - case RSA_ENCPWD_REJECT: /* Rejected (reason might follow) */ - strlcpy((char *)buf, " REJECT ", buflen); - goto common; - - case RSA_ENCPWD_ACCEPT: /* Accepted (name might follow) */ - strlcpy((char *)buf, " ACCEPT ", buflen); - common: - BUMP(buf, buflen); - if (cnt <= 4) - break; - ADDC(buf, buflen, '"'); - for (i = 4; i < cnt; i++) - ADDC(buf, buflen, data[i]); - ADDC(buf, buflen, '"'); - ADDC(buf, buflen, '\0'); - break; - - case RSA_ENCPWD_AUTH: /* Authentication data follows */ - strlcpy((char *)buf, " AUTH", buflen); - goto common2; - - case RSA_ENCPWD_CHALLENGEKEY: - strlcpy((char *)buf, " CHALLENGEKEY", buflen); - goto common2; - - default: - snprintf(buf, buflen, " %d (unknown)", data[3]); - common2: - BUMP(buf, buflen); - for (i = 4; i < cnt; i++) { - snprintf(buf, buflen, " %d", data[i]); - BUMP(buf, buflen); - } - break; - } -} - -int rsaencpwd_passwdok(name, passwd) -char *name, *passwd; -{ - char *crypt(); - char *salt, *p; - struct passwd *pwd; - int passwdok_status = 0; - - if (pwd = k_getpwnam(name)) - salt = pwd->pw_passwd; - else salt = "xx"; - - p = crypt(passwd, salt); - - if (pwd && !strcmp(p, pwd->pw_passwd)) { - passwdok_status = 1; - } else passwdok_status = 0; - return(passwdok_status); -} - -#endif - -#ifdef notdef - -prkey(msg, key) - char *msg; - unsigned char *key; -{ - int i; - printf("%s:", msg); - for (i = 0; i < 8; i++) - printf(" %3d", key[i]); - printf("\r\n"); -} -#endif diff --git a/appl/telnet/libtelnet/spx.c b/appl/telnet/libtelnet/spx.c deleted file mode 100644 index 8672c5b4c..000000000 --- a/appl/telnet/libtelnet/spx.c +++ /dev/null @@ -1,589 +0,0 @@ -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -RCSID("$Id$"); - -#ifdef SPX -/* - * COPYRIGHT (C) 1990 DIGITAL EQUIPMENT CORPORATION - * ALL RIGHTS RESERVED - * - * "Digital Equipment Corporation authorizes the reproduction, - * distribution and modification of this software subject to the following - * restrictions: - * - * 1. Any partial or whole copy of this software, or any modification - * thereof, must include this copyright notice in its entirety. - * - * 2. This software is supplied "as is" with no warranty of any kind, - * expressed or implied, for any purpose, including any warranty of fitness - * or merchantibility. DIGITAL assumes no responsibility for the use or - * reliability of this software, nor promises to provide any form of - * support for it on any basis. - * - * 3. Distribution of this software is authorized only if no profit or - * remuneration of any kind is received in exchange for such distribution. - * - * 4. This software produces public key authentication certificates - * bearing an expiration date established by DIGITAL and RSA Data - * Security, Inc. It may cease to generate certificates after the expiration - * date. Any modification of this software that changes or defeats - * the expiration date or its effect is unauthorized. - * - * 5. Software that will renew or extend the expiration date of - * authentication certificates produced by this software may be obtained - * from RSA Data Security, Inc., 10 Twin Dolphin Drive, Redwood City, CA - * 94065, (415)595-8782, or from DIGITAL" - * - */ - -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_ARPA_TELNET_H -#include -#endif -#include -#include "gssapi_defs.h" -#include -#include - -#include -#ifdef SOCKS -#include -#endif - -#include "encrypt.h" -#include "auth.h" -#include "misc.h" - -extern auth_debug_mode; - -static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0, - AUTHTYPE_SPX, }; -static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION, - TELQUAL_NAME, }; - -#define SPX_AUTH 0 /* Authentication data follows */ -#define SPX_REJECT 1 /* Rejected (reason might follow) */ -#define SPX_ACCEPT 2 /* Accepted */ - -static des_key_schedule sched; -static des_cblock challenge = { 0 }; - - -/*******************************************************************/ - -gss_OID_set actual_mechs; -gss_OID actual_mech_type, output_name_type; -int major_status, status, msg_ctx = 0, new_status; -int req_flags = 0, ret_flags, lifetime_rec; -gss_cred_id_t gss_cred_handle; -gss_ctx_id_t actual_ctxhandle, context_handle; -gss_buffer_desc output_token, input_token, input_name_buffer; -gss_buffer_desc status_string; -gss_name_t desired_targname, src_name; -gss_channel_bindings input_chan_bindings; -char lhostname[GSS_C_MAX_PRINTABLE_NAME]; -char targ_printable[GSS_C_MAX_PRINTABLE_NAME]; -int to_addr=0, from_addr=0; -char *address; -gss_buffer_desc fullname_buffer; -gss_OID fullname_type; -gss_cred_id_t gss_delegated_cred_handle; - -/*******************************************************************/ - - - - static int -Data(ap, type, d, c) - Authenticator *ap; - int type; - void *d; - int c; -{ - unsigned char *p = str_data + 4; - unsigned char *cd = (unsigned char *)d; - - if (c == -1) - c = strlen((char *)cd); - - if (0) { - printf("%s:%d: [%d] (%d)", - str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", - str_data[3], - type, c); - printd(d, c); - printf("\r\n"); - } - *p++ = ap->type; - *p++ = ap->way; - *p++ = type; - while (c-- > 0) { - if ((*p++ = *cd++) == IAC) - *p++ = IAC; - } - *p++ = IAC; - *p++ = SE; - if (str_data[3] == TELQUAL_IS) - printsub('>', &str_data[2], p - (&str_data[2])); - return(telnet_net_write(str_data, p - str_data)); -} - - int -spx_init(ap, server) - Authenticator *ap; - int server; -{ - gss_cred_id_t tmp_cred_handle; - - if (server) { - str_data[3] = TELQUAL_REPLY; - gethostname(lhostname, sizeof(lhostname)); - snprintf (targ_printable, sizeof(targ_printable), - "SERVICE:rcmd@%s", lhostname); - input_name_buffer.length = strlen(targ_printable); - input_name_buffer.value = targ_printable; - major_status = gss_import_name(&status, - &input_name_buffer, - GSS_C_NULL_OID, - &desired_targname); - major_status = gss_acquire_cred(&status, - desired_targname, - 0, - GSS_C_NULL_OID_SET, - GSS_C_ACCEPT, - &tmp_cred_handle, - &actual_mechs, - &lifetime_rec); - if (major_status != GSS_S_COMPLETE) return(0); - } else { - str_data[3] = TELQUAL_IS; - } - return(1); -} - - int -spx_send(ap) - Authenticator *ap; -{ - des_cblock enckey; - int r; - - gss_OID actual_mech_type, output_name_type; - int msg_ctx = 0, new_status, status; - int req_flags = 0, ret_flags, lifetime_rec, major_status; - gss_buffer_desc output_token, input_token, input_name_buffer; - gss_buffer_desc output_name_buffer, status_string; - gss_name_t desired_targname; - gss_channel_bindings input_chan_bindings; - char targ_printable[GSS_C_MAX_PRINTABLE_NAME]; - int from_addr=0, to_addr=0, myhostlen, j; - int deleg_flag=1, mutual_flag=0, replay_flag=0, seq_flag=0; - char *address; - - printf("[ Trying SPX ... ]\r\n"); - snprintf (targ_printable, sizeof(targ_printable), - "SERVICE:rcmd@%s", RemoteHostName); - - input_name_buffer.length = strlen(targ_printable); - input_name_buffer.value = targ_printable; - - if (!UserNameRequested) { - return(0); - } - - major_status = gss_import_name(&status, - &input_name_buffer, - GSS_C_NULL_OID, - &desired_targname); - - - major_status = gss_display_name(&status, - desired_targname, - &output_name_buffer, - &output_name_type); - - printf("target is '%.*s'\n", (int)output_name_buffer.length, - (char*)output_name_buffer.value); - fflush(stdout); - - major_status = gss_release_buffer(&status, &output_name_buffer); - - input_chan_bindings = (gss_channel_bindings) - malloc(sizeof(gss_channel_bindings_desc)); - - input_chan_bindings->initiator_addrtype = GSS_C_AF_INET; - input_chan_bindings->initiator_address.length = 4; - address = (char *) malloc(4); - input_chan_bindings->initiator_address.value = (char *) address; - address[0] = ((from_addr & 0xff000000) >> 24); - address[1] = ((from_addr & 0xff0000) >> 16); - address[2] = ((from_addr & 0xff00) >> 8); - address[3] = (from_addr & 0xff); - input_chan_bindings->acceptor_addrtype = GSS_C_AF_INET; - input_chan_bindings->acceptor_address.length = 4; - address = (char *) malloc(4); - input_chan_bindings->acceptor_address.value = (char *) address; - address[0] = ((to_addr & 0xff000000) >> 24); - address[1] = ((to_addr & 0xff0000) >> 16); - address[2] = ((to_addr & 0xff00) >> 8); - address[3] = (to_addr & 0xff); - input_chan_bindings->application_data.length = 0; - - req_flags = 0; - if (deleg_flag) req_flags = req_flags | 1; - if (mutual_flag) req_flags = req_flags | 2; - if (replay_flag) req_flags = req_flags | 4; - if (seq_flag) req_flags = req_flags | 8; - - major_status = gss_init_sec_context(&status, /* minor status */ - GSS_C_NO_CREDENTIAL, /* cred handle */ - &actual_ctxhandle, /* ctx handle */ - desired_targname, /* target name */ - GSS_C_NULL_OID, /* mech type */ - req_flags, /* req flags */ - 0, /* time req */ - input_chan_bindings, /* chan binding */ - GSS_C_NO_BUFFER, /* input token */ - &actual_mech_type, /* actual mech */ - &output_token, /* output token */ - &ret_flags, /* ret flags */ - &lifetime_rec); /* time rec */ - - if ((major_status != GSS_S_COMPLETE) && - (major_status != GSS_S_CONTINUE_NEEDED)) { - gss_display_status(&new_status, - status, - GSS_C_MECH_CODE, - GSS_C_NULL_OID, - &msg_ctx, - &status_string); - printf("%.*s\n", (int)status_string.length, - (char*)status_string.value); - return(0); - } - - if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) { - return(0); - } - - if (!Data(ap, SPX_AUTH, output_token.value, output_token.length)) { - return(0); - } - - return(1); -} - - void -spx_is(ap, data, cnt) - Authenticator *ap; - unsigned char *data; - int cnt; -{ - Session_Key skey; - des_cblock datablock; - int r; - - if (cnt-- < 1) - return; - switch (*data++) { - case SPX_AUTH: - input_token.length = cnt; - input_token.value = (char *) data; - - gethostname(lhostname, sizeof(lhostname)); - - snprintf(targ_printable, sizeof(targ_printable), - "SERVICE:rcmd@%s", lhostname); - - input_name_buffer.length = strlen(targ_printable); - input_name_buffer.value = targ_printable; - - major_status = gss_import_name(&status, - &input_name_buffer, - GSS_C_NULL_OID, - &desired_targname); - - major_status = gss_acquire_cred(&status, - desired_targname, - 0, - GSS_C_NULL_OID_SET, - GSS_C_ACCEPT, - &gss_cred_handle, - &actual_mechs, - &lifetime_rec); - - major_status = gss_release_name(&status, desired_targname); - - input_chan_bindings = (gss_channel_bindings) - malloc(sizeof(gss_channel_bindings_desc)); - - input_chan_bindings->initiator_addrtype = GSS_C_AF_INET; - input_chan_bindings->initiator_address.length = 4; - address = (char *) malloc(4); - input_chan_bindings->initiator_address.value = (char *) address; - address[0] = ((from_addr & 0xff000000) >> 24); - address[1] = ((from_addr & 0xff0000) >> 16); - address[2] = ((from_addr & 0xff00) >> 8); - address[3] = (from_addr & 0xff); - input_chan_bindings->acceptor_addrtype = GSS_C_AF_INET; - input_chan_bindings->acceptor_address.length = 4; - address = (char *) malloc(4); - input_chan_bindings->acceptor_address.value = (char *) address; - address[0] = ((to_addr & 0xff000000) >> 24); - address[1] = ((to_addr & 0xff0000) >> 16); - address[2] = ((to_addr & 0xff00) >> 8); - address[3] = (to_addr & 0xff); - input_chan_bindings->application_data.length = 0; - - major_status = gss_accept_sec_context(&status, - &context_handle, - gss_cred_handle, - &input_token, - input_chan_bindings, - &src_name, - &actual_mech_type, - &output_token, - &ret_flags, - &lifetime_rec, - &gss_delegated_cred_handle); - - - if (major_status != GSS_S_COMPLETE) { - - major_status = gss_display_name(&status, - src_name, - &fullname_buffer, - &fullname_type); - Data(ap, SPX_REJECT, "auth failed", -1); - auth_finished(ap, AUTH_REJECT); - return; - } - - major_status = gss_display_name(&status, - src_name, - &fullname_buffer, - &fullname_type); - - - Data(ap, SPX_ACCEPT, output_token.value, output_token.length); - auth_finished(ap, AUTH_USER); - break; - - default: - Data(ap, SPX_REJECT, 0, 0); - break; - } -} - - - void -spx_reply(ap, data, cnt) - Authenticator *ap; - unsigned char *data; - int cnt; -{ - Session_Key skey; - - if (cnt-- < 1) - return; - switch (*data++) { - case SPX_REJECT: - if (cnt > 0) { - printf("[ SPX refuses authentication because %.*s ]\r\n", - cnt, data); - } else - printf("[ SPX refuses authentication ]\r\n"); - auth_send_retry(); - return; - case SPX_ACCEPT: - printf("[ SPX accepts you ]\r\n"); - if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { - /* - * Send over the encrypted challenge. - */ - input_token.value = (char *) data; - input_token.length = cnt; - - major_status = gss_init_sec_context(&status, /* minor stat */ - GSS_C_NO_CREDENTIAL, /* cred handle */ - &actual_ctxhandle, /* ctx handle */ - desired_targname, /* target name */ - GSS_C_NULL_OID, /* mech type */ - req_flags, /* req flags */ - 0, /* time req */ - input_chan_bindings, /* chan binding */ - &input_token, /* input token */ - &actual_mech_type, /* actual mech */ - &output_token, /* output token */ - &ret_flags, /* ret flags */ - &lifetime_rec); /* time rec */ - - if (major_status != GSS_S_COMPLETE) { - gss_display_status(&new_status, - status, - GSS_C_MECH_CODE, - GSS_C_NULL_OID, - &msg_ctx, - &status_string); - printf("[ SPX mutual response fails ... '%.*s' ]\r\n", - (int)status_string.length, - (char*)status_string.value); - auth_send_retry(); - return; - } - } - auth_finished(ap, AUTH_USER); - return; - - default: - return; - } -} - - int -spx_status(ap, name, name_sz, level) - Authenticator *ap; - char *name; - size_t name_sz; - int level; -{ - - gss_buffer_desc fullname_buffer, acl_file_buffer; - gss_OID fullname_type; - char acl_file[160], fullname[160]; - int major_status, status = 0; - struct passwd *pwd; - - /* - * hard code fullname to - * "SPX:/C=US/O=Digital/OU=LKG/OU=Sphinx/OU=Users/CN=Kannan Alagappan" - * and acl_file to "~kannan/.sphinx" - */ - - pwd = k_getpwnam(UserNameRequested); - if (pwd == NULL) { - return(AUTH_USER); /* not authenticated */ - } - - snprintf (acl_file, sizeof(acl_file), - "%s/.sphinx", pwd->pw_dir); - - acl_file_buffer.value = acl_file; - acl_file_buffer.length = strlen(acl_file); - - major_status = gss_display_name(&status, - src_name, - &fullname_buffer, - &fullname_type); - - if (level < AUTH_USER) - return(level); - - major_status = gss__check_acl(&status, &fullname_buffer, - &acl_file_buffer); - - if (major_status == GSS_S_COMPLETE) { - strlcpy(name, UserNameRequested, name_sz); - return(AUTH_VALID); - } else { - return(AUTH_USER); - } - -} - -#define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} -#define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);} - - void -spx_printsub(unsigned char *data, size_t cnt, - unsigned char *buf, size_t buflen) -{ - size_t i; - - buf[buflen-1] = '\0'; /* make sure it's NULL terminated */ - buflen -= 1; - - switch(data[3]) { - case SPX_REJECT: /* Rejected (reason might follow) */ - strlcpy((char *)buf, " REJECT ", buflen); - goto common; - - case SPX_ACCEPT: /* Accepted (name might follow) */ - strlcpy((char *)buf, " ACCEPT ", buflen); - common: - BUMP(buf, buflen); - if (cnt <= 4) - break; - ADDC(buf, buflen, '"'); - for (i = 4; i < cnt; i++) - ADDC(buf, buflen, data[i]); - ADDC(buf, buflen, '"'); - ADDC(buf, buflen, '\0'); - break; - - case SPX_AUTH: /* Authentication data follows */ - strlcpy((char *)buf, " AUTH", buflen); - goto common2; - - default: - snprintf(buf, buflen, " %d (unknown)", data[3]); - common2: - BUMP(buf, buflen); - for (i = 4; i < cnt; i++) { - snprintf(buf, buflen, " %d", data[i]); - BUMP(buf, buflen); - } - break; - } -} - -#endif - -#ifdef notdef - -prkey(msg, key) - char *msg; - unsigned char *key; -{ - int i; - printf("%s:", msg); - for (i = 0; i < 8; i++) - printf(" %3d", key[i]); - printf("\r\n"); -} -#endif diff --git a/appl/telnet/telnet.state b/appl/telnet/telnet.state deleted file mode 100644 index 1927a2b4b..000000000 --- a/appl/telnet/telnet.state +++ /dev/null @@ -1,80 +0,0 @@ - - Three pieces of state need to be kept for each side of each option. - (You need the localside, sending WILL/WONT & receiving DO/DONT, and - the remoteside, sending DO/DONT and receiving WILL/WONT) - - MY_STATE: What state am I in? - WANT_STATE: What state do I want? - WANT_RESP: How many requests have I initiated? - - Default values: - MY_STATE = WANT_STATE = DONT - WANT_RESP = 0 - - The local setup will change based on the state of the Telnet - variables. When we are the originator, we can either make the - local setup changes at option request time (in which case if - the option is denied we need to change things back) or when - the option is acknowledged. - - To initiate a switch to NEW_STATE: - - if ((WANT_RESP == 0 && NEW_STATE == MY_STATE) || - WANT_STATE == NEW_STATE) { - do nothing; - } else { - /* - * This is where the logic goes to change the local setup - * if we are doing so at request initiation - */ - WANT_STATE = NEW_STATE; - send NEW_STATE; - WANT_RESP += 1; - } - - When receiving NEW_STATE: - - if (WANT_RESP) { - --WANT_RESP; - if (WANT_RESP && (NEW_STATE == MY_STATE)) - --WANT_RESP; - } - if (WANT_RESP == 0) { - if (NEW_STATE != WANT_STATE) { - /* - * This is where the logic goes to decide if it is ok - * to switch to NEW_STATE, and if so, do any necessary - * local setup changes. - */ - if (ok_to_switch_to NEW_STATE) - WANT_STATE = NEW_STATE; - else - WANT_RESP++; -* if (MY_STATE != WANT_STATE) - reply with WANT_STATE; - } else { - /* - * This is where the logic goes to change the local setup - * if we are doing so at request acknowledgment - */ - } - } - MY_STATE = NEW_STATE; - -* This if() line is not needed, it should be ok to always do the - "reply with WANT_STATE". With the if() line, asking to turn on - an option that the other side doesn't understand is: - Send DO option - Recv WONT option - Without the if() line, it is: - Send DO option - Recv WONT option - Send DONT option - If the other side does not expect to receive the latter case, - but generates the latter case, then there is a potential for - option negotiation loops. An implementation that does not expect - to get the second case should not generate it, an implementation - that does expect to get it may or may not generate it, and things - will still work. Being conservative in what we send, we have the - if() statement in, but we expect the other side to generate the - last response. diff --git a/appl/telnet/telnet/Makefile.am b/appl/telnet/telnet/Makefile.am deleted file mode 100644 index fa3020714..000000000 --- a/appl/telnet/telnet/Makefile.am +++ /dev/null @@ -1,24 +0,0 @@ -# $Id$ - -include $(top_srcdir)/Makefile.am.common - -AM_CPPFLAGS += -I$(srcdir)/.. $(INCLUDE_hcrypto) - -bin_PROGRAMS = telnet - -CHECK_LOCAL = - -telnet_SOURCES = authenc.c commands.c main.c network.c ring.c \ - sys_bsd.c telnet.c terminal.c \ - utilities.c defines.h externs.h ring.h telnet_locl.h types.h - -man_MANS = telnet.1 - -LDADD = ../libtelnet/libtelnet.a \ - $(LIB_krb5) \ - $(LIB_hcrypto) \ - $(LIB_tgetent) \ - $(LIB_kdfs) \ - $(LIB_roken) - -EXTRA_DIST = $(man_MANS) diff --git a/appl/telnet/telnet/authenc.c b/appl/telnet/telnet/authenc.c deleted file mode 100644 index 4c0f6fd12..000000000 --- a/appl/telnet/telnet/authenc.c +++ /dev/null @@ -1,99 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "telnet_locl.h" - -RCSID("$Id$"); - -#if defined(AUTHENTICATION) || defined(ENCRYPTION) -int -telnet_net_write(unsigned char *str, int len) -{ - if (NETROOM() > len) { - ring_supply_data(&netoring, str, len); - if (str[0] == IAC && str[1] == SE) - printsub('>', &str[2], len-2); - return(len); - } - return(0); -} - -void -net_encrypt(void) -{ -#if defined(ENCRYPTION) - if (encrypt_output) - ring_encrypt(&netoring, encrypt_output); - else - ring_clearto(&netoring); -#endif -} - -int -telnet_spin(void) -{ - int ret = 0; - - scheduler_lockout_tty = 1; - if (Scheduler(0) == -1) - ret = 1; - scheduler_lockout_tty = 0; - - return ret; - -} - -char * -telnet_getenv(const char *val) -{ - return((char *)env_getvalue((unsigned char *)val)); -} - -char * -telnet_gets(char *prompt, char *result, int length, int echo) -{ - int om = globalmode; - char *res; - - TerminalNewMode(-1); - if (echo) { - printf("%s", prompt); - res = fgets(result, length, stdin); - } else if ((res = getpass(prompt))) { - strlcpy(result, res, length); - res = result; - } - TerminalNewMode(om); - return(res); -} -#endif diff --git a/appl/telnet/telnet/commands.c b/appl/telnet/telnet/commands.c deleted file mode 100644 index 082aec3a1..000000000 --- a/appl/telnet/telnet/commands.c +++ /dev/null @@ -1,2675 +0,0 @@ -/* - * Copyright (c) 1988, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "telnet_locl.h" - -RCSID("$Id$"); - -#if defined(IPPROTO_IP) && defined(IP_TOS) -int tos = -1; -#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */ - -char *hostname; -static char _hostname[MaxHostNameLen]; - -typedef int (*intrtn_t)(int, char**); -static int call(intrtn_t, ...); - -typedef struct { - char *name; /* command name */ - char *help; /* help string (NULL for no help) */ - int (*handler)(); /* routine which executes command */ - int needconnect; /* Do we need to be connected to execute? */ -} Command; - -static char line[256]; -static char saveline[256]; -static int margc; -static char *margv[20]; - -static void -makeargv() -{ - char *cp, *cp2, c; - char **argp = margv; - - margc = 0; - cp = line; - if (*cp == '!') { /* Special case shell escape */ - /* save for shell command */ - strlcpy(saveline, line, sizeof(saveline)); - *argp++ = "!"; /* No room in string to get this */ - margc++; - cp++; - } - while ((c = *cp)) { - int inquote = 0; - while (isspace((unsigned char)c)) - c = *++cp; - if (c == '\0') - break; - *argp++ = cp; - margc += 1; - for (cp2 = cp; c != '\0'; c = *++cp) { - if (inquote) { - if (c == inquote) { - inquote = 0; - continue; - } - } else { - if (c == '\\') { - if ((c = *++cp) == '\0') - break; - } else if (c == '"') { - inquote = '"'; - continue; - } else if (c == '\'') { - inquote = '\''; - continue; - } else if (isspace((unsigned char)c)) - break; - } - *cp2++ = c; - } - *cp2 = '\0'; - if (c == '\0') - break; - cp++; - } - *argp++ = 0; -} - -/* - * Make a character string into a number. - * - * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). - */ - -static char -special(char *s) -{ - char c; - char b; - - switch (*s) { - case '^': - b = *++s; - if (b == '?') { - c = b | 0x40; /* DEL */ - } else { - c = b & 0x1f; - } - break; - default: - c = *s; - break; - } - return c; -} - -/* - * Construct a control character sequence - * for a special character. - */ -static char * -control(cc_t c) -{ - static char buf[5]; - /* - * The only way I could get the Sun 3.5 compiler - * to shut up about - * if ((unsigned int)c >= 0x80) - * was to assign "c" to an unsigned int variable... - * Arggg.... - */ - unsigned int uic = (unsigned int)c; - - if (uic == 0x7f) - return ("^?"); - if (c == (cc_t)_POSIX_VDISABLE) { - return "off"; - } - if (uic >= 0x80) { - buf[0] = '\\'; - buf[1] = ((c>>6)&07) + '0'; - buf[2] = ((c>>3)&07) + '0'; - buf[3] = (c&07) + '0'; - buf[4] = 0; - } else if (uic >= 0x20) { - buf[0] = c; - buf[1] = 0; - } else { - buf[0] = '^'; - buf[1] = '@'+c; - buf[2] = 0; - } - return (buf); -} - - - -/* - * The following are data structures and routines for - * the "send" command. - * - */ - -struct sendlist { - char *name; /* How user refers to it (case independent) */ - char *help; /* Help information (0 ==> no help) */ - int needconnect; /* Need to be connected */ - int narg; /* Number of arguments */ - int (*handler)(); /* Routine to perform (for special ops) */ - int nbyte; /* Number of bytes to send this command */ - int what; /* Character to be sent (<0 ==> special) */ -}; - - -static int - send_esc (void), - send_help (void), - send_docmd (char *), - send_dontcmd (char *), - send_willcmd (char *), - send_wontcmd (char *); - -static struct sendlist Sendlist[] = { - { "ao", "Send Telnet Abort output", 1, 0, 0, 2, AO }, - { "ayt", "Send Telnet 'Are You There'", 1, 0, 0, 2, AYT }, - { "brk", "Send Telnet Break", 1, 0, 0, 2, BREAK }, - { "break", 0, 1, 0, 0, 2, BREAK }, - { "ec", "Send Telnet Erase Character", 1, 0, 0, 2, EC }, - { "el", "Send Telnet Erase Line", 1, 0, 0, 2, EL }, - { "escape", "Send current escape character", 1, 0, send_esc, 1, 0 }, - { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, 0, 2, GA }, - { "ip", "Send Telnet Interrupt Process", 1, 0, 0, 2, IP }, - { "intp", 0, 1, 0, 0, 2, IP }, - { "interrupt", 0, 1, 0, 0, 2, IP }, - { "intr", 0, 1, 0, 0, 2, IP }, - { "nop", "Send Telnet 'No operation'", 1, 0, 0, 2, NOP }, - { "eor", "Send Telnet 'End of Record'", 1, 0, 0, 2, EOR }, - { "abort", "Send Telnet 'Abort Process'", 1, 0, 0, 2, ABORT }, - { "susp", "Send Telnet 'Suspend Process'", 1, 0, 0, 2, SUSP }, - { "eof", "Send Telnet End of File Character", 1, 0, 0, 2, xEOF }, - { "synch", "Perform Telnet 'Synch operation'", 1, 0, dosynch, 2, 0 }, - { "getstatus", "Send request for STATUS", 1, 0, get_status, 6, 0 }, - { "?", "Display send options", 0, 0, send_help, 0, 0 }, - { "help", 0, 0, 0, send_help, 0, 0 }, - { "do", 0, 0, 1, send_docmd, 3, 0 }, - { "dont", 0, 0, 1, send_dontcmd, 3, 0 }, - { "will", 0, 0, 1, send_willcmd, 3, 0 }, - { "wont", 0, 0, 1, send_wontcmd, 3, 0 }, - { 0 } -}; - -#define GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \ - sizeof(struct sendlist))) - -static int -sendcmd(int argc, char **argv) -{ - int count; /* how many bytes we are going to need to send */ - int i; - struct sendlist *s; /* pointer to current command */ - int success = 0; - int needconnect = 0; - - if (argc < 2) { - printf("need at least one argument for 'send' command\r\n"); - printf("'send ?' for help\r\n"); - return 0; - } - /* - * First, validate all the send arguments. - * In addition, we see how much space we are going to need, and - * whether or not we will be doing a "SYNCH" operation (which - * flushes the network queue). - */ - count = 0; - for (i = 1; i < argc; i++) { - s = GETSEND(argv[i]); - if (s == 0) { - printf("Unknown send argument '%s'\r\n'send ?' for help.\r\n", - argv[i]); - return 0; - } else if (Ambiguous(s)) { - printf("Ambiguous send argument '%s'\r\n'send ?' for help.\r\n", - argv[i]); - return 0; - } - if (i + s->narg >= argc) { - fprintf(stderr, - "Need %d argument%s to 'send %s' command. 'send %s ?' for help.\r\n", - s->narg, s->narg == 1 ? "" : "s", s->name, s->name); - return 0; - } - count += s->nbyte; - if (s->handler == send_help) { - send_help(); - return 0; - } - - i += s->narg; - needconnect += s->needconnect; - } - if (!connected && needconnect) { - printf("?Need to be connected first.\r\n"); - printf("'send ?' for help\r\n"); - return 0; - } - /* Now, do we have enough room? */ - if (NETROOM() < count) { - printf("There is not enough room in the buffer TO the network\r\n"); - printf("to process your request. Nothing will be done.\r\n"); - printf("('send synch' will throw away most data in the network\r\n"); - printf("buffer, if this might help.)\r\n"); - return 0; - } - /* OK, they are all OK, now go through again and actually send */ - count = 0; - for (i = 1; i < argc; i++) { - if ((s = GETSEND(argv[i])) == 0) { - fprintf(stderr, "Telnet 'send' error - argument disappeared!\r\n"); - quit(); - /*NOTREACHED*/ - } - if (s->handler) { - count++; - success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0, - (s->narg > 1) ? argv[i+2] : 0); - i += s->narg; - } else { - NET2ADD(IAC, s->what); - printoption("SENT", IAC, s->what); - } - } - return (count == success); -} - -static int -send_tncmd(void (*func)(), char *cmd, char *name); - -static int -send_esc() -{ - NETADD(escape); - return 1; -} - -static int -send_docmd(char *name) -{ - return(send_tncmd(send_do, "do", name)); -} - -static int -send_dontcmd(char *name) -{ - return(send_tncmd(send_dont, "dont", name)); -} - -static int -send_willcmd(char *name) -{ - return(send_tncmd(send_will, "will", name)); -} - -static int -send_wontcmd(char *name) -{ - return(send_tncmd(send_wont, "wont", name)); -} - -extern char *telopts[]; /* XXX */ - -static int -send_tncmd(void (*func)(), char *cmd, char *name) -{ - char **cpp; - int val = 0; - - if (isprefix(name, "help") || isprefix(name, "?")) { - int col, len; - - printf("Usage: send %s \r\n", cmd); - printf("\"value\" must be from 0 to 255\r\n"); - printf("Valid options are:\r\n\t"); - - col = 8; - for (cpp = telopts; *cpp; cpp++) { - len = strlen(*cpp) + 3; - if (col + len > 65) { - printf("\r\n\t"); - col = 8; - } - printf(" \"%s\"", *cpp); - col += len; - } - printf("\r\n"); - return 0; - } - cpp = genget(name, telopts, sizeof(char *)); - if (Ambiguous(cpp)) { - fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\r\n", - name, cmd); - return 0; - } - if (cpp) { - val = cpp - telopts; - } else { - char *cp = name; - - while (*cp >= '0' && *cp <= '9') { - val *= 10; - val += *cp - '0'; - cp++; - } - if (*cp != 0) { - fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\r\n", - name, cmd); - return 0; - } else if (val < 0 || val > 255) { - fprintf(stderr, "'%s': bad value ('send %s ?' for help).\r\n", - name, cmd); - return 0; - } - } - if (!connected) { - printf("?Need to be connected first.\r\n"); - return 0; - } - (*func)(val, 1); - return 1; -} - -static int -send_help() -{ - struct sendlist *s; /* pointer to current command */ - for (s = Sendlist; s->name; s++) { - if (s->help) - printf("%-15s %s\r\n", s->name, s->help); - } - return(0); -} - -/* - * The following are the routines and data structures referred - * to by the arguments to the "toggle" command. - */ - -static int -lclchars() -{ - donelclchars = 1; - return 1; -} - -static int -togdebug() -{ -#ifndef NOT43 - if (net > 0 && - (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) { - perror("setsockopt (SO_DEBUG)"); - } -#else /* NOT43 */ - if (debug) { - if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) - perror("setsockopt (SO_DEBUG)"); - } else - printf("Cannot turn off socket debugging\r\n"); -#endif /* NOT43 */ - return 1; -} - -static int -togcrlf() -{ - if (crlf) { - printf("Will send carriage returns as telnet .\r\n"); - } else { - printf("Will send carriage returns as telnet .\r\n"); - } - return 1; -} - -int binmode; - -static int -togbinary(int val) -{ - donebinarytoggle = 1; - - if (val >= 0) { - binmode = val; - } else { - if (my_want_state_is_will(TELOPT_BINARY) && - my_want_state_is_do(TELOPT_BINARY)) { - binmode = 1; - } else if (my_want_state_is_wont(TELOPT_BINARY) && - my_want_state_is_dont(TELOPT_BINARY)) { - binmode = 0; - } - val = binmode ? 0 : 1; - } - - if (val == 1) { - if (my_want_state_is_will(TELOPT_BINARY) && - my_want_state_is_do(TELOPT_BINARY)) { - printf("Already operating in binary mode with remote host.\r\n"); - } else { - printf("Negotiating binary mode with remote host.\r\n"); - tel_enter_binary(3); - } - } else { - if (my_want_state_is_wont(TELOPT_BINARY) && - my_want_state_is_dont(TELOPT_BINARY)) { - printf("Already in network ascii mode with remote host.\r\n"); - } else { - printf("Negotiating network ascii mode with remote host.\r\n"); - tel_leave_binary(3); - } - } - return 1; -} - -static int -togrbinary(int val) -{ - donebinarytoggle = 1; - - if (val == -1) - val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1; - - if (val == 1) { - if (my_want_state_is_do(TELOPT_BINARY)) { - printf("Already receiving in binary mode.\r\n"); - } else { - printf("Negotiating binary mode on input.\r\n"); - tel_enter_binary(1); - } - } else { - if (my_want_state_is_dont(TELOPT_BINARY)) { - printf("Already receiving in network ascii mode.\r\n"); - } else { - printf("Negotiating network ascii mode on input.\r\n"); - tel_leave_binary(1); - } - } - return 1; -} - -static int -togxbinary(int val) -{ - donebinarytoggle = 1; - - if (val == -1) - val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1; - - if (val == 1) { - if (my_want_state_is_will(TELOPT_BINARY)) { - printf("Already transmitting in binary mode.\r\n"); - } else { - printf("Negotiating binary mode on output.\r\n"); - tel_enter_binary(2); - } - } else { - if (my_want_state_is_wont(TELOPT_BINARY)) { - printf("Already transmitting in network ascii mode.\r\n"); - } else { - printf("Negotiating network ascii mode on output.\r\n"); - tel_leave_binary(2); - } - } - return 1; -} - - -static int togglehelp (void); -#if defined(AUTHENTICATION) -extern int auth_togdebug (int); -#endif -#if defined(ENCRYPTION) -extern int EncryptAutoEnc (int); -extern int EncryptAutoDec (int); -extern int EncryptDebug (int); -extern int EncryptVerbose (int); -#endif - -struct togglelist { - char *name; /* name of toggle */ - char *help; /* help message */ - int (*handler)(); /* routine to do actual setting */ - int *variable; - char *actionexplanation; -}; - -static struct togglelist Togglelist[] = { - { "autoflush", - "flushing of output when sending interrupt characters", - 0, - &autoflush, - "flush output when sending interrupt characters" }, - { "autosynch", - "automatic sending of interrupt characters in urgent mode", - 0, - &autosynch, - "send interrupt characters in urgent mode" }, -#if defined(AUTHENTICATION) - { "autologin", - "automatic sending of login and/or authentication info", - 0, - &autologin, - "send login name and/or authentication information" }, - { "authdebug", - "authentication debugging", - auth_togdebug, - 0, - "print authentication debugging information" }, -#endif -#if defined(ENCRYPTION) - { "autoencrypt", - "automatic encryption of data stream", - EncryptAutoEnc, - 0, - "automatically encrypt output" }, - { "autodecrypt", - "automatic decryption of data stream", - EncryptAutoDec, - 0, - "automatically decrypt input" }, - { "verbose_encrypt", - "verbose encryption output", - EncryptVerbose, - 0, - "print verbose encryption output" }, - { "encdebug", - "encryption debugging", - EncryptDebug, - 0, - "print encryption debugging information" }, -#endif -#if defined(KRB5) - { "forward", - "credentials forwarding", - kerberos5_set_forward, - 0, - "forward credentials" }, - { "forwardable", - "forwardable flag of forwarded credentials", - kerberos5_set_forwardable, - 0, - "forward forwardable credentials" }, -#endif - { "skiprc", - "don't read ~/.telnetrc file", - 0, - &skiprc, - "skip reading of ~/.telnetrc file" }, - { "binary", - "sending and receiving of binary data", - togbinary, - 0, - 0 }, - { "inbinary", - "receiving of binary data", - togrbinary, - 0, - 0 }, - { "outbinary", - "sending of binary data", - togxbinary, - 0, - 0 }, - { "crlf", - "sending carriage returns as telnet ", - togcrlf, - &crlf, - 0 }, - { "crmod", - "mapping of received carriage returns", - 0, - &crmod, - "map carriage return on output" }, - { "localchars", - "local recognition of certain control characters", - lclchars, - &localchars, - "recognize certain control characters" }, - { " ", "", 0 }, /* empty line */ - { "debug", - "debugging", - togdebug, - &debug, - "turn on socket level debugging" }, - { "netdata", - "printing of hexadecimal network data (debugging)", - 0, - &netdata, - "print hexadecimal representation of network traffic" }, - { "prettydump", - "output of \"netdata\" to user readable format (debugging)", - 0, - &prettydump, - "print user readable output for \"netdata\"" }, - { "options", - "viewing of options processing (debugging)", - 0, - &showoptions, - "show option processing" }, - { "termdata", - "printing of hexadecimal terminal data (debugging)", - 0, - &termdata, - "print hexadecimal representation of terminal traffic" }, - { "?", - 0, - togglehelp }, - { "help", - 0, - togglehelp }, - { 0 } -}; - -static int -togglehelp() -{ - struct togglelist *c; - - for (c = Togglelist; c->name; c++) { - if (c->help) { - if (*c->help) - printf("%-15s toggle %s\r\n", c->name, c->help); - else - printf("\r\n"); - } - } - printf("\r\n"); - printf("%-15s %s\r\n", "?", "display help information"); - return 0; -} - -static void -settogglehelp(int set) -{ - struct togglelist *c; - - for (c = Togglelist; c->name; c++) { - if (c->help) { - if (*c->help) - printf("%-15s %s %s\r\n", c->name, set ? "enable" : "disable", - c->help); - else - printf("\r\n"); - } - } -} - -#define GETTOGGLE(name) (struct togglelist *) \ - genget(name, (char **) Togglelist, sizeof(struct togglelist)) - -static int -toggle(int argc, char *argv[]) -{ - int retval = 1; - char *name; - struct togglelist *c; - - if (argc < 2) { - fprintf(stderr, - "Need an argument to 'toggle' command. 'toggle ?' for help.\r\n"); - return 0; - } - argc--; - argv++; - while (argc--) { - name = *argv++; - c = GETTOGGLE(name); - if (Ambiguous(c)) { - fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\r\n", - name); - return 0; - } else if (c == 0) { - fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\r\n", - name); - return 0; - } else { - if (c->variable) { - *c->variable = !*c->variable; /* invert it */ - if (c->actionexplanation) { - printf("%s %s.\r\n", *c->variable? "Will" : "Won't", - c->actionexplanation); - } - } - if (c->handler) { - retval &= (*c->handler)(-1); - } - } - } - return retval; -} - -/* - * The following perform the "set" command. - */ - -struct termios new_tc = { 0 }; - -struct setlist { - char *name; /* name */ - char *help; /* help information */ - void (*handler)(); - cc_t *charp; /* where it is located at */ -}; - -static struct setlist Setlist[] = { -#ifdef KLUDGELINEMODE - { "echo", "character to toggle local echoing on/off", 0, &echoc }, -#endif - { "escape", "character to escape back to telnet command mode", 0, &escape }, - { "rlogin", "rlogin escape character", 0, &rlogin }, - { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile}, - { " ", "" }, - { " ", "The following need 'localchars' to be toggled true", 0, 0 }, - { "flushoutput", "character to cause an Abort Output", 0, &termFlushChar }, - { "interrupt", "character to cause an Interrupt Process", 0, &termIntChar }, - { "quit", "character to cause an Abort process", 0, &termQuitChar }, - { "eof", "character to cause an EOF ", 0, &termEofChar }, - { " ", "" }, - { " ", "The following are for local editing in linemode", 0, 0 }, - { "erase", "character to use to erase a character", 0, &termEraseChar }, - { "kill", "character to use to erase a line", 0, &termKillChar }, - { "lnext", "character to use for literal next", 0, &termLiteralNextChar }, - { "susp", "character to cause a Suspend Process", 0, &termSuspChar }, - { "reprint", "character to use for line reprint", 0, &termRprntChar }, - { "worderase", "character to use to erase a word", 0, &termWerasChar }, - { "start", "character to use for XON", 0, &termStartChar }, - { "stop", "character to use for XOFF", 0, &termStopChar }, - { "forw1", "alternate end of line character", 0, &termForw1Char }, - { "forw2", "alternate end of line character", 0, &termForw2Char }, - { "ayt", "alternate AYT character", 0, &termAytChar }, - { 0 } -}; - -static struct setlist * -getset(char *name) -{ - return (struct setlist *) - genget(name, (char **) Setlist, sizeof(struct setlist)); -} - -void -set_escape_char(char *s) -{ - if (rlogin != _POSIX_VDISABLE) { - rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE; - printf("Telnet rlogin escape character is '%s'.\r\n", - control(rlogin)); - } else { - escape = (s && *s) ? special(s) : _POSIX_VDISABLE; - printf("Telnet escape character is '%s'.\r\n", control(escape)); - } -} - -static int -setcmd(int argc, char *argv[]) -{ - int value; - struct setlist *ct; - struct togglelist *c; - - if (argc < 2 || argc > 3) { - printf("Format is 'set Name Value'\r\n'set ?' for help.\r\n"); - return 0; - } - if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) { - for (ct = Setlist; ct->name; ct++) - printf("%-15s %s\r\n", ct->name, ct->help); - printf("\r\n"); - settogglehelp(1); - printf("%-15s %s\r\n", "?", "display help information"); - return 0; - } - - ct = getset(argv[1]); - if (ct == 0) { - c = GETTOGGLE(argv[1]); - if (c == 0) { - fprintf(stderr, "'%s': unknown argument ('set ?' for help).\r\n", - argv[1]); - return 0; - } else if (Ambiguous(c)) { - fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\r\n", - argv[1]); - return 0; - } - if (c->variable) { - if ((argc == 2) || (strcmp("on", argv[2]) == 0)) - *c->variable = 1; - else if (strcmp("off", argv[2]) == 0) - *c->variable = 0; - else { - printf("Format is 'set togglename [on|off]'\r\n'set ?' for help.\r\n"); - return 0; - } - if (c->actionexplanation) { - printf("%s %s.\r\n", *c->variable? "Will" : "Won't", - c->actionexplanation); - } - } - if (c->handler) - (*c->handler)(1); - } else if (argc != 3) { - printf("Format is 'set Name Value'\r\n'set ?' for help.\r\n"); - return 0; - } else if (Ambiguous(ct)) { - fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\r\n", - argv[1]); - return 0; - } else if (ct->handler) { - (*ct->handler)(argv[2]); - printf("%s set to \"%s\".\r\n", ct->name, (char *)ct->charp); - } else { - if (strcmp("off", argv[2])) { - value = special(argv[2]); - } else { - value = _POSIX_VDISABLE; - } - *(ct->charp) = (cc_t)value; - printf("%s character is '%s'.\r\n", ct->name, control(*(ct->charp))); - } - slc_check(); - return 1; -} - -static int -unsetcmd(int argc, char *argv[]) -{ - struct setlist *ct; - struct togglelist *c; - char *name; - - if (argc < 2) { - fprintf(stderr, - "Need an argument to 'unset' command. 'unset ?' for help.\r\n"); - return 0; - } - if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) { - for (ct = Setlist; ct->name; ct++) - printf("%-15s %s\r\n", ct->name, ct->help); - printf("\r\n"); - settogglehelp(0); - printf("%-15s %s\r\n", "?", "display help information"); - return 0; - } - - argc--; - argv++; - while (argc--) { - name = *argv++; - ct = getset(name); - if (ct == 0) { - c = GETTOGGLE(name); - if (c == 0) { - fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\r\n", - name); - return 0; - } else if (Ambiguous(c)) { - fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\r\n", - name); - return 0; - } - if (c->variable) { - *c->variable = 0; - if (c->actionexplanation) { - printf("%s %s.\r\n", *c->variable? "Will" : "Won't", - c->actionexplanation); - } - } - if (c->handler) - (*c->handler)(0); - } else if (Ambiguous(ct)) { - fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\r\n", - name); - return 0; - } else if (ct->handler) { - (*ct->handler)(0); - printf("%s reset to \"%s\".\r\n", ct->name, (char *)ct->charp); - } else { - *(ct->charp) = _POSIX_VDISABLE; - printf("%s character is '%s'.\r\n", ct->name, control(*(ct->charp))); - } - } - return 1; -} - -/* - * The following are the data structures and routines for the - * 'mode' command. - */ -#ifdef KLUDGELINEMODE - -static int -dokludgemode(void) -{ - kludgelinemode = 1; - send_wont(TELOPT_LINEMODE, 1); - send_dont(TELOPT_SGA, 1); - send_dont(TELOPT_ECHO, 1); - return 1; -} -#endif - -static int -dolinemode() -{ -#ifdef KLUDGELINEMODE - if (kludgelinemode) - send_dont(TELOPT_SGA, 1); -#endif - send_will(TELOPT_LINEMODE, 1); - send_dont(TELOPT_ECHO, 1); - return 1; -} - -static int -docharmode() -{ -#ifdef KLUDGELINEMODE - if (kludgelinemode) - send_do(TELOPT_SGA, 1); - else -#endif - send_wont(TELOPT_LINEMODE, 1); - send_do(TELOPT_ECHO, 1); - return 1; -} - -static int -dolmmode(int bit, int on) -{ - unsigned char c; - - if (my_want_state_is_wont(TELOPT_LINEMODE)) { - printf("?Need to have LINEMODE option enabled first.\r\n"); - printf("'mode ?' for help.\r\n"); - return 0; - } - - if (on) - c = (linemode | bit); - else - c = (linemode & ~bit); - lm_mode(&c, 1, 1); - return 1; -} - -static int -tn_setmode(int bit) -{ - return dolmmode(bit, 1); -} - -static int -tn_clearmode(int bit) -{ - return dolmmode(bit, 0); -} - -struct modelist { - char *name; /* command name */ - char *help; /* help string */ - int (*handler)(); /* routine which executes command */ - int needconnect; /* Do we need to be connected to execute? */ - int arg1; -}; - -static int modehelp(void); - -static struct modelist ModeList[] = { - { "character", "Disable LINEMODE option", docharmode, 1 }, -#ifdef KLUDGELINEMODE - { "", "(or disable obsolete line-by-line mode)", 0 }, -#endif - { "line", "Enable LINEMODE option", dolinemode, 1 }, -#ifdef KLUDGELINEMODE - { "", "(or enable obsolete line-by-line mode)", 0 }, -#endif - { "", "", 0 }, - { "", "These require the LINEMODE option to be enabled", 0 }, - { "isig", "Enable signal trapping", tn_setmode, 1, MODE_TRAPSIG }, - { "+isig", 0, tn_setmode, 1, MODE_TRAPSIG }, - { "-isig", "Disable signal trapping", tn_clearmode, 1, MODE_TRAPSIG }, - { "edit", "Enable character editing", tn_setmode, 1, MODE_EDIT }, - { "+edit", 0, tn_setmode, 1, MODE_EDIT }, - { "-edit", "Disable character editing", tn_clearmode, 1, MODE_EDIT }, - { "softtabs", "Enable tab expansion", tn_setmode, 1, MODE_SOFT_TAB }, - { "+softtabs", 0, tn_setmode, 1, MODE_SOFT_TAB }, - { "-softtabs", "Disable tab expansion", tn_clearmode, 1, MODE_SOFT_TAB }, - { "litecho", "Enable literal character echo", tn_setmode, 1, MODE_LIT_ECHO }, - { "+litecho", 0, tn_setmode, 1, MODE_LIT_ECHO }, - { "-litecho", "Disable literal character echo", tn_clearmode, 1, MODE_LIT_ECHO }, - { "help", 0, modehelp, 0 }, -#ifdef KLUDGELINEMODE - { "kludgeline", 0, dokludgemode, 1 }, -#endif - { "", "", 0 }, - { "?", "Print help information", modehelp, 0 }, - { 0 }, -}; - - -static int -modehelp(void) -{ - struct modelist *mt; - - printf("format is: 'mode Mode', where 'Mode' is one of:\r\n\r\n"); - for (mt = ModeList; mt->name; mt++) { - if (mt->help) { - if (*mt->help) - printf("%-15s %s\r\n", mt->name, mt->help); - else - printf("\r\n"); - } - } - return 0; -} - -#define GETMODECMD(name) (struct modelist *) \ - genget(name, (char **) ModeList, sizeof(struct modelist)) - -static int -modecmd(int argc, char **argv) -{ - struct modelist *mt; - - if (argc != 2) { - printf("'mode' command requires an argument\r\n"); - printf("'mode ?' for help.\r\n"); - } else if ((mt = GETMODECMD(argv[1])) == 0) { - fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\r\n", argv[1]); - } else if (Ambiguous(mt)) { - fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\r\n", argv[1]); - } else if (mt->needconnect && !connected) { - printf("?Need to be connected first.\r\n"); - printf("'mode ?' for help.\r\n"); - } else if (mt->handler) { - return (*mt->handler)(mt->arg1); - } - return 0; -} - -/* - * The following data structures and routines implement the - * "display" command. - */ - -static int -display(int argc, char *argv[]) -{ - struct togglelist *tl; - struct setlist *sl; - -#define dotog(tl) if (tl->variable && tl->actionexplanation) { \ - if (*tl->variable) { \ - printf("will"); \ - } else { \ - printf("won't"); \ - } \ - printf(" %s.\r\n", tl->actionexplanation); \ - } - -#define doset(sl) if (sl->name && *sl->name != ' ') { \ - if (sl->handler == 0) \ - printf("%-15s [%s]\r\n", sl->name, control(*sl->charp)); \ - else \ - printf("%-15s \"%s\"\r\n", sl->name, (char *)sl->charp); \ - } - - if (argc == 1) { - for (tl = Togglelist; tl->name; tl++) { - dotog(tl); - } - printf("\r\n"); - for (sl = Setlist; sl->name; sl++) { - doset(sl); - } - } else { - int i; - - for (i = 1; i < argc; i++) { - sl = getset(argv[i]); - tl = GETTOGGLE(argv[i]); - if (Ambiguous(sl) || Ambiguous(tl)) { - printf("?Ambiguous argument '%s'.\r\n", argv[i]); - return 0; - } else if (!sl && !tl) { - printf("?Unknown argument '%s'.\r\n", argv[i]); - return 0; - } else { - if (tl) { - dotog(tl); - } - if (sl) { - doset(sl); - } - } - } - } -/*@*/optionstatus(); -#if defined(ENCRYPTION) - EncryptStatus(); -#endif - return 1; -#undef doset -#undef dotog -} - -/* - * The following are the data structures, and many of the routines, - * relating to command processing. - */ - -/* - * Set the escape character. - */ -static int -setescape(int argc, char *argv[]) -{ - char *arg; - char buf[50]; - - printf( - "Deprecated usage - please use 'set escape%s%s' in the future.\r\n", - (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); - if (argc > 2) - arg = argv[1]; - else { - printf("new escape character: "); - fgets(buf, sizeof(buf), stdin); - arg = buf; - } - if (arg[0] != '\0') - escape = arg[0]; - printf("Escape character is '%s'.\r\n", control(escape)); - - fflush(stdout); - return 1; -} - -static int -togcrmod() -{ - crmod = !crmod; - printf("Deprecated usage - please use 'toggle crmod' in the future.\r\n"); - printf("%s map carriage return on output.\r\n", crmod ? "Will" : "Won't"); - fflush(stdout); - return 1; -} - -static int -telnetsuspend() -{ -#ifdef SIGTSTP - setcommandmode(); - { - long oldrows, oldcols, newrows, newcols, err; - - err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; - kill(0, SIGTSTP); - /* - * If we didn't get the window size before the SUSPEND, but we - * can get them now (?), then send the NAWS to make sure that - * we are set up for the right window size. - */ - if (TerminalWindowSize(&newrows, &newcols) && connected && - (err || ((oldrows != newrows) || (oldcols != newcols)))) { - sendnaws(); - } - } - /* reget parameters in case they were changed */ - TerminalSaveState(); - setconnmode(0); -#else - printf("Suspend is not supported. Try the '!' command instead\r\n"); -#endif - return 1; -} - -static int -shell(int argc, char **argv) -{ - long oldrows, oldcols, newrows, newcols, err; - - setcommandmode(); - - err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; - switch(fork()) { - case -1: - perror("Fork failed\r\n"); - break; - - case 0: - { - /* - * Fire up the shell in the child. - */ - char *shellp, *shellname; - - shellp = getenv("SHELL"); - if (shellp == NULL) - shellp = "/bin/sh"; - if ((shellname = strrchr(shellp, '/')) == 0) - shellname = shellp; - else - shellname++; - if (argc > 1) - execl(shellp, shellname, "-c", &saveline[1], NULL); - else - execl(shellp, shellname, NULL); - perror("Execl"); - _exit(1); - } - default: - wait((int *)0); /* Wait for the shell to complete */ - - if (TerminalWindowSize(&newrows, &newcols) && connected && - (err || ((oldrows != newrows) || (oldcols != newcols)))) { - sendnaws(); - } - break; - } - return 1; -} - -static int -bye(int argc, char **argv) -{ - if (connected) { - shutdown(net, 2); - printf("Connection closed.\r\n"); - NetClose(net); - connected = 0; - resettermname = 1; -#if defined(AUTHENTICATION) || defined(ENCRYPTION) - auth_encrypt_connect(connected); -#endif - /* reset options */ - tninit(); - } - if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) - longjmp(toplevel, 1); - return 0; /* NOTREACHED */ -} - -int -quit(void) -{ - call(bye, "bye", "fromquit", 0); - Exit(0); - return 0; /*NOTREACHED*/ -} - -static int -logout() -{ - send_do(TELOPT_LOGOUT, 1); - netflush(); - return 1; -} - - -/* - * The SLC command. - */ - -struct slclist { - char *name; - char *help; - void (*handler)(); - int arg; -}; - -static void slc_help(void); - -struct slclist SlcList[] = { - { "export", "Use local special character definitions", - slc_mode_export, 0 }, - { "import", "Use remote special character definitions", - slc_mode_import, 1 }, - { "check", "Verify remote special character definitions", - slc_mode_import, 0 }, - { "help", 0, slc_help, 0 }, - { "?", "Print help information", slc_help, 0 }, - { 0 }, -}; - -static void -slc_help(void) -{ - struct slclist *c; - - for (c = SlcList; c->name; c++) { - if (c->help) { - if (*c->help) - printf("%-15s %s\r\n", c->name, c->help); - else - printf("\r\n"); - } - } -} - -static struct slclist * -getslc(char *name) -{ - return (struct slclist *) - genget(name, (char **) SlcList, sizeof(struct slclist)); -} - -static int -slccmd(int argc, char **argv) -{ - struct slclist *c; - - if (argc != 2) { - fprintf(stderr, - "Need an argument to 'slc' command. 'slc ?' for help.\r\n"); - return 0; - } - c = getslc(argv[1]); - if (c == 0) { - fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\r\n", - argv[1]); - return 0; - } - if (Ambiguous(c)) { - fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\r\n", - argv[1]); - return 0; - } - (*c->handler)(c->arg); - slcstate(); - return 1; -} - -/* - * The ENVIRON command. - */ - -struct envlist { - char *name; - char *help; - void (*handler)(); - int narg; -}; - -static void env_help (void); - -struct envlist EnvList[] = { - { "define", "Define an environment variable", - (void (*)())env_define, 2 }, - { "undefine", "Undefine an environment variable", - env_undefine, 1 }, - { "export", "Mark an environment variable for automatic export", - env_export, 1 }, - { "unexport", "Don't mark an environment variable for automatic export", - env_unexport, 1 }, - { "send", "Send an environment variable", env_send, 1 }, - { "list", "List the current environment variables", - env_list, 0 }, - { "help", 0, env_help, 0 }, - { "?", "Print help information", env_help, 0 }, - { 0 }, -}; - -static void -env_help() -{ - struct envlist *c; - - for (c = EnvList; c->name; c++) { - if (c->help) { - if (*c->help) - printf("%-15s %s\r\n", c->name, c->help); - else - printf("\r\n"); - } - } -} - -static struct envlist * -getenvcmd(char *name) -{ - return (struct envlist *) - genget(name, (char **) EnvList, sizeof(struct envlist)); -} - -static int -env_cmd(int argc, char **argv) -{ - struct envlist *c; - - if (argc < 2) { - fprintf(stderr, - "Need an argument to 'environ' command. 'environ ?' for help.\r\n"); - return 0; - } - c = getenvcmd(argv[1]); - if (c == 0) { - fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\r\n", - argv[1]); - return 0; - } - if (Ambiguous(c)) { - fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\r\n", - argv[1]); - return 0; - } - if (c->narg + 2 != argc) { - fprintf(stderr, - "Need %s%d argument%s to 'environ %s' command. 'environ ?' for help.\r\n", - c->narg < argc + 2 ? "only " : "", - c->narg, c->narg == 1 ? "" : "s", c->name); - return 0; - } - (*c->handler)(argv[2], argv[3]); - return 1; -} - -struct env_lst { - struct env_lst *next; /* pointer to next structure */ - struct env_lst *prev; /* pointer to previous structure */ - unsigned char *var; /* pointer to variable name */ - unsigned char *value; /* pointer to variable value */ - int export; /* 1 -> export with default list of variables */ - int welldefined; /* A well defined variable */ -}; - -struct env_lst envlisthead; - -struct env_lst * -env_find(unsigned char *var) -{ - struct env_lst *ep; - - for (ep = envlisthead.next; ep; ep = ep->next) { - if (strcmp((char *)ep->var, (char *)var) == 0) - return(ep); - } - return(NULL); -} - -#if !HAVE_DECL_ENVIRON -extern char **environ; -#endif - -void -env_init(void) -{ - char **epp, *cp; - struct env_lst *ep; - - for (epp = environ; *epp; epp++) { - if ((cp = strchr(*epp, '='))) { - *cp = '\0'; - ep = env_define((unsigned char *)*epp, - (unsigned char *)cp+1); - ep->export = 0; - *cp = '='; - } - } - /* - * Special case for DISPLAY variable. If it is ":0.0" or - * "unix:0.0", we have to get rid of "unix" and insert our - * hostname. - */ - if ((ep = env_find((unsigned char*)"DISPLAY")) - && (*ep->value == ':' - || strncmp((char *)ep->value, "unix:", 5) == 0)) { - char hbuf[256+1]; - char *cp2 = strchr((char *)ep->value, ':'); - int error; - - /* XXX - should be k_gethostname? */ - gethostname(hbuf, 256); - hbuf[256] = '\0'; - - /* If this is not the full name, try to get it via DNS */ - if (strchr(hbuf, '.') == 0) { - struct addrinfo hints, *ai, *a; - - memset (&hints, 0, sizeof(hints)); - hints.ai_flags = AI_CANONNAME; - - error = getaddrinfo (hbuf, NULL, &hints, &ai); - if (error == 0) { - for (a = ai; a != NULL; a = a->ai_next) - if (a->ai_canonname != NULL) { - strlcpy (hbuf, - ai->ai_canonname, - 256); - break; - } - freeaddrinfo (ai); - } - } - - error = asprintf (&cp, "%s%s", hbuf, cp2); - if (error != -1) { - free (ep->value); - ep->value = (unsigned char *)cp; - } - } - /* - * If USER is not defined, but LOGNAME is, then add - * USER with the value from LOGNAME. By default, we - * don't export the USER variable. - */ - if ((env_find((unsigned char*)"USER") == NULL) && - (ep = env_find((unsigned char*)"LOGNAME"))) { - env_define((unsigned char *)"USER", ep->value); - env_unexport((unsigned char *)"USER"); - } - env_export((unsigned char *)"DISPLAY"); - env_export((unsigned char *)"PRINTER"); - env_export((unsigned char *)"XAUTHORITY"); -} - -struct env_lst * -env_define(unsigned char *var, unsigned char *value) -{ - struct env_lst *ep; - - if ((ep = env_find(var))) { - if (ep->var) - free(ep->var); - if (ep->value) - free(ep->value); - } else { - ep = (struct env_lst *)malloc(sizeof(struct env_lst)); - ep->next = envlisthead.next; - envlisthead.next = ep; - ep->prev = &envlisthead; - if (ep->next) - ep->next->prev = ep; - } - ep->welldefined = opt_welldefined((char *)var); - ep->export = 1; - ep->var = (unsigned char *)strdup((char *)var); - ep->value = (unsigned char *)strdup((char *)value); - return(ep); -} - -void -env_undefine(unsigned char *var) -{ - struct env_lst *ep; - - if ((ep = env_find(var))) { - ep->prev->next = ep->next; - if (ep->next) - ep->next->prev = ep->prev; - if (ep->var) - free(ep->var); - if (ep->value) - free(ep->value); - free(ep); - } -} - -void -env_export(unsigned char *var) -{ - struct env_lst *ep; - - if ((ep = env_find(var))) - ep->export = 1; -} - -void -env_unexport(unsigned char *var) -{ - struct env_lst *ep; - - if ((ep = env_find(var))) - ep->export = 0; -} - -void -env_send(unsigned char *var) -{ - struct env_lst *ep; - - if (my_state_is_wont(TELOPT_NEW_ENVIRON) -#ifdef OLD_ENVIRON - && my_state_is_wont(TELOPT_OLD_ENVIRON) -#endif - ) { - fprintf(stderr, - "Cannot send '%s': Telnet ENVIRON option not enabled\r\n", - var); - return; - } - ep = env_find(var); - if (ep == 0) { - fprintf(stderr, "Cannot send '%s': variable not defined\r\n", - var); - return; - } - env_opt_start_info(); - env_opt_add(ep->var); - env_opt_end(0); -} - -void -env_list(void) -{ - struct env_lst *ep; - - for (ep = envlisthead.next; ep; ep = ep->next) { - printf("%c %-20s %s\r\n", ep->export ? '*' : ' ', - ep->var, ep->value); - } -} - -unsigned char * -env_default(int init, int welldefined) -{ - static struct env_lst *nep = NULL; - - if (init) { - nep = &envlisthead; - return NULL; - } - if (nep) { - while ((nep = nep->next)) { - if (nep->export && (nep->welldefined == welldefined)) - return(nep->var); - } - } - return(NULL); -} - -unsigned char * -env_getvalue(unsigned char *var) -{ - struct env_lst *ep; - - if ((ep = env_find(var))) - return(ep->value); - return(NULL); -} - - -#if defined(AUTHENTICATION) -/* - * The AUTHENTICATE command. - */ - -struct authlist { - char *name; - char *help; - int (*handler)(); - int narg; -}; - -static int - auth_help (void); - -struct authlist AuthList[] = { - { "status", "Display current status of authentication information", - auth_status, 0 }, - { "disable", "Disable an authentication type ('auth disable ?' for more)", - auth_disable, 1 }, - { "enable", "Enable an authentication type ('auth enable ?' for more)", - auth_enable, 1 }, - { "help", 0, auth_help, 0 }, - { "?", "Print help information", auth_help, 0 }, - { 0 }, -}; - -static int -auth_help() -{ - struct authlist *c; - - for (c = AuthList; c->name; c++) { - if (c->help) { - if (*c->help) - printf("%-15s %s\r\n", c->name, c->help); - else - printf("\r\n"); - } - } - return 0; -} - -static int -auth_cmd(int argc, char **argv) -{ - struct authlist *c; - - if (argc < 2) { - fprintf(stderr, - "Need an argument to 'auth' command. 'auth ?' for help.\r\n"); - return 0; - } - - c = (struct authlist *) - genget(argv[1], (char **) AuthList, sizeof(struct authlist)); - if (c == 0) { - fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\r\n", - argv[1]); - return 0; - } - if (Ambiguous(c)) { - fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\r\n", - argv[1]); - return 0; - } - if (c->narg + 2 != argc) { - fprintf(stderr, - "Need %s%d argument%s to 'auth %s' command. 'auth ?' for help.\r\n", - c->narg < argc + 2 ? "only " : "", - c->narg, c->narg == 1 ? "" : "s", c->name); - return 0; - } - return((*c->handler)(argv[2], argv[3])); -} -#endif - - -#if defined(ENCRYPTION) -/* - * The ENCRYPT command. - */ - -struct encryptlist { - char *name; - char *help; - int (*handler)(); - int needconnect; - int minarg; - int maxarg; -}; - -static int - EncryptHelp (void); - -struct encryptlist EncryptList[] = { - { "enable", "Enable encryption. ('encrypt enable ?' for more)", - EncryptEnable, 1, 1, 2 }, - { "disable", "Disable encryption. ('encrypt enable ?' for more)", - EncryptDisable, 0, 1, 2 }, - { "type", "Set encryptiong type. ('encrypt type ?' for more)", - EncryptType, 0, 1, 1 }, - { "start", "Start encryption. ('encrypt start ?' for more)", - EncryptStart, 1, 0, 1 }, - { "stop", "Stop encryption. ('encrypt stop ?' for more)", - EncryptStop, 1, 0, 1 }, - { "input", "Start encrypting the input stream", - EncryptStartInput, 1, 0, 0 }, - { "-input", "Stop encrypting the input stream", - EncryptStopInput, 1, 0, 0 }, - { "output", "Start encrypting the output stream", - EncryptStartOutput, 1, 0, 0 }, - { "-output", "Stop encrypting the output stream", - EncryptStopOutput, 1, 0, 0 }, - - { "status", "Display current status of authentication information", - EncryptStatus, 0, 0, 0 }, - { "help", 0, EncryptHelp, 0, 0, 0 }, - { "?", "Print help information", EncryptHelp, 0, 0, 0 }, - { 0 }, -}; - -static int -EncryptHelp() -{ - struct encryptlist *c; - - for (c = EncryptList; c->name; c++) { - if (c->help) { - if (*c->help) - printf("%-15s %s\r\n", c->name, c->help); - else - printf("\r\n"); - } - } - return 0; -} - -static int -encrypt_cmd(int argc, char **argv) -{ - struct encryptlist *c; - - c = (struct encryptlist *) - genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist)); - if (c == 0) { - fprintf(stderr, "'%s': unknown argument ('encrypt ?' for help).\r\n", - argv[1]); - return 0; - } - if (Ambiguous(c)) { - fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\r\n", - argv[1]); - return 0; - } - argc -= 2; - if (argc < c->minarg || argc > c->maxarg) { - if (c->minarg == c->maxarg) { - fprintf(stderr, "Need %s%d argument%s ", - c->minarg < argc ? "only " : "", c->minarg, - c->minarg == 1 ? "" : "s"); - } else { - fprintf(stderr, "Need %s%d-%d arguments ", - c->maxarg < argc ? "only " : "", c->minarg, c->maxarg); - } - fprintf(stderr, "to 'encrypt %s' command. 'encrypt ?' for help.\r\n", - c->name); - return 0; - } - if (c->needconnect && !connected) { - if (!(argc && (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) { - printf("?Need to be connected first.\r\n"); - return 0; - } - } - return ((*c->handler)(argc > 0 ? argv[2] : 0, - argc > 1 ? argv[3] : 0, - argc > 2 ? argv[4] : 0)); -} -#endif - - -/* - * Print status about the connection. - */ - -static int -status(int argc, char **argv) -{ - if (connected) { - printf("Connected to %s.\r\n", hostname); - if ((argc < 2) || strcmp(argv[1], "notmuch")) { - int mode = getconnmode(); - - if (my_want_state_is_will(TELOPT_LINEMODE)) { - printf("Operating with LINEMODE option\r\n"); - printf("%s line editing\r\n", (mode&MODE_EDIT) ? "Local" : "No"); - printf("%s catching of signals\r\n", - (mode&MODE_TRAPSIG) ? "Local" : "No"); - slcstate(); -#ifdef KLUDGELINEMODE - } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) { - printf("Operating in obsolete linemode\r\n"); -#endif - } else { - printf("Operating in single character mode\r\n"); - if (localchars) - printf("Catching signals locally\r\n"); - } - printf("%s character echo\r\n", (mode&MODE_ECHO) ? "Local" : "Remote"); - if (my_want_state_is_will(TELOPT_LFLOW)) - printf("%s flow control\r\n", (mode&MODE_FLOW) ? "Local" : "No"); -#if defined(ENCRYPTION) - encrypt_display(); -#endif - } - } else { - printf("No connection.\r\n"); - } - printf("Escape character is '%s'.\r\n", control(escape)); - fflush(stdout); - return 1; -} - -#ifdef SIGINFO -/* - * Function that gets called when SIGINFO is received. - */ -RETSIGTYPE -ayt_status(int ignore) -{ - call(status, "status", "notmuch", 0); -} -#endif - -static Command *getcmd(char *name); - -static void -cmdrc(char *m1, char *m2) -{ - static char rcname[128]; - Command *c; - FILE *rcfile; - int gotmachine = 0; - int l1 = strlen(m1); - int l2 = strlen(m2); - char m1save[64]; - - if (skiprc) - return; - - strlcpy(m1save, m1, sizeof(m1save)); - m1 = m1save; - - if (rcname[0] == 0) { - char *home = getenv("HOME"); - - snprintf (rcname, sizeof(rcname), "%s/.telnetrc", - home ? home : ""); - } - - if ((rcfile = fopen(rcname, "r")) == 0) { - return; - } - - for (;;) { - if (fgets(line, sizeof(line), rcfile) == NULL) - break; - if (line[0] == 0) - break; - if (line[0] == '#') - continue; - if (gotmachine) { - if (!isspace((unsigned char)line[0])) - gotmachine = 0; - } - if (gotmachine == 0) { - if (isspace((unsigned char)line[0])) - continue; - if (strncasecmp(line, m1, l1) == 0) - strncpy(line, &line[l1], sizeof(line) - l1); - else if (strncasecmp(line, m2, l2) == 0) - strncpy(line, &line[l2], sizeof(line) - l2); - else if (strncasecmp(line, "DEFAULT", 7) == 0) - strncpy(line, &line[7], sizeof(line) - 7); - else - continue; - if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n') - continue; - gotmachine = 1; - } - makeargv(); - if (margv[0] == 0) - continue; - c = getcmd(margv[0]); - if (Ambiguous(c)) { - printf("?Ambiguous command: %s\r\n", margv[0]); - continue; - } - if (c == 0) { - printf("?Invalid command: %s\r\n", margv[0]); - continue; - } - /* - * This should never happen... - */ - if (c->needconnect && !connected) { - printf("?Need to be connected first for %s.\r\n", margv[0]); - continue; - } - (*c->handler)(margc, margv); - } - fclose(rcfile); -} - -int -tn(int argc, char **argv) -{ - struct servent *sp = 0; - char *cmd, *hostp = 0, *portp = 0; - char *user = 0; - int port = 0; - - /* clear the socket address prior to use */ - - if (connected) { - printf("?Already connected to %s\r\n", hostname); - return 0; - } - if (argc < 2) { - strlcpy(line, "open ", sizeof(line)); - printf("(to) "); - fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin); - makeargv(); - argc = margc; - argv = margv; - } - cmd = *argv; - --argc; ++argv; - while (argc) { - if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?")) - goto usage; - if (strcmp(*argv, "-l") == 0) { - --argc; ++argv; - if (argc == 0) - goto usage; - user = strdup(*argv++); - --argc; - continue; - } - if (strcmp(*argv, "-a") == 0) { - --argc; ++argv; - autologin = 1; - continue; - } - if (hostp == 0) { - hostp = *argv++; - --argc; - continue; - } - if (portp == 0) { - portp = *argv++; - --argc; - continue; - } - usage: - printf("usage: %s [-l user] [-a] host-name [port]\r\n", cmd); - return 0; - } - if (hostp == 0) - goto usage; - - strlcpy (_hostname, hostp, sizeof(_hostname)); - hostp = _hostname; - if (hostp[0] == '@' || hostp[0] == '!') { - char *p; - hostname = NULL; - for (p = hostp + 1; *p; p++) { - if (*p == ',' || *p == '@') - hostname = p; - } - if (hostname == NULL) { - fprintf(stderr, "%s: bad source route specification\n", hostp); - return 0; - } - *hostname++ = '\0'; - } else - hostname = hostp; - - if (portp) { - if (*portp == '-') { - portp++; - telnetport = 1; - } else - telnetport = 0; - port = atoi(portp); - if (port == 0) { - sp = roken_getservbyname(portp, "tcp"); - if (sp) - port = sp->s_port; - else { - printf("%s: bad port number\r\n", portp); - return 0; - } - } else { - port = htons(port); - } - } else { - if (sp == 0) { - sp = roken_getservbyname("telnet", "tcp"); - if (sp == 0) { - fprintf(stderr, "telnet: tcp/telnet: unknown service\r\n"); - return 0; - } - port = sp->s_port; - } - telnetport = 1; - } - - { - struct addrinfo *ai, *a, hints; - int error; - char portstr[NI_MAXSERV]; - - memset (&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - hints.ai_flags = AI_CANONNAME; - - snprintf (portstr, sizeof(portstr), "%u", ntohs(port)); - - error = getaddrinfo (hostname, portstr, &hints, &ai); - if (error) { - fprintf (stderr, "%s: %s\r\n", hostname, gai_strerror (error)); - return 0; - } - - for (a = ai; a != NULL && connected == 0; a = a->ai_next) { - char addrstr[256]; - - if (a->ai_canonname != NULL) - strlcpy (_hostname, a->ai_canonname, sizeof(_hostname)); - - if (getnameinfo (a->ai_addr, a->ai_addrlen, - addrstr, sizeof(addrstr), - NULL, 0, NI_NUMERICHOST) != 0) - strlcpy (addrstr, "unknown address", sizeof(addrstr)); - - printf("Trying %s...\r\n", addrstr); - - net = socket (a->ai_family, a->ai_socktype, a->ai_protocol); - if (net < 0) { - warn ("socket"); - continue; - } - -#if defined(IP_OPTIONS) && defined(IPPROTO_IP) && defined(HAVE_SETSOCKOPT) - if (hostp[0] == '@' || hostp[0] == '!') { - char *srp = 0; - int srlen; - int proto, opt; - - if ((srlen = sourceroute(a, hostp, &srp, &proto, &opt)) < 0) { - (void) NetClose(net); - net = -1; - continue; - } - if (srp && setsockopt(net, proto, opt, srp, srlen) < 0) - perror("setsockopt (source route)"); - } -#endif - -#if defined(IPPROTO_IP) && defined(IP_TOS) - if (a->ai_family == AF_INET) { -# if defined(HAVE_GETTOSBYNAME) - struct tosent *tp; - if (tos < 0 && (tp = gettosbyname("telnet", "tcp"))) - tos = tp->t_tos; -# endif - if (tos < 0) - tos = 020; /* Low Delay bit */ - if (tos - && (setsockopt(net, IPPROTO_IP, IP_TOS, - (void *)&tos, sizeof(int)) < 0) - && (errno != ENOPROTOOPT)) - perror("telnet: setsockopt (IP_TOS) (ignored)"); - } -#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */ - if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { - perror("setsockopt (SO_DEBUG)"); - } - - if (connect (net, a->ai_addr, a->ai_addrlen) < 0) { - fprintf (stderr, "telnet: connect to address %s: %s\n", - addrstr, strerror(errno)); - NetClose(net); - if (a->ai_next != NULL) { - continue; - } else { - freeaddrinfo (ai); - return 0; - } - } - ++connected; -#if defined(AUTHENTICATION) || defined(ENCRYPTION) - auth_encrypt_connect(connected); -#endif - } - freeaddrinfo (ai); - if (connected == 0) - return 0; - } - cmdrc(hostp, hostname); - set_forward_options(); - if (autologin && user == NULL) - user = (char *)get_default_username (); - if (user) { - env_define((unsigned char *)"USER", (unsigned char *)user); - env_export((unsigned char *)"USER"); - } - call(status, "status", "notmuch", 0); - if (setjmp(peerdied) == 0) - my_telnet((char *)user); - NetClose(net); - ExitString("Connection closed by foreign host.\r\n",1); - /*NOTREACHED*/ - return 0; -} - -#define HELPINDENT ((int)sizeof ("connect")) - -static char - openhelp[] = "connect to a site", - closehelp[] = "close current connection", - logouthelp[] = "forcibly logout remote user and close the connection", - quithelp[] = "exit telnet", - statushelp[] = "print status information", - helphelp[] = "print help information", - sendhelp[] = "transmit special characters ('send ?' for more)", - sethelp[] = "set operating parameters ('set ?' for more)", - unsethelp[] = "unset operating parameters ('unset ?' for more)", - togglestring[] ="toggle operating parameters ('toggle ?' for more)", - slchelp[] = "change state of special charaters ('slc ?' for more)", - displayhelp[] = "display operating parameters", -#if defined(AUTHENTICATION) - authhelp[] = "turn on (off) authentication ('auth ?' for more)", -#endif -#if defined(ENCRYPTION) - encrypthelp[] = "turn on (off) encryption ('encrypt ?' for more)", -#endif - zhelp[] = "suspend telnet", - shellhelp[] = "invoke a subshell", - envhelp[] = "change environment variables ('environ ?' for more)", - modestring[] = "try to enter line or character mode ('mode ?' for more)"; - -static int help(int argc, char **argv); - -static Command cmdtab[] = { - { "close", closehelp, bye, 1 }, - { "logout", logouthelp, logout, 1 }, - { "display", displayhelp, display, 0 }, - { "mode", modestring, modecmd, 0 }, - { "open", openhelp, tn, 0 }, - { "quit", quithelp, quit, 0 }, - { "send", sendhelp, sendcmd, 0 }, - { "set", sethelp, setcmd, 0 }, - { "unset", unsethelp, unsetcmd, 0 }, - { "status", statushelp, status, 0 }, - { "toggle", togglestring, toggle, 0 }, - { "slc", slchelp, slccmd, 0 }, -#if defined(AUTHENTICATION) - { "auth", authhelp, auth_cmd, 0 }, -#endif -#if defined(ENCRYPTION) - { "encrypt", encrypthelp, encrypt_cmd, 0 }, -#endif - { "z", zhelp, telnetsuspend, 0 }, - { "!", shellhelp, shell, 0 }, - { "environ", envhelp, env_cmd, 0 }, - { "?", helphelp, help, 0 }, - { 0, 0, 0, 0 } -}; - -static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; -static char escapehelp[] = "deprecated command -- use 'set escape' instead"; - -static Command cmdtab2[] = { - { "help", 0, help, 0 }, - { "escape", escapehelp, setescape, 0 }, - { "crmod", crmodhelp, togcrmod, 0 }, - { 0, 0, 0, 0 } -}; - - -/* - * Call routine with argc, argv set from args (terminated by 0). - */ - -static int -call(intrtn_t routine, ...) -{ - va_list ap; - char *args[100]; - int argno = 0; - - va_start(ap, routine); - while ((args[argno++] = va_arg(ap, char *)) != 0); - va_end(ap); - return (*routine)(argno-1, args); -} - - -static Command -*getcmd(char *name) -{ - Command *cm; - - if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command)))) - return cm; - return (Command *) genget(name, (char **) cmdtab2, sizeof(Command)); -} - -void -command(int top, char *tbuf, int cnt) -{ - Command *c; - - setcommandmode(); - if (!top) { - putchar('\n'); - } else { - signal(SIGINT, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - } - for (;;) { - if (rlogin == _POSIX_VDISABLE) - printf("%s> ", prompt); - if (tbuf) { - char *cp; - cp = line; - while (cnt > 0 && (*cp++ = *tbuf++) != '\n') - cnt--; - tbuf = 0; - if (cp == line || *--cp != '\n' || cp == line) - goto getline; - *cp = '\0'; - if (rlogin == _POSIX_VDISABLE) - printf("%s\r\n", line); - } else { - getline: - if (rlogin != _POSIX_VDISABLE) - printf("%s> ", prompt); - if (fgets(line, sizeof(line), stdin) == NULL) { - if (feof(stdin) || ferror(stdin)) { - quit(); - /*NOTREACHED*/ - } - break; - } - } - if (line[0] == 0) - break; - makeargv(); - if (margv[0] == 0) { - break; - } - c = getcmd(margv[0]); - if (Ambiguous(c)) { - printf("?Ambiguous command\r\n"); - continue; - } - if (c == 0) { - printf("?Invalid command\r\n"); - continue; - } - if (c->needconnect && !connected) { - printf("?Need to be connected first.\r\n"); - continue; - } - if ((*c->handler)(margc, margv)) { - break; - } - } - if (!top) { - if (!connected) { - longjmp(toplevel, 1); - /*NOTREACHED*/ - } - setconnmode(0); - } -} - -/* - * Help command. - */ -static int -help(int argc, char **argv) -{ - Command *c; - - if (argc == 1) { - printf("Commands may be abbreviated. Commands are:\r\n\r\n"); - for (c = cmdtab; c->name; c++) - if (c->help) { - printf("%-*s\t%s\r\n", HELPINDENT, c->name, - c->help); - } - return 0; - } - while (--argc > 0) { - char *arg; - arg = *++argv; - c = getcmd(arg); - if (Ambiguous(c)) - printf("?Ambiguous help command %s\r\n", arg); - else if (c == (Command *)0) - printf("?Invalid help command %s\r\n", arg); - else - printf("%s\r\n", c->help); - } - return 0; -} - - -#if defined(IP_OPTIONS) && defined(IPPROTO_IP) - -/* - * Source route is handed in as - * [!]@hop1@hop2...@dst - * - * If the leading ! is present, it is a strict source route, otherwise it is - * assmed to be a loose source route. Note that leading ! is effective - * only for IPv4 case. - * - * We fill in the source route option as - * hop1,hop2,hop3...dest - * and return a pointer to hop1, which will - * be the address to connect() to. - * - * Arguments: - * ai: The address (by struct addrinfo) for the final destination. - * - * arg: Pointer to route list to decipher - * - * cpp: Pointer to a pointer, so that sourceroute() can return - * the address of result buffer (statically alloc'ed). - * - * protop/optp: - * Pointer to an integer. The pointed variable - * lenp: pointer to an integer that contains the - * length of *cpp if *cpp != NULL. - * - * Return values: - * - * Returns the length of the option pointed to by *cpp. If the - * return value is -1, there was a syntax error in the - * option, either arg contained unknown characters or too many hosts, - * or hostname cannot be resolved. - * - * The caller needs to pass return value (len), *cpp, *protop and *optp - * to setsockopt(2). - * - * *cpp: Points to the result buffer. The region is statically - * allocated by the function. - * - * *protop: - * protocol # to be passed to setsockopt(2). - * - * *optp: option # to be passed to setsockopt(2). - * - */ -int -sourceroute(struct addrinfo *ai, - char *arg, - char **cpp, - int *protop, - int *optp) -{ - char *cp, *cp2, *lsrp = NULL, *lsrep = NULL; - struct addrinfo hints, *res; - int len, error; - struct sockaddr_in *sin; - register char c; - static char lsr[44]; -#ifdef INET6 - struct cmsghdr *cmsg = NULL; - struct sockaddr_in6 *sin6; - static char rhbuf[1024]; -#endif - - /* - * Verify the arguments. - */ - if (cpp == NULL) - return -1; - - cp = arg; - - *cpp = NULL; - switch (ai->ai_family) { - case AF_INET: - lsrp = lsr; - lsrep = lsrp + sizeof(lsr); - - /* - * Next, decide whether we have a loose source - * route or a strict source route, and fill in - * the begining of the option. - */ - if (*cp == '!') { - cp++; - *lsrp++ = IPOPT_SSRR; - } else - *lsrp++ = IPOPT_LSRR; - if (*cp != '@') - return -1; - lsrp++; /* skip over length, we'll fill it in later */ - *lsrp++ = 4; - cp++; - *protop = IPPROTO_IP; - *optp = IP_OPTIONS; - break; -#ifdef INET6 - case AF_INET6: -/* this needs to be updated for rfc2292bis */ -#ifdef IPV6_PKTOPTIONS - cmsg = inet6_rthdr_init(rhbuf, IPV6_RTHDR_TYPE_0); - if (*cp != '@') - return -1; - cp++; - *protop = IPPROTO_IPV6; - *optp = IPV6_PKTOPTIONS; - break; -#else - return -1; -#endif -#endif - default: - return -1; - } - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = ai->ai_family; - hints.ai_socktype = SOCK_STREAM; - - for (c = 0;;) { - if (c == ':') - cp2 = 0; - else for (cp2 = cp; (c = *cp2) != '\0'; cp2++) { - if (c == ',') { - *cp2++ = '\0'; - if (*cp2 == '@') - cp2++; - } else if (c == '@') { - *cp2++ = '\0'; - } -#if 0 /*colon conflicts with IPv6 address*/ - else if (c == ':') { - *cp2++ = '\0'; - } -#endif - else - continue; - break; - } - if (!c) - cp2 = 0; - - error = getaddrinfo(cp, NULL, &hints, &res); - if (error) { - fprintf(stderr, "%s: %s\n", cp, gai_strerror(error)); - return -1; - } - if (ai->ai_family != res->ai_family) { - freeaddrinfo(res); - return -1; - } - if (ai->ai_family == AF_INET) { - /* - * Check to make sure there is space for address - */ - if (lsrp + 4 > lsrep) { - freeaddrinfo(res); - return -1; - } - sin = (struct sockaddr_in *)res->ai_addr; - memcpy(lsrp, &sin->sin_addr, sizeof(struct in_addr)); - lsrp += sizeof(struct in_addr); - } -#ifdef INET6 - else if (ai->ai_family == AF_INET6) { - sin6 = (struct sockaddr_in6 *)res->ai_addr; - inet6_rthdr_add(cmsg, &sin6->sin6_addr, - IPV6_RTHDR_LOOSE); - } -#endif - else { - freeaddrinfo(res); - return -1; - } - freeaddrinfo(res); - if (cp2) - cp = cp2; - else - break; - } - if (ai->ai_family == AF_INET) { - /* record the last hop */ - if (lsrp + 4 > lsrep) - return -1; - sin = (struct sockaddr_in *)ai->ai_addr; - memcpy(lsrp, &sin->sin_addr, sizeof(struct in_addr)); - lsrp += sizeof(struct in_addr); -#ifndef sysV88 - lsr[IPOPT_OLEN] = lsrp - lsr; - if (lsr[IPOPT_OLEN] <= 7 || lsr[IPOPT_OLEN] > 40) - return -1; - *lsrp++ = IPOPT_NOP; /*32bit word align*/ - len = lsrp - lsr; - *cpp = lsr; -#else - ipopt.io_len = lsrp - lsr; - if (ipopt.io_len <= 5) /*is 3 better?*/ - return -1; - *cpp = (char 8)&ipopt; -#endif - } -#ifdef INET6 - else if (ai->ai_family == AF_INET6) { - inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE); - len = cmsg->cmsg_len; - *cpp = rhbuf; - } -#endif - else - return -1; - return len; -} -#endif diff --git a/appl/telnet/telnet/externs.h b/appl/telnet/telnet/externs.h deleted file mode 100644 index ba55a7bfe..000000000 --- a/appl/telnet/telnet/externs.h +++ /dev/null @@ -1,443 +0,0 @@ -/* - * Copyright (c) 1988, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)externs.h 8.3 (Berkeley) 5/30/95 - */ - -/* $Id$ */ - -#ifndef BSD -# define BSD 43 -#endif - -#ifndef _POSIX_VDISABLE -# ifdef sun -# include /* pick up VDISABLE definition, mayby */ -# endif -# ifdef VDISABLE -# define _POSIX_VDISABLE VDISABLE -# else -# define _POSIX_VDISABLE ((cc_t)'\377') -# endif -#endif - -#define SUBBUFSIZE 256 - -extern int - autologin, /* Autologin enabled */ - skiprc, /* Don't process the ~/.telnetrc file */ - eight, /* use eight bit mode (binary in and/or out */ - binary, - flushout, /* flush output */ - connected, /* Are we connected to the other side? */ - globalmode, /* Mode tty should be in */ - telnetport, /* Are we connected to the telnet port? */ - localflow, /* Flow control handled locally */ - restartany, /* If flow control, restart output on any character */ - localchars, /* we recognize interrupt/quit */ - donelclchars, /* the user has set "localchars" */ - showoptions, - wantencryption, /* User has requested encryption */ - net, /* Network file descriptor */ - tin, /* Terminal input file descriptor */ - tout, /* Terminal output file descriptor */ - crlf, /* Should '\r' be mapped to (or )? */ - autoflush, /* flush output when interrupting? */ - autosynch, /* send interrupt characters with SYNCH? */ - SYNCHing, /* Is the stream in telnet SYNCH mode? */ - donebinarytoggle, /* the user has put us in binary */ - dontlecho, /* do we suppress local echoing right now? */ - crmod, - netdata, /* Print out network data flow */ - prettydump, /* Print "netdata" output in user readable format */ - termdata, /* Print out terminal data flow */ - debug; /* Debug level */ - -extern int intr_happened, intr_waiting; /* for interrupt handling */ - -extern cc_t escape; /* Escape to command mode */ -extern cc_t rlogin; /* Rlogin mode escape character */ -#ifdef KLUDGELINEMODE -extern cc_t echoc; /* Toggle local echoing */ -#endif - -extern char - *prompt; /* Prompt for command. */ - -extern char - doopt[], - dont[], - will[], - wont[], - do_dont_resp[], - will_wont_resp[], - options[], /* All the little options */ - *hostname; /* Who are we connected to? */ -#if defined(ENCRYPTION) -extern void (*encrypt_output) (unsigned char *, int); -extern int (*decrypt_input) (int); -#endif - -/* - * We keep track of each side of the option negotiation. - */ - -#define MY_STATE_WILL 0x01 -#define MY_WANT_STATE_WILL 0x02 -#define MY_STATE_DO 0x04 -#define MY_WANT_STATE_DO 0x08 - -/* - * Macros to check the current state of things - */ - -#define my_state_is_do(opt) (options[opt]&MY_STATE_DO) -#define my_state_is_will(opt) (options[opt]&MY_STATE_WILL) -#define my_want_state_is_do(opt) (options[opt]&MY_WANT_STATE_DO) -#define my_want_state_is_will(opt) (options[opt]&MY_WANT_STATE_WILL) - -#define my_state_is_dont(opt) (!my_state_is_do(opt)) -#define my_state_is_wont(opt) (!my_state_is_will(opt)) -#define my_want_state_is_dont(opt) (!my_want_state_is_do(opt)) -#define my_want_state_is_wont(opt) (!my_want_state_is_will(opt)) - -#define set_my_state_do(opt) {options[opt] |= MY_STATE_DO;} -#define set_my_state_will(opt) {options[opt] |= MY_STATE_WILL;} -#define set_my_want_state_do(opt) {options[opt] |= MY_WANT_STATE_DO;} -#define set_my_want_state_will(opt) {options[opt] |= MY_WANT_STATE_WILL;} - -#define set_my_state_dont(opt) {options[opt] &= ~MY_STATE_DO;} -#define set_my_state_wont(opt) {options[opt] &= ~MY_STATE_WILL;} -#define set_my_want_state_dont(opt) {options[opt] &= ~MY_WANT_STATE_DO;} -#define set_my_want_state_wont(opt) {options[opt] &= ~MY_WANT_STATE_WILL;} - -/* - * Make everything symmetrical - */ - -#define HIS_STATE_WILL MY_STATE_DO -#define HIS_WANT_STATE_WILL MY_WANT_STATE_DO -#define HIS_STATE_DO MY_STATE_WILL -#define HIS_WANT_STATE_DO MY_WANT_STATE_WILL - -#define his_state_is_do my_state_is_will -#define his_state_is_will my_state_is_do -#define his_want_state_is_do my_want_state_is_will -#define his_want_state_is_will my_want_state_is_do - -#define his_state_is_dont my_state_is_wont -#define his_state_is_wont my_state_is_dont -#define his_want_state_is_dont my_want_state_is_wont -#define his_want_state_is_wont my_want_state_is_dont - -#define set_his_state_do set_my_state_will -#define set_his_state_will set_my_state_do -#define set_his_want_state_do set_my_want_state_will -#define set_his_want_state_will set_my_want_state_do - -#define set_his_state_dont set_my_state_wont -#define set_his_state_wont set_my_state_dont -#define set_his_want_state_dont set_my_want_state_wont -#define set_his_want_state_wont set_my_want_state_dont - - -extern FILE - *NetTrace; /* Where debugging output goes */ -extern char - NetTraceFile[]; /* Name of file where debugging output goes */ -extern void - SetNetTrace (char *); /* Function to change where debugging goes */ - -extern jmp_buf - peerdied, - toplevel; /* For error conditions. */ - -int Scheduler(int); -extern int scheduler_lockout_tty; - - -/* authenc.c */ - -#if defined(AUTHENTICATION) || defined(ENCRYPTION) -int telnet_net_write(unsigned char *str, int len); -void net_encrypt(void); -int telnet_spin(void); -char *telnet_getenv(const char *val); -char *telnet_gets(char *prompt, char *result, int length, int echo); -#endif - -/* commands.c */ - -struct env_lst *env_define (unsigned char *, unsigned char *); -struct env_lst *env_find(unsigned char *var); -void env_init (void); -void env_undefine (unsigned char *); -void env_export (unsigned char *); -void env_unexport (unsigned char *); -void env_send (unsigned char *); -void env_list (void); -unsigned char * env_default(int init, int welldefined); -unsigned char * env_getvalue(unsigned char *var); - -void set_escape_char(char *s); -int sourceroute(struct addrinfo *ai, char *arg, char **cpp, - int *prototp, int *optp); - -#if defined(AUTHENTICATION) -int auth_enable (char *); -int auth_disable (char *); -int auth_status (void); -#endif - -#if defined(ENCRYPTION) -int EncryptEnable (char *, char *); -int EncryptDisable (char *, char *); -int EncryptType (char *, char *); -int EncryptStart (char *); -int EncryptStartInput (void); -int EncryptStartOutput (void); -int EncryptStop (char *); -int EncryptStopInput (void); -int EncryptStopOutput (void); -int EncryptStatus (void); -#endif - -#ifdef SIGINFO -RETSIGTYPE ayt_status(int); -#endif -int tn(int argc, char **argv); -void command(int top, char *tbuf, int cnt); - -/* main.c */ - -void tninit(void); -void set_forward_options(void); - -/* network.c */ - -void init_network(void); -int stilloob(void); -void setneturg(void); -int netflush(void); - -/* sys_bsd.c */ - -void init_sys(void); -int TerminalWrite(char *buf, int n); -int TerminalRead(unsigned char *buf, int n); -int TerminalAutoFlush(void); -int TerminalSpecialChars(int c); -void TerminalFlushOutput(void); -void TerminalSaveState(void); -void TerminalDefaultChars(void); -void TerminalNewMode(int f); -cc_t *tcval(int func); -void TerminalSpeeds(long *input_speed, long *output_speed); -int TerminalWindowSize(long *rows, long *cols); -int NetClose(int fd); -void NetNonblockingIO(int fd, int onoff); -int process_rings(int netin, int netout, int netex, int ttyin, int ttyout, - int poll); - -/* telnet.c */ - -void init_telnet(void); - -void tel_leave_binary(int rw); -void tel_enter_binary(int rw); -int opt_welldefined(char *ep); -int telrcv(void); -int rlogin_susp(void); -void intp(void); -void sendbrk(void); -void sendabort(void); -void sendsusp(void); -void sendeof(void); -void sendayt(void); - -void xmitAO(void); -void xmitEL(void); -void xmitEC(void); - - -void Dump (char, unsigned char *, int); -void printoption (char *, int, int); -void sendnaws (void); -void setconnmode (int); -void setcommandmode (void); -void setneturg (void); -void sys_telnet_init (void); -void my_telnet (char *); -void tel_enter_binary (int); -void TerminalFlushOutput (void); -void TerminalNewMode (int); -void TerminalRestoreState (void); -void TerminalSaveState (void); -void willoption (int); -void wontoption (int); - - -void send_do (int, int); -void send_dont (int, int); -void send_will (int, int); -void send_wont (int, int); - -void lm_will (unsigned char *, int); -void lm_wont (unsigned char *, int); -void lm_do (unsigned char *, int); -void lm_dont (unsigned char *, int); -void lm_mode (unsigned char *, int, int); - -void slc_init (void); -void slcstate (void); -void slc_mode_export (void); -void slc_mode_import (int); -void slc_import (int); -void slc_export (void); -void slc (unsigned char *, int); -void slc_check (void); -void slc_start_reply (void); -void slc_add_reply (unsigned char, unsigned char, cc_t); -void slc_end_reply (void); -int slc_update (void); - -void env_opt (unsigned char *, int); -void env_opt_start (void); -void env_opt_start_info (void); -void env_opt_add (unsigned char *); -void env_opt_end (int); - -unsigned char *env_default (int, int); -unsigned char *env_getvalue (unsigned char *); - -int get_status (void); -int dosynch (void); - -cc_t *tcval (int); - -int quit (void); - -/* terminal.c */ - -void init_terminal(void); -int ttyflush(int drop); -int getconnmode(void); - -/* utilities.c */ - -int SetSockOpt(int fd, int level, int option, int yesno); -void SetNetTrace(char *file); -void Dump(char direction, unsigned char *buffer, int length); -void printoption(char *direction, int cmd, int option); -void optionstatus(void); -void printsub(int direction, unsigned char *pointer, size_t length); -void EmptyTerminal(void); -void SetForExit(void); -void Exit(int returnCode); -void ExitString(char *string, int returnCode); - -extern struct termios new_tc; - -# define termEofChar new_tc.c_cc[VEOF] -# define termEraseChar new_tc.c_cc[VERASE] -# define termIntChar new_tc.c_cc[VINTR] -# define termKillChar new_tc.c_cc[VKILL] -# define termQuitChar new_tc.c_cc[VQUIT] - -# ifndef VSUSP -extern cc_t termSuspChar; -# else -# define termSuspChar new_tc.c_cc[VSUSP] -# endif -# if defined(VFLUSHO) && !defined(VDISCARD) -# define VDISCARD VFLUSHO -# endif -# ifndef VDISCARD -extern cc_t termFlushChar; -# else -# define termFlushChar new_tc.c_cc[VDISCARD] -# endif -# ifndef VWERASE -extern cc_t termWerasChar; -# else -# define termWerasChar new_tc.c_cc[VWERASE] -# endif -# ifndef VREPRINT -extern cc_t termRprntChar; -# else -# define termRprntChar new_tc.c_cc[VREPRINT] -# endif -# ifndef VLNEXT -extern cc_t termLiteralNextChar; -# else -# define termLiteralNextChar new_tc.c_cc[VLNEXT] -# endif -# ifndef VSTART -extern cc_t termStartChar; -# else -# define termStartChar new_tc.c_cc[VSTART] -# endif -# ifndef VSTOP -extern cc_t termStopChar; -# else -# define termStopChar new_tc.c_cc[VSTOP] -# endif -# ifndef VEOL -extern cc_t termForw1Char; -# else -# define termForw1Char new_tc.c_cc[VEOL] -# endif -# ifndef VEOL2 -extern cc_t termForw2Char; -# else -# define termForw2Char new_tc.c_cc[VEOL] -# endif -# ifndef VSTATUS -extern cc_t termAytChar; -#else -# define termAytChar new_tc.c_cc[VSTATUS] -#endif - -/* Ring buffer structures which are shared */ - -extern Ring - netoring, - netiring, - ttyoring, - ttyiring; - -extern int resettermname; -extern int linemode; -#ifdef KLUDGELINEMODE -extern int kludgelinemode; -#endif -extern int want_status_response; diff --git a/appl/telnet/telnet/main.c b/appl/telnet/telnet/main.c deleted file mode 100644 index 6a5e892c4..000000000 --- a/appl/telnet/telnet/main.c +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright (c) 1988, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -static char *copyright[] = { - "@(#) Copyright (c) 1988, 1990, 1993\n" - "\tThe Regents of the University of California. All rights reserved.\n", - (char*)copyright -}; - -#include "telnet_locl.h" -RCSID("$Id$"); - -#if KRB5 -#define FORWARD -#endif - -/* - * Initialize variables. - */ -void -tninit(void) -{ - init_terminal(); - - init_network(); - - init_telnet(); - - init_sys(); -} - -static void -usage(int exit_code) -{ - fprintf(stderr, "Usage: %s %s%s%s%s\n", prompt, -#ifdef AUTHENTICATION - "[-8] [-E] [-K] [-L] [-G] [-S tos] [-X atype] [-a] [-c] [-d] [-e char]", - "\n\t[-k realm] [-l user] [-f/-F] [-n tracefile] ", -#else - "[-8] [-E] [-L] [-S tos] [-a] [-c] [-d] [-e char] [-l user]", - "\n\t[-n tracefile]", -#endif - "[-r] ", -#ifdef ENCRYPTION - "[-x] [host-name [port]]" -#else - "[host-name [port]]" -#endif - ); - exit(exit_code); -} - -/* - * main. Parse arguments, invoke the protocol or command parser. - */ - - -#ifdef FORWARD -int forward_option = 0; /* forward flags set from command line */ -#endif /* FORWARD */ -void -set_forward_options(void) -{ -#ifdef FORWARD - switch(forward_option) { - case 'f': - kerberos5_set_forward(1); - kerberos5_set_forwardable(0); - break; - case 'F': - kerberos5_set_forward(1); - kerberos5_set_forwardable(1); - break; - case 'G': - kerberos5_set_forward(0); - kerberos5_set_forwardable(0); - break; - default: - break; - } -#endif -} - -#ifdef KRB5 -#define Authenticator asn1_Authenticator -#include -static void -krb5_init(void) -{ - krb5_context context; - krb5_error_code ret; - krb5_boolean ret_val; - - ret = krb5_init_context(&context); - if (ret) - return; - -#if defined(AUTHENTICATION) && defined(FORWARD) - krb5_appdefault_boolean(context, NULL, - NULL, "forward", - 0, &ret_val); - if (ret_val) - kerberos5_set_forward(1); - krb5_appdefault_boolean(context, NULL, - NULL, "forwardable", - 0, &ret_val); - if (ret_val) - kerberos5_set_forwardable(1); -#endif -#ifdef ENCRYPTION - krb5_appdefault_boolean(context, NULL, - NULL, "encrypt", - 0, &ret_val); - if (ret_val) { - encrypt_auto(1); - decrypt_auto(1); - wantencryption = 1; - EncryptVerbose(1); - } -#endif - - krb5_free_context(context); -} -#endif - -int -main(int argc, char **argv) -{ - int ch; - char *user; - - setprogname(argv[0]); - -#ifdef KRB5 - krb5_init(); -#endif - - tninit(); /* Clear out things */ - - TerminalSaveState(); - - if ((prompt = strrchr(argv[0], '/'))) - ++prompt; - else - prompt = argv[0]; - - user = NULL; - - rlogin = (strncmp(prompt, "rlog", 4) == 0) ? '~' : _POSIX_VDISABLE; - - /* - * if AUTHENTICATION and ENCRYPTION is set autologin will be - * se to true after the getopt switch; unless the -K option is - * passed - */ - autologin = -1; - - if (argc == 2 && strcmp(argv[1], "--version") == 0) { - print_version(NULL); - exit(0); - } - if (argc == 2 && strcmp(argv[1], "--help") == 0) - usage(0); - - - while((ch = getopt(argc, argv, - "78DEKLS:X:abcde:fFk:l:n:rxG")) != -1) { - switch(ch) { - case '8': - eight = 3; /* binary output and input */ - break; - case '7': - eight = 0; - break; - case 'b': - binary = 3; - break; - case 'D': { - /* sometimes we don't want a mangled display */ - char *p; - if((p = getenv("DISPLAY"))) - env_define((unsigned char*)"DISPLAY", (unsigned char*)p); - break; - } - case 'E': - rlogin = escape = _POSIX_VDISABLE; - break; - case 'K': -#ifdef AUTHENTICATION - autologin = 0; -#endif - break; - case 'L': - eight |= 2; /* binary output only */ - break; - case 'S': - { -#ifdef HAVE_PARSETOS - extern int tos; - - if ((tos = parsetos(optarg, "tcp")) < 0) - fprintf(stderr, "%s%s%s%s\n", - prompt, ": Bad TOS argument '", - optarg, - "; will try to use default TOS"); -#else - fprintf(stderr, - "%s: Warning: -S ignored, no parsetos() support.\n", - prompt); -#endif - } - break; - case 'X': -#ifdef AUTHENTICATION - auth_disable_name(optarg); -#endif - break; - case 'a': - autologin = 1; - break; - case 'c': - skiprc = 1; - break; - case 'd': - debug = 1; - break; - case 'e': - set_escape_char(optarg); - break; - case 'f': - case 'F': - case 'G': -#if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD) - if (forward_option) { - fprintf(stderr, - "%s: Only one of -f, -F and -G allowed.\n", - prompt); - usage(1); - } - forward_option = ch; -#else - fprintf(stderr, - "%s: Warning: -%c ignored, no Kerberos V5 support.\n", - prompt, ch); -#endif - break; - case 'k': - fprintf(stderr, - "%s: Warning: -k ignored, no Kerberos V4 support.\n", - prompt); - break; - case 'l': - if(autologin == 0){ - fprintf(stderr, "%s: Warning: -K ignored\n", prompt); - autologin = -1; - } - user = optarg; - break; - case 'n': - SetNetTrace(optarg); - break; - case 'r': - rlogin = '~'; - break; - case 'x': -#ifdef ENCRYPTION - encrypt_auto(1); - decrypt_auto(1); - wantencryption = 1; - EncryptVerbose(1); -#else - fprintf(stderr, - "%s: Warning: -x ignored, no ENCRYPT support.\n", - prompt); -#endif - break; - - case '?': - default: - usage(1); - /* NOTREACHED */ - } - } - - if (autologin == -1) { /* esc@magic.fi; force */ -#if defined(AUTHENTICATION) - autologin = 1; -#endif -#if defined(ENCRYPTION) - encrypt_auto(1); - decrypt_auto(1); - wantencryption = -1; -#endif - } - - if (autologin == -1) - autologin = (rlogin == _POSIX_VDISABLE) ? 0 : 1; - - argc -= optind; - argv += optind; - - if (argc) { - char *args[7], **argp = args; - - if (argc > 2) - usage(1); - *argp++ = prompt; - if (user) { - *argp++ = "-l"; - *argp++ = user; - } - *argp++ = argv[0]; /* host */ - if (argc > 1) - *argp++ = argv[1]; /* port */ - *argp = 0; - - if (setjmp(toplevel) != 0) - Exit(0); - if (tn(argp - args, args) == 1) - return (0); - else - return (1); - } - setjmp(toplevel); - for (;;) { - command(1, 0, 0); - } -} diff --git a/appl/telnet/telnet/network.c b/appl/telnet/telnet/network.c deleted file mode 100644 index a22ff9b48..000000000 --- a/appl/telnet/telnet/network.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "telnet_locl.h" - -RCSID("$Id$"); - -Ring netoring, netiring; -size_t netobufsize = 64*1024; -size_t netibufsize = 64*1024; - -/* - * Initialize internal network data structures. - */ - -void -init_network(void) -{ - void *obuf, *ibuf; - - if ((obuf = malloc(netobufsize)) == NULL) - exit(1); - if ((ibuf = malloc(netibufsize)) == NULL) - exit(1); - - if (ring_init(&netoring, obuf, netobufsize) != 1) { - exit(1); - } - if (ring_init(&netiring, ibuf, netibufsize) != 1) { - exit(1); - } - NetTrace = stdout; -} - - -/* - * Check to see if any out-of-band data exists on a socket (for - * Telnet "synch" processing). - */ - -int -stilloob(void) -{ - static struct timeval timeout = { 0 }; - fd_set excepts; - int value; - - do { - FD_ZERO(&excepts); - if (net >= FD_SETSIZE) - errx (1, "fd too large"); - FD_SET(net, &excepts); - value = select(net+1, 0, 0, &excepts, &timeout); - } while ((value == -1) && (errno == EINTR)); - - if (value < 0) { - perror("select"); - quit(); - /* NOTREACHED */ - } - if (FD_ISSET(net, &excepts)) { - return 1; - } else { - return 0; - } -} - - -/* - * setneturg() - * - * Sets "neturg" to the current location. - */ - -void -setneturg(void) -{ - ring_mark(&netoring); -} - - -/* - * netflush - * Send as much data as possible to the network, - * handling requests for urgent data. - * - * The return value indicates whether we did any - * useful work. - */ - - -int -netflush(void) -{ - int n, n1; - -#if defined(ENCRYPTION) - if (encrypt_output) - ring_encrypt(&netoring, encrypt_output); -#endif - if ((n1 = n = ring_full_consecutive(&netoring)) > 0) { - if (!ring_at_mark(&netoring)) { - n = send(net, (char *)netoring.consume, n, 0); /* normal write */ - } else { - /* - * In 4.2 (and 4.3) systems, there is some question about - * what byte in a sendOOB operation is the "OOB" data. - * To make ourselves compatible, we only send ONE byte - * out of band, the one WE THINK should be OOB (though - * we really have more the TCP philosophy of urgent data - * rather than the Unix philosophy of OOB data). - */ - n = send(net, (char *)netoring.consume, 1, MSG_OOB);/* URGENT data */ - } - } - if (n < 0) { - if (errno != ENOBUFS && errno != EWOULDBLOCK) { - setcommandmode(); - perror(hostname); - NetClose(net); - ring_clear_mark(&netoring); - longjmp(peerdied, -1); - /*NOTREACHED*/ - } - n = 0; - } - if (netdata && n) { - Dump('>', netoring.consume, n); - } - if (n) { - ring_consumed(&netoring, n); - /* - * If we sent all, and more to send, then recurse to pick - * up the other half. - */ - if ((n1 == n) && ring_full_consecutive(&netoring)) { - netflush(); - } - return 1; - } else { - return 0; - } -} diff --git a/appl/telnet/telnet/ring.c b/appl/telnet/telnet/ring.c deleted file mode 100644 index f4aee9ed7..000000000 --- a/appl/telnet/telnet/ring.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "telnet_locl.h" - -RCSID("$Id$"); - -/* - * This defines a structure for a ring buffer. - * - * The circular buffer has two parts: - *((( - * full: [consume, supply) - * empty: [supply, consume) - *]]] - * - */ - -/* Internal macros */ - -#define ring_subtract(d,a,b) (((a)-(b) >= 0)? \ - (a)-(b): (((a)-(b))+(d)->size)) - -#define ring_increment(d,a,c) (((a)+(c) < (d)->top)? \ - (a)+(c) : (((a)+(c))-(d)->size)) - -#define ring_decrement(d,a,c) (((a)-(c) >= (d)->bottom)? \ - (a)-(c) : (((a)-(c))-(d)->size)) - - -/* - * The following is a clock, used to determine full, empty, etc. - * - * There is some trickiness here. Since the ring buffers are initialized - * to ZERO on allocation, we need to make sure, when interpreting the - * clock, that when the times are EQUAL, then the buffer is FULL. - */ -static u_long ring_clock = 0; - - -#define ring_empty(d) (((d)->consume == (d)->supply) && \ - ((d)->consumetime >= (d)->supplytime)) -#define ring_full(d) (((d)->supply == (d)->consume) && \ - ((d)->supplytime > (d)->consumetime)) - - - - - -/* Buffer state transition routines */ - -int -ring_init(Ring *ring, unsigned char *buffer, int count) -{ - memset(ring, 0, sizeof *ring); - - ring->size = count; - - ring->supply = ring->consume = ring->bottom = buffer; - - ring->top = ring->bottom+ring->size; - -#if defined(ENCRYPTION) - ring->clearto = 0; -#endif - - return 1; -} - -/* Mark routines */ - -/* - * Mark the most recently supplied byte. - */ - -void -ring_mark(Ring *ring) -{ - ring->mark = ring_decrement(ring, ring->supply, 1); -} - -/* - * Is the ring pointing to the mark? - */ - -int -ring_at_mark(Ring *ring) -{ - if (ring->mark == ring->consume) { - return 1; - } else { - return 0; - } -} - -/* - * Clear any mark set on the ring. - */ - -void -ring_clear_mark(Ring *ring) -{ - ring->mark = 0; -} - -/* - * Add characters from current segment to ring buffer. - */ -void -ring_supplied(Ring *ring, int count) -{ - ring->supply = ring_increment(ring, ring->supply, count); - ring->supplytime = ++ring_clock; -} - -/* - * We have just consumed "c" bytes. - */ -void -ring_consumed(Ring *ring, int count) -{ - if (count == 0) /* don't update anything */ - return; - - if (ring->mark && - (ring_subtract(ring, ring->mark, ring->consume) < count)) { - ring->mark = 0; - } -#if defined(ENCRYPTION) - if (ring->consume < ring->clearto && - ring->clearto <= ring->consume + count) - ring->clearto = 0; - else if (ring->consume + count > ring->top && - ring->bottom <= ring->clearto && - ring->bottom + ((ring->consume + count) - ring->top)) - ring->clearto = 0; -#endif - ring->consume = ring_increment(ring, ring->consume, count); - ring->consumetime = ++ring_clock; - /* - * Try to encourage "ring_empty_consecutive()" to be large. - */ - if (ring_empty(ring)) { - ring->consume = ring->supply = ring->bottom; - } -} - - - -/* Buffer state query routines */ - - -/* Number of bytes that may be supplied */ -int -ring_empty_count(Ring *ring) -{ - if (ring_empty(ring)) { /* if empty */ - return ring->size; - } else { - return ring_subtract(ring, ring->consume, ring->supply); - } -} - -/* number of CONSECUTIVE bytes that may be supplied */ -int -ring_empty_consecutive(Ring *ring) -{ - if ((ring->consume < ring->supply) || ring_empty(ring)) { - /* - * if consume is "below" supply, or empty, then - * return distance to the top - */ - return ring_subtract(ring, ring->top, ring->supply); - } else { - /* - * else, return what we may. - */ - return ring_subtract(ring, ring->consume, ring->supply); - } -} - -/* Return the number of bytes that are available for consuming - * (but don't give more than enough to get to cross over set mark) - */ - -int -ring_full_count(Ring *ring) -{ - if ((ring->mark == 0) || (ring->mark == ring->consume)) { - if (ring_full(ring)) { - return ring->size; /* nothing consumed, but full */ - } else { - return ring_subtract(ring, ring->supply, ring->consume); - } - } else { - return ring_subtract(ring, ring->mark, ring->consume); - } -} - -/* - * Return the number of CONSECUTIVE bytes available for consuming. - * However, don't return more than enough to cross over set mark. - */ -int -ring_full_consecutive(Ring *ring) -{ - if ((ring->mark == 0) || (ring->mark == ring->consume)) { - if ((ring->supply < ring->consume) || ring_full(ring)) { - return ring_subtract(ring, ring->top, ring->consume); - } else { - return ring_subtract(ring, ring->supply, ring->consume); - } - } else { - if (ring->mark < ring->consume) { - return ring_subtract(ring, ring->top, ring->consume); - } else { /* Else, distance to mark */ - return ring_subtract(ring, ring->mark, ring->consume); - } - } -} - -/* - * Move data into the "supply" portion of of the ring buffer. - */ -void -ring_supply_data(Ring *ring, unsigned char *buffer, int count) -{ - int i; - - while (count) { - i = min(count, ring_empty_consecutive(ring)); - memmove(ring->supply, buffer, i); - ring_supplied(ring, i); - count -= i; - buffer += i; - } -} - -#ifdef notdef - -/* - * Move data from the "consume" portion of the ring buffer - */ -void -ring_consume_data(Ring *ring, unsigned char *buffer, int count) -{ - int i; - - while (count) { - i = min(count, ring_full_consecutive(ring)); - memmove(buffer, ring->consume, i); - ring_consumed(ring, i); - count -= i; - buffer += i; - } -} -#endif - -#if defined(ENCRYPTION) -void -ring_encrypt(Ring *ring, void (*encryptor)(unsigned char *, int)) -{ - unsigned char *s, *c; - - if (ring_empty(ring) || ring->clearto == ring->supply) - return; - - if (!(c = ring->clearto)) - c = ring->consume; - - s = ring->supply; - - if (s <= c) { - (*encryptor)(c, ring->top - c); - (*encryptor)(ring->bottom, s - ring->bottom); - } else - (*encryptor)(c, s - c); - - ring->clearto = ring->supply; -} - -void -ring_clearto(Ring *ring) -{ - if (!ring_empty(ring)) - ring->clearto = ring->supply; - else - ring->clearto = 0; -} -#endif - diff --git a/appl/telnet/telnet/ring.h b/appl/telnet/telnet/ring.h deleted file mode 100644 index 04e3eaebd..000000000 --- a/appl/telnet/telnet/ring.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)ring.h 8.1 (Berkeley) 6/6/93 - */ - -/* $Id$ */ - -/* - * This defines a structure for a ring buffer. - * - * The circular buffer has two parts: - *((( - * full: [consume, supply) - * empty: [supply, consume) - *]]] - * - */ -typedef struct { - unsigned char *consume, /* where data comes out of */ - *supply, /* where data comes in to */ - *bottom, /* lowest address in buffer */ - *top, /* highest address+1 in buffer */ - *mark; /* marker (user defined) */ -#if defined(ENCRYPTION) - unsigned char *clearto; /* Data to this point is clear text */ - unsigned char *encryyptedto; /* Data is encrypted to here */ -#endif - int size; /* size in bytes of buffer */ - u_long consumetime, /* help us keep straight full, empty, etc. */ - supplytime; -} Ring; - -/* Here are some functions and macros to deal with the ring buffer */ - -/* Initialization routine */ -extern int - ring_init (Ring *ring, unsigned char *buffer, int count); - -/* Data movement routines */ -extern void - ring_supply_data (Ring *ring, unsigned char *buffer, int count); -#ifdef notdef -extern void - ring_consume_data (Ring *ring, unsigned char *buffer, int count); -#endif - -/* Buffer state transition routines */ -extern void - ring_supplied (Ring *ring, int count), - ring_consumed (Ring *ring, int count); - -/* Buffer state query routines */ -extern int - ring_empty_count (Ring *ring), - ring_empty_consecutive (Ring *ring), - ring_full_count (Ring *ring), - ring_full_consecutive (Ring *ring); - -#if defined(ENCRYPTION) -extern void - ring_encrypt (Ring *ring, void (*func)(unsigned char *, int)), - ring_clearto (Ring *ring); -#endif - -extern int ring_at_mark(Ring *ring); - -extern void - ring_clear_mark(Ring *ring), - ring_mark(Ring *ring); diff --git a/appl/telnet/telnet/sys_bsd.c b/appl/telnet/telnet/sys_bsd.c deleted file mode 100644 index 52e74e7af..000000000 --- a/appl/telnet/telnet/sys_bsd.c +++ /dev/null @@ -1,979 +0,0 @@ -/* - * Copyright (c) 1988, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "telnet_locl.h" - -RCSID("$Id$"); - -/* - * The following routines try to encapsulate what is system dependent - * (at least between 4.x and dos) which is used in telnet.c. - */ - -int - tout, /* Output file descriptor */ - tin, /* Input file descriptor */ - net; - -struct termios old_tc = { 0 }; -extern struct termios new_tc; - -# ifndef TCSANOW -# ifdef TCSETS -# define TCSANOW TCSETS -# define TCSADRAIN TCSETSW -# define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t) -# else -# ifdef TCSETA -# define TCSANOW TCSETA -# define TCSADRAIN TCSETAW -# define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t) -# else -# define TCSANOW TIOCSETA -# define TCSADRAIN TIOCSETAW -# define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t) -# endif -# endif -# define tcsetattr(f, a, t) ioctl(f, a, (char *)t) -# define cfgetospeed(ptr) ((ptr)->c_cflag&CBAUD) -# ifdef CIBAUD -# define cfgetispeed(ptr) (((ptr)->c_cflag&CIBAUD) >> IBSHIFT) -# else -# define cfgetispeed(ptr) cfgetospeed(ptr) -# endif -# endif /* TCSANOW */ - -static fd_set ibits, obits, xbits; - - -void -init_sys(void) -{ - tout = fileno(stdout); - tin = fileno(stdin); - FD_ZERO(&ibits); - FD_ZERO(&obits); - FD_ZERO(&xbits); - - errno = 0; -} - - -int -TerminalWrite(char *buf, int n) -{ - return write(tout, buf, n); -} - -int -TerminalRead(unsigned char *buf, int n) -{ - return read(tin, buf, n); -} - -/* - * - */ - -int -TerminalAutoFlush(void) -{ -#if defined(LNOFLSH) - int flush; - - ioctl(0, TIOCLGET, (char *)&flush); - return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */ -#else /* LNOFLSH */ - return 1; -#endif /* LNOFLSH */ -} - -/* - * TerminalSpecialChars() - * - * Look at an input character to see if it is a special character - * and decide what to do. - * - * Output: - * - * 0 Don't add this character. - * 1 Do add this character - */ - -int -TerminalSpecialChars(int c) -{ - if (c == termIntChar) { - intp(); - return 0; - } else if (c == termQuitChar) { -#ifdef KLUDGELINEMODE - if (kludgelinemode) - sendbrk(); - else -#endif - sendabort(); - return 0; - } else if (c == termEofChar) { - if (my_want_state_is_will(TELOPT_LINEMODE)) { - sendeof(); - return 0; - } - return 1; - } else if (c == termSuspChar) { - sendsusp(); - return(0); - } else if (c == termFlushChar) { - xmitAO(); /* Transmit Abort Output */ - return 0; - } else if (!MODE_LOCAL_CHARS(globalmode)) { - if (c == termKillChar) { - xmitEL(); - return 0; - } else if (c == termEraseChar) { - xmitEC(); /* Transmit Erase Character */ - return 0; - } - } - return 1; -} - - -/* - * Flush output to the terminal - */ - -void -TerminalFlushOutput(void) -{ -#ifdef TIOCFLUSH - ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); -#else - ioctl(fileno(stdout), TCFLSH, (char *) 0); -#endif -} - -void -TerminalSaveState(void) -{ - tcgetattr(0, &old_tc); - - new_tc = old_tc; - -#ifndef VDISCARD - termFlushChar = CONTROL('O'); -#endif -#ifndef VWERASE - termWerasChar = CONTROL('W'); -#endif -#ifndef VREPRINT - termRprntChar = CONTROL('R'); -#endif -#ifndef VLNEXT - termLiteralNextChar = CONTROL('V'); -#endif -#ifndef VSTART - termStartChar = CONTROL('Q'); -#endif -#ifndef VSTOP - termStopChar = CONTROL('S'); -#endif -#ifndef VSTATUS - termAytChar = CONTROL('T'); -#endif -} - -cc_t* -tcval(int func) -{ - switch(func) { - case SLC_IP: return(&termIntChar); - case SLC_ABORT: return(&termQuitChar); - case SLC_EOF: return(&termEofChar); - case SLC_EC: return(&termEraseChar); - case SLC_EL: return(&termKillChar); - case SLC_XON: return(&termStartChar); - case SLC_XOFF: return(&termStopChar); - case SLC_FORW1: return(&termForw1Char); - case SLC_FORW2: return(&termForw2Char); -# ifdef VDISCARD - case SLC_AO: return(&termFlushChar); -# endif -# ifdef VSUSP - case SLC_SUSP: return(&termSuspChar); -# endif -# ifdef VWERASE - case SLC_EW: return(&termWerasChar); -# endif -# ifdef VREPRINT - case SLC_RP: return(&termRprntChar); -# endif -# ifdef VLNEXT - case SLC_LNEXT: return(&termLiteralNextChar); -# endif -# ifdef VSTATUS - case SLC_AYT: return(&termAytChar); -# endif - - case SLC_SYNCH: - case SLC_BRK: - case SLC_EOR: - default: - return((cc_t *)0); - } -} - -void -TerminalDefaultChars(void) -{ - memmove(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc)); -# ifndef VDISCARD - termFlushChar = CONTROL('O'); -# endif -# ifndef VWERASE - termWerasChar = CONTROL('W'); -# endif -# ifndef VREPRINT - termRprntChar = CONTROL('R'); -# endif -# ifndef VLNEXT - termLiteralNextChar = CONTROL('V'); -# endif -# ifndef VSTART - termStartChar = CONTROL('Q'); -# endif -# ifndef VSTOP - termStopChar = CONTROL('S'); -# endif -# ifndef VSTATUS - termAytChar = CONTROL('T'); -# endif -} - -#ifdef notdef -void -TerminalRestoreState() -{ -} -#endif - -/* - * TerminalNewMode - set up terminal to a specific mode. - * MODE_ECHO: do local terminal echo - * MODE_FLOW: do local flow control - * MODE_TRAPSIG: do local mapping to TELNET IAC sequences - * MODE_EDIT: do local line editing - * - * Command mode: - * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG - * local echo - * local editing - * local xon/xoff - * local signal mapping - * - * Linemode: - * local/no editing - * Both Linemode and Single Character mode: - * local/remote echo - * local/no xon/xoff - * local/no signal mapping - */ - - -#ifdef SIGTSTP -static RETSIGTYPE susp(int); -#endif /* SIGTSTP */ -#ifdef SIGINFO -static RETSIGTYPE ayt(int); -#endif - -void -TerminalNewMode(int f) -{ - static int prevmode = 0; - struct termios tmp_tc; - int onoff; - int old; - cc_t esc; - - globalmode = f&~MODE_FORCE; - if (prevmode == f) - return; - - /* - * Write any outstanding data before switching modes - * ttyflush() returns 0 only when there is no more data - * left to write out, it returns -1 if it couldn't do - * anything at all, otherwise it returns 1 + the number - * of characters left to write. - */ - old = ttyflush(SYNCHing|flushout); - if (old < 0 || old > 1) { - tcgetattr(tin, &tmp_tc); - do { - /* - * Wait for data to drain, then flush again. - */ - tcsetattr(tin, TCSADRAIN, &tmp_tc); - old = ttyflush(SYNCHing|flushout); - } while (old < 0 || old > 1); - } - - old = prevmode; - prevmode = f&~MODE_FORCE; - tmp_tc = new_tc; - - if (f&MODE_ECHO) { - tmp_tc.c_lflag |= ECHO; - tmp_tc.c_oflag |= ONLCR; - if (crlf) - tmp_tc.c_iflag |= ICRNL; - } else { - tmp_tc.c_lflag &= ~ECHO; - tmp_tc.c_oflag &= ~ONLCR; -# ifdef notdef - if (crlf) - tmp_tc.c_iflag &= ~ICRNL; -# endif - } - - if ((f&MODE_FLOW) == 0) { - tmp_tc.c_iflag &= ~(IXOFF|IXON); /* Leave the IXANY bit alone */ - } else { - if (restartany < 0) { - tmp_tc.c_iflag |= IXOFF|IXON; /* Leave the IXANY bit alone */ - } else if (restartany > 0) { - tmp_tc.c_iflag |= IXOFF|IXON|IXANY; - } else { - tmp_tc.c_iflag |= IXOFF|IXON; - tmp_tc.c_iflag &= ~IXANY; - } - } - - if ((f&MODE_TRAPSIG) == 0) { - tmp_tc.c_lflag &= ~ISIG; - localchars = 0; - } else { - tmp_tc.c_lflag |= ISIG; - localchars = 1; - } - - if (f&MODE_EDIT) { - tmp_tc.c_lflag |= ICANON; - } else { - tmp_tc.c_lflag &= ~ICANON; - tmp_tc.c_iflag &= ~ICRNL; - tmp_tc.c_cc[VMIN] = 1; - tmp_tc.c_cc[VTIME] = 0; - } - - if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) { -# ifdef VLNEXT - tmp_tc.c_cc[VLNEXT] = (cc_t)(_POSIX_VDISABLE); -# endif - } - - if (f&MODE_SOFT_TAB) { -# ifdef OXTABS - tmp_tc.c_oflag |= OXTABS; -# endif -# ifdef TABDLY - tmp_tc.c_oflag &= ~TABDLY; - tmp_tc.c_oflag |= TAB3; -# endif - } else { -# ifdef OXTABS - tmp_tc.c_oflag &= ~OXTABS; -# endif -# ifdef TABDLY - tmp_tc.c_oflag &= ~TABDLY; -# endif - } - - if (f&MODE_LIT_ECHO) { -# ifdef ECHOCTL - tmp_tc.c_lflag &= ~ECHOCTL; -# endif - } else { -# ifdef ECHOCTL - tmp_tc.c_lflag |= ECHOCTL; -# endif - } - - if (f == -1) { - onoff = 0; - } else { - if (f & MODE_INBIN) - tmp_tc.c_iflag &= ~ISTRIP; - else - tmp_tc.c_iflag |= ISTRIP; - if ((f & MODE_OUTBIN) || (f & MODE_OUT8)) { - tmp_tc.c_cflag &= ~(CSIZE|PARENB); - tmp_tc.c_cflag |= CS8; - if(f & MODE_OUTBIN) - tmp_tc.c_oflag &= ~OPOST; - else - tmp_tc.c_oflag |= OPOST; - } else { - tmp_tc.c_cflag &= ~(CSIZE|PARENB); - tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB); - tmp_tc.c_oflag |= OPOST; - } - onoff = 1; - } - - if (f != -1) { - -#ifdef SIGTSTP - signal(SIGTSTP, susp); -#endif /* SIGTSTP */ -#ifdef SIGINFO - signal(SIGINFO, ayt); -#endif -#ifdef NOKERNINFO - tmp_tc.c_lflag |= NOKERNINFO; -#endif - /* - * We don't want to process ^Y here. It's just another - * character that we'll pass on to the back end. It has - * to process it because it will be processed when the - * user attempts to read it, not when we send it. - */ -# ifdef VDSUSP - tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE); -# endif - /* - * If the VEOL character is already set, then use VEOL2, - * otherwise use VEOL. - */ - esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape; - if ((tmp_tc.c_cc[VEOL] != esc) -# ifdef VEOL2 - && (tmp_tc.c_cc[VEOL2] != esc) -# endif - ) { - if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE)) - tmp_tc.c_cc[VEOL] = esc; -# ifdef VEOL2 - else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE)) - tmp_tc.c_cc[VEOL2] = esc; -# endif - } - } else { - sigset_t sm; - -#ifdef SIGINFO - signal(SIGINFO, ayt_status); -#endif -#ifdef SIGTSTP - signal(SIGTSTP, SIG_DFL); - sigemptyset(&sm); - sigaddset(&sm, SIGTSTP); - sigprocmask(SIG_UNBLOCK, &sm, NULL); -#endif /* SIGTSTP */ - tmp_tc = old_tc; - } - if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0) - tcsetattr(tin, TCSANOW, &tmp_tc); - - ioctl(tin, FIONBIO, (char *)&onoff); - ioctl(tout, FIONBIO, (char *)&onoff); - -} - -/* - * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD). - */ -#if B4800 != 4800 -#define DECODE_BAUD -#endif - -#ifdef DECODE_BAUD -#ifndef B7200 -#define B7200 B4800 -#endif - -#ifndef B14400 -#define B14400 B9600 -#endif - -#ifndef B19200 -# define B19200 B14400 -#endif - -#ifndef B28800 -#define B28800 B19200 -#endif - -#ifndef B38400 -# define B38400 B28800 -#endif - -#ifndef B57600 -#define B57600 B38400 -#endif - -#ifndef B76800 -#define B76800 B57600 -#endif - -#ifndef B115200 -#define B115200 B76800 -#endif - -#ifndef B230400 -#define B230400 B115200 -#endif - - -/* - * This code assumes that the values B0, B50, B75... - * are in ascending order. They do not have to be - * contiguous. - */ -struct termspeeds { - long speed; - long value; -} termspeeds[] = { - { 0, B0 }, { 50, B50 }, { 75, B75 }, - { 110, B110 }, { 134, B134 }, { 150, B150 }, - { 200, B200 }, { 300, B300 }, { 600, B600 }, - { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, - { 4800, B4800 }, { 7200, B7200 }, { 9600, B9600 }, - { 14400, B14400 }, { 19200, B19200 }, { 28800, B28800 }, - { 38400, B38400 }, { 57600, B57600 }, { 115200, B115200 }, - { 230400, B230400 }, { -1, B230400 } -}; -#endif /* DECODE_BAUD */ - -void -TerminalSpeeds(long *input_speed, long *output_speed) -{ -#ifdef DECODE_BAUD - struct termspeeds *tp; -#endif /* DECODE_BAUD */ - long in, out; - - out = cfgetospeed(&old_tc); - in = cfgetispeed(&old_tc); - if (in == 0) - in = out; - -#ifdef DECODE_BAUD - tp = termspeeds; - while ((tp->speed != -1) && (tp->value < in)) - tp++; - *input_speed = tp->speed; - - tp = termspeeds; - while ((tp->speed != -1) && (tp->value < out)) - tp++; - *output_speed = tp->speed; -#else /* DECODE_BAUD */ - *input_speed = in; - *output_speed = out; -#endif /* DECODE_BAUD */ -} - -int -TerminalWindowSize(long *rows, long *cols) -{ - struct winsize ws; - - if (get_window_size (STDIN_FILENO, &ws) == 0) { - *rows = ws.ws_row; - *cols = ws.ws_col; - return 1; - } else - return 0; -} - -int -NetClose(int fd) -{ - return close(fd); -} - - -void -NetNonblockingIO(int fd, int onoff) -{ - ioctl(fd, FIONBIO, (char *)&onoff); -} - - -/* - * Various signal handling routines. - */ - -static RETSIGTYPE deadpeer(int), - intr(int), intr2(int), susp(int), sendwin(int); -#ifdef SIGINFO -static RETSIGTYPE ayt(int); -#endif - - - /* ARGSUSED */ -static RETSIGTYPE -deadpeer(int sig) -{ - setcommandmode(); - longjmp(peerdied, -1); -} - -int intr_happened = 0; -int intr_waiting = 0; - - /* ARGSUSED */ -static RETSIGTYPE -intr(int sig) -{ - if (intr_waiting) { - intr_happened = 1; - return; - } - if (localchars) { - intp(); - return; - } - setcommandmode(); - longjmp(toplevel, -1); -} - - /* ARGSUSED */ -static RETSIGTYPE -intr2(int sig) -{ - if (localchars) { -#ifdef KLUDGELINEMODE - if (kludgelinemode) - sendbrk(); - else -#endif - sendabort(); - return; - } -} - -#ifdef SIGTSTP - /* ARGSUSED */ -static RETSIGTYPE -susp(int sig) -{ - if ((rlogin != _POSIX_VDISABLE) && rlogin_susp()) - return; - if (localchars) - sendsusp(); -} -#endif - -#ifdef SIGWINCH - /* ARGSUSED */ -static RETSIGTYPE -sendwin(int sig) -{ - if (connected) { - sendnaws(); - } -} -#endif - -#ifdef SIGINFO - /* ARGSUSED */ -static RETSIGTYPE -ayt(int sig) -{ - if (connected) - sendayt(); - else - ayt_status(sig); -} -#endif - - -void -sys_telnet_init(void) -{ - signal(SIGINT, intr); - signal(SIGQUIT, intr2); - signal(SIGPIPE, deadpeer); -#ifdef SIGWINCH - signal(SIGWINCH, sendwin); -#endif -#ifdef SIGTSTP - signal(SIGTSTP, susp); -#endif -#ifdef SIGINFO - signal(SIGINFO, ayt); -#endif - - setconnmode(0); - - NetNonblockingIO(net, 1); - - -#if defined(SO_OOBINLINE) - if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) - perror("setsockopt (SO_OOBINLINE) (ignored)"); -#endif /* defined(SO_OOBINLINE) */ -} - -/* - * Process rings - - * - * This routine tries to fill up/empty our various rings. - * - * The parameter specifies whether this is a poll operation, - * or a block-until-something-happens operation. - * - * The return value is 1 if something happened, 0 if not. - */ - -int -process_rings(int netin, - int netout, - int netex, - int ttyin, - int ttyout, - int poll) /* If 0, then block until something to do */ -{ - int c; - /* One wants to be a bit careful about setting returnValue - * to one, since a one implies we did some useful work, - * and therefore probably won't be called to block next - * time (TN3270 mode only). - */ - int returnValue = 0; - static struct timeval TimeValue = { 0 }; - - if (net >= FD_SETSIZE - || tout >= FD_SETSIZE - || tin >= FD_SETSIZE) - errx (1, "fd too large"); - - if (netout) { - FD_SET(net, &obits); - } - if (ttyout) { - FD_SET(tout, &obits); - } - if (ttyin) { - FD_SET(tin, &ibits); - } - if (netin) { - FD_SET(net, &ibits); - } -#if !defined(SO_OOBINLINE) - if (netex) { - FD_SET(net, &xbits); - } -#endif - if ((c = select(FD_SETSIZE, &ibits, &obits, &xbits, - (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) { - if (c == -1) { - /* - * we can get EINTR if we are in line mode, - * and the user does an escape (TSTP), or - * some other signal generator. - */ - if (errno == EINTR) { - return 0; - } - /* I don't like this, does it ever happen? */ - printf("sleep(5) from telnet, after select\r\n"); - sleep(5); - } - return 0; - } - - /* - * Any urgent data? - */ - if (FD_ISSET(net, &xbits)) { - FD_CLR(net, &xbits); - SYNCHing = 1; - ttyflush(1); /* flush already enqueued data */ - } - - /* - * Something to read from the network... - */ - if (FD_ISSET(net, &ibits)) { - int canread; - - FD_CLR(net, &ibits); - canread = ring_empty_consecutive(&netiring); -#if !defined(SO_OOBINLINE) - /* - * In 4.2 (and some early 4.3) systems, the - * OOB indication and data handling in the kernel - * is such that if two separate TCP Urgent requests - * come in, one byte of TCP data will be overlaid. - * This is fatal for Telnet, but we try to live - * with it. - * - * In addition, in 4.2 (and...), a special protocol - * is needed to pick up the TCP Urgent data in - * the correct sequence. - * - * What we do is: if we think we are in urgent - * mode, we look to see if we are "at the mark". - * If we are, we do an OOB receive. If we run - * this twice, we will do the OOB receive twice, - * but the second will fail, since the second - * time we were "at the mark", but there wasn't - * any data there (the kernel doesn't reset - * "at the mark" until we do a normal read). - * Once we've read the OOB data, we go ahead - * and do normal reads. - * - * There is also another problem, which is that - * since the OOB byte we read doesn't put us - * out of OOB state, and since that byte is most - * likely the TELNET DM (data mark), we would - * stay in the TELNET SYNCH (SYNCHing) state. - * So, clocks to the rescue. If we've "just" - * received a DM, then we test for the - * presence of OOB data when the receive OOB - * fails (and AFTER we did the normal mode read - * to clear "at the mark"). - */ - if (SYNCHing) { - int atmark; - static int bogus_oob = 0, first = 1; - - ioctl(net, SIOCATMARK, (char *)&atmark); - if (atmark) { - c = recv(net, netiring.supply, canread, MSG_OOB); - if ((c == -1) && (errno == EINVAL)) { - c = recv(net, netiring.supply, canread, 0); - if (clocks.didnetreceive < clocks.gotDM) { - SYNCHing = stilloob(); - } - } else if (first && c > 0) { - /* - * Bogosity check. Systems based on 4.2BSD - * do not return an error if you do a second - * recv(MSG_OOB). So, we do one. If it - * succeeds and returns exactly the same - * data, then assume that we are running - * on a broken system and set the bogus_oob - * flag. (If the data was different, then - * we probably got some valid new data, so - * increment the count...) - */ - int i; - i = recv(net, netiring.supply + c, canread - c, MSG_OOB); - if (i == c && - memcmp(netiring.supply, netiring.supply + c, i) == 0) { - bogus_oob = 1; - first = 0; - } else if (i < 0) { - bogus_oob = 0; - first = 0; - } else - c += i; - } - if (bogus_oob && c > 0) { - int i; - /* - * Bogosity. We have to do the read - * to clear the atmark to get out of - * an infinate loop. - */ - i = read(net, netiring.supply + c, canread - c); - if (i > 0) - c += i; - } - } else { - c = recv(net, netiring.supply, canread, 0); - } - } else { - c = recv(net, netiring.supply, canread, 0); - } - settimer(didnetreceive); -#else /* !defined(SO_OOBINLINE) */ - c = recv(net, (char *)netiring.supply, canread, 0); -#endif /* !defined(SO_OOBINLINE) */ - if (c < 0 && errno == EWOULDBLOCK) { - c = 0; - } else if (c <= 0) { - return -1; - } - if (netdata) { - Dump('<', netiring.supply, c); - } - if (c) - ring_supplied(&netiring, c); - returnValue = 1; - } - - /* - * Something to read from the tty... - */ - if (FD_ISSET(tin, &ibits)) { - FD_CLR(tin, &ibits); - c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring)); - if (c < 0 && errno == EIO) - c = 0; - if (c < 0 && errno == EWOULDBLOCK) { - c = 0; - } else { - /* EOF detection for line mode!!!! */ - if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) { - /* must be an EOF... */ - *ttyiring.supply = termEofChar; - c = 1; - } - if (c <= 0) { - return -1; - } - if (termdata) { - Dump('<', ttyiring.supply, c); - } - ring_supplied(&ttyiring, c); - } - returnValue = 1; /* did something useful */ - } - - if (FD_ISSET(net, &obits)) { - FD_CLR(net, &obits); - returnValue |= netflush(); - } - if (FD_ISSET(tout, &obits)) { - FD_CLR(tout, &obits); - returnValue |= (ttyflush(SYNCHing|flushout) > 0); - } - - return returnValue; -} diff --git a/appl/telnet/telnet/telnet.1 b/appl/telnet/telnet/telnet.1 deleted file mode 100644 index 37f588a4c..000000000 --- a/appl/telnet/telnet/telnet.1 +++ /dev/null @@ -1,1369 +0,0 @@ -.\" Copyright (c) 1983, 1990, 1993 -.\" The Regents of the University of California. All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. -.\" 4. Neither the name of the University nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" @(#)telnet.1 8.6 (Berkeley) 6/1/94 -.\" -.Dd June 1, 1994 -.Dt TELNET 1 -.Os BSD 4.2 -.Sh NAME -.Nm telnet -.Nd user interface to the -.Tn TELNET -protocol -.Sh SYNOPSIS -.Nm telnet -.Op Fl 78EFKLacdfrx -.Op Fl S Ar tos -.Op Fl X Ar authtype -.Op Fl e Ar escapechar -.Op Fl k Ar realm -.Op Fl l Ar user -.Op Fl n Ar tracefile -.Oo -.Ar host -.Op port -.Oc -.Sh DESCRIPTION -The -.Nm telnet -command -is used to communicate with another host using the -.Tn TELNET -protocol. -If -.Nm telnet -is invoked without the -.Ar host -argument, it enters command mode, -indicated by its prompt -.Pq Nm telnet\*[Gt] . -In this mode, it accepts and executes the commands listed below. -If it is invoked with arguments, it performs an -.Ic open -command with those arguments. -.Pp -Options: -.Bl -tag -width indent -.It Fl 8 -Specifies an 8-bit data path. This causes an attempt to -negotiate the -.Dv TELNET BINARY -option on both input and output. -.It Fl 7 -Do not try to negotiate -.Dv TELNET BINARY -option. -.It Fl E -Stops any character from being recognized as an escape character. -.It Fl F -If Kerberos V5 authentication is being used, the -.Fl F -option allows the local credentials to be forwarded -to the remote system, including any credentials that -have already been forwarded into the local environment. -.It Fl K -Specifies no automatic login to the remote system. -.It Fl L -Specifies an 8-bit data path on output. This causes the -BINARY option to be negotiated on output. -.It Fl S Ar tos -Sets the IP type-of-service (TOS) option for the telnet -connection to the value -.Ar tos , -which can be a numeric TOS value -or, on systems that support it, a symbolic -TOS name found in the /etc/iptos file. -.It Fl X Ar atype -Disables the -.Ar atype -type of authentication. -.It Fl a -Attempt automatic login. -Currently, this sends the user name via the -.Ev USER -variable -of the -.Ev ENVIRON -option if supported by the remote system. -The name used is that of the current user as returned by -.Xr getlogin 2 -if it agrees with the current user ID, -otherwise it is the name associated with the user ID. -.It Fl c -Disables the reading of the user's -.Pa \&.telnetrc -file. (See the -.Ic toggle skiprc -command on this man page.) -.It Fl d -Sets the initial value of the -.Ic debug -toggle to -.Dv TRUE -.It Fl e Ar escape char -Sets the initial -.Nm -.Nm telnet -escape character to -.Ar escape char . -If -.Ar escape char -is omitted, then -there will be no escape character. -.It Fl f -If Kerberos V5 authentication is being used, the -.Fl f -option allows the local credentials to be forwarded to the remote system. -.It Fl k Ar realm -If Kerberos authentication is being used, the -.Fl k -option requests that telnet obtain tickets for the remote host in -realm realm instead of the remote host's realm, as determined -by -.Xr krb_realmofhost 3 . -.It Fl l Ar user -When connecting to the remote system, if the remote system -understands the -.Ev ENVIRON -option, then -.Ar user -will be sent to the remote system as the value for the variable USER. -This option implies the -.Fl a -option. -This option may also be used with the -.Ic open -command. -.It Fl n Ar tracefile -Opens -.Ar tracefile -for recording trace information. -See the -.Ic set tracefile -command below. -.It Fl r -Specifies a user interface similar to -.Xr rlogin 1 . -In this -mode, the escape character is set to the tilde (~) character, -unless modified by the -e option. -.It Fl x -Turn on encryption of the data stream. When this option is turned on, -.B telnet -will exit with an error if authentication cannot be negotiated or if -encryption cannot be turned on. -.It Ar host -Indicates the official name, an alias, or the Internet address -of a remote host. -.It Ar port -Indicates a port number (address of an application). If a number is -not specified, the default -.Nm telnet -port is used. -.El -.Pp -When in rlogin mode, a line of the form ~. disconnects from the -remote host; ~ is the telnet escape character. -Similarly, the line ~^Z suspends the telnet session. -The line ~^] escapes to the normal telnet escape prompt. -.Pp -Once a connection has been opened, -.Nm telnet -will attempt to enable the -.Dv TELNET LINEMODE -option. -If this fails, then -.Nm telnet -will revert to one of two input modes: -either \*(Lqcharacter at a time\*(Rq -or \*(Lqold line by line\*(Rq -depending on what the remote system supports. -.Pp -When -.Dv LINEMODE -is enabled, character processing is done on the -local system, under the control of the remote system. When input -editing or character echoing is to be disabled, the remote system -will relay that information. The remote system will also relay -changes to any special characters that happen on the remote -system, so that they can take effect on the local system. -.Pp -In \*(Lqcharacter at a time\*(Rq mode, most -text typed is immediately sent to the remote host for processing. -.Pp -In \*(Lqold line by line\*(Rq mode, all text is echoed locally, -and (normally) only completed lines are sent to the remote host. -The \*(Lqlocal echo character\*(Rq (initially \*(Lq^E\*(Rq) may be used -to turn off and on the local echo -(this would mostly be used to enter passwords -without the password being echoed). -.Pp -If the -.Dv LINEMODE -option is enabled, or if the -.Ic localchars -toggle is -.Dv TRUE -(the default for \*(Lqold line by line\*(Lq; see below), -the user's -.Ic quit , -.Ic intr , -and -.Ic flush -characters are trapped locally, and sent as -.Tn TELNET -protocol sequences to the remote side. -If -.Dv LINEMODE -has ever been enabled, then the user's -.Ic susp -and -.Ic eof -are also sent as -.Tn TELNET -protocol sequences, -and -.Ic quit -is sent as a -.Dv TELNET ABORT -instead of -.Dv BREAK -There are options (see -.Ic toggle -.Ic autoflush -and -.Ic toggle -.Ic autosynch -below) -which cause this action to flush subsequent output to the terminal -(until the remote host acknowledges the -.Tn TELNET -sequence) and flush previous terminal input -(in the case of -.Ic quit -and -.Ic intr ) . -.Pp -While connected to a remote host, -.Nm telnet -command mode may be entered by typing the -.Nm telnet -\*(Lqescape character\*(Rq (initially \*(Lq^]\*(Rq). -When in command mode, the normal terminal editing conventions are available. -.Pp -The following -.Nm telnet -commands are available. -Only enough of each command to uniquely identify it need be typed -(this is also true for arguments to the -.Ic mode , -.Ic set , -.Ic toggle , -.Ic unset , -.Ic slc , -.Ic environ , -and -.Ic display -commands). -.Pp -.Bl -tag -width "mode type" -.It Ic auth Ar argument ... -The auth command manipulates the information sent through the -.Dv TELNET AUTHENTICATE -option. Valid arguments for the -auth command are as follows: -.Bl -tag -width "disable type" -.It Ic disable Ar type -Disables the specified type of authentication. To -obtain a list of available types, use the -.Ic auth disable ?\& -command. -.It Ic enable Ar type -Enables the specified type of authentication. To -obtain a list of available types, use the -.Ic auth enable ?\& -command. -.It Ic status -Lists the current status of the various types of -authentication. -.El -.It Ic close -Close a -.Tn TELNET -session and return to command mode. -.It Ic display Ar argument ... -Displays all, or some, of the -.Ic set -and -.Ic toggle -values (see below). -.It Ic encrypt Ar argument ... -The encrypt command manipulates the information sent through the -.Dv TELNET ENCRYPT -option. -.Pp -Note: Because of export controls, the -.Dv TELNET ENCRYPT -option is not supported outside of the United States and Canada. -.Pp -Valid arguments for the encrypt command are as follows: -.Bl -tag -width Ar -.It Ic disable Ar type Xo -.Op Cm input | output -.Xc -Disables the specified type of encryption. If you -omit the input and output, both input and output -are disabled. To obtain a list of available -types, use the -.Ic encrypt disable ?\& -command. -.It Ic enable Ar type Xo -.Op Cm input | output -.Xc -Enables the specified type of encryption. If you -omit input and output, both input and output are -enabled. To obtain a list of available types, use the -.Ic encrypt enable ?\& -command. -.It Ic input -This is the same as the -.Ic encrypt start input -command. -.It Ic -input -This is the same as the -.Ic encrypt stop input -command. -.It Ic output -This is the same as the -.Ic encrypt start output -command. -.It Ic -output -This is the same as the -.Ic encrypt stop output -command. -.It Ic start Op Cm input | output -Attempts to start encryption. If you omit -.Ic input -and -.Ic output , -both input and output are enabled. To -obtain a list of available types, use the -.Ic encrypt enable ?\& -command. -.It Ic status -Lists the current status of encryption. -.It Ic stop Op Cm input | output -Stops encryption. If you omit input and output, -encryption is on both input and output. -.It Ic type Ar type -Sets the default type of encryption to be used -with later -.Ic encrypt start -or -.Ic encrypt stop -commands. -.El -.It Ic environ Ar arguments ... -The -.Ic environ -command is used to manipulate the -the variables that my be sent through the -.Dv TELNET ENVIRON -option. -The initial set of variables is taken from the users -environment, with only the -.Ev DISPLAY -and -.Ev PRINTER -variables being exported by default. -The -.Ev USER -variable is also exported if the -.Fl a -or -.Fl l -options are used. -.Pp -Valid arguments for the -.Ic environ -command are: -.Bl -tag -width Fl -.It Ic define Ar variable value -Define the variable -.Ar variable -to have a value of -.Ar value . -Any variables defined by this command are automatically exported. -The -.Ar value -may be enclosed in single or double quotes so -that tabs and spaces may be included. -.It Ic undefine Ar variable -Remove -.Ar variable -from the list of environment variables. -.It Ic export Ar variable -Mark the variable -.Ar variable -to be exported to the remote side. -.It Ic unexport Ar variable -Mark the variable -.Ar variable -to not be exported unless -explicitly asked for by the remote side. -.It Ic list -List the current set of environment variables. -Those marked with a -.Cm * -will be sent automatically, -other variables will only be sent if explicitly requested. -.It Ic ?\& -Prints out help information for the -.Ic environ -command. -.El -.It Ic logout -Sends the -.Dv TELNET LOGOUT -option to the remote side. -This command is similar to a -.Ic close -command; however, if the remote side does not support the -.Dv LOGOUT -option, nothing happens. -If, however, the remote side does support the -.Dv LOGOUT -option, this command should cause the remote side to close the -.Tn TELNET -connection. -If the remote side also supports the concept of -suspending a user's session for later reattachment, -the logout argument indicates that you -should terminate the session immediately. -.It Ic mode Ar type -.Ar Type -is one of several options, depending on the state of the -.Tn TELNET -session. -The remote host is asked for permission to go into the requested mode. -If the remote host is capable of entering that mode, the requested -mode will be entered. -.Bl -tag -width Ar -.It Ic character -Disable the -.Dv TELNET LINEMODE -option, or, if the remote side does not understand the -.Dv LINEMODE -option, then enter \*(Lqcharacter at a time\*(Lq mode. -.It Ic line -Enable the -.Dv TELNET LINEMODE -option, or, if the remote side does not understand the -.Dv LINEMODE -option, then attempt to enter \*(Lqold-line-by-line\*(Lq mode. -.It Ic isig Pq Ic \-isig -Attempt to enable (disable) the -.Dv TRAPSIG -mode of the -.Dv LINEMODE -option. -This requires that the -.Dv LINEMODE -option be enabled. -.It Ic edit Pq Ic \-edit -Attempt to enable (disable) the -.Dv EDIT -mode of the -.Dv LINEMODE -option. -This requires that the -.Dv LINEMODE -option be enabled. -.It Ic softtabs Pq Ic \-softtabs -Attempt to enable (disable) the -.Dv SOFT_TAB -mode of the -.Dv LINEMODE -option. -This requires that the -.Dv LINEMODE -option be enabled. -.It Ic litecho Pq Ic \-litecho -Attempt to enable (disable) the -.Dv LIT_ECHO -mode of the -.Dv LINEMODE -option. -This requires that the -.Dv LINEMODE -option be enabled. -.It Ic ?\& -Prints out help information for the -.Ic mode -command. -.El -.It Xo -.Ic open Ar host -.Op Fl l Ar user -.Op Oo Fl Oc Ns Ar port -.Xc -Open a connection to the named host. -If no port number -is specified, -.Nm telnet -will attempt to contact a -.Tn TELNET -server at the default port. -The host specification may be either a host name (see -.Xr hosts 5 ) -or an Internet address specified in the \*(Lqdot notation\*(Rq (see -.Xr inet 3 ) . -The -.Op Fl l -option may be used to specify the user name -to be passed to the remote system via the -.Ev ENVIRON -option. -When connecting to a non-standard port, -.Nm telnet -omits any automatic initiation of -.Tn TELNET -options. When the port number is preceded by a minus sign, -the initial option negotiation is done. -After establishing a connection, the file -.Pa \&.telnetrc -in the -users home directory is opened. Lines beginning with a # are -comment lines. Blank lines are ignored. Lines that begin -without white space are the start of a machine entry. The -first thing on the line is the name of the machine that is -being connected to. The rest of the line, and successive -lines that begin with white space are assumed to be -.Nm telnet -commands and are processed as if they had been typed -in manually to the -.Nm telnet -command prompt. -.It Ic quit -Close any open -.Tn TELNET -session and exit -.Nm telnet . -An end of file (in command mode) will also close a session and exit. -.It Ic send Ar arguments -Sends one or more special character sequences to the remote host. -The following are the arguments which may be specified -(more than one argument may be specified at a time): -.Pp -.Bl -tag -width escape -.It Ic abort -Sends the -.Dv TELNET ABORT -(Abort -processes) -sequence. -.It Ic ao -Sends the -.Dv TELNET AO -(Abort Output) sequence, which should cause the remote system to flush -all output -.Em from -the remote system -.Em to -the user's terminal. -.It Ic ayt -Sends the -.Dv TELNET AYT -(Are You There) -sequence, to which the remote system may or may not choose to respond. -.It Ic brk -Sends the -.Dv TELNET BRK -(Break) sequence, which may have significance to the remote -system. -.It Ic ec -Sends the -.Dv TELNET EC -(Erase Character) -sequence, which should cause the remote system to erase the last character -entered. -.It Ic el -Sends the -.Dv TELNET EL -(Erase Line) -sequence, which should cause the remote system to erase the line currently -being entered. -.It Ic eof -Sends the -.Dv TELNET EOF -(End Of File) -sequence. -.It Ic eor -Sends the -.Dv TELNET EOR -(End of Record) -sequence. -.It Ic escape -Sends the current -.Nm telnet -escape character (initially \*(Lq^\*(Rq). -.It Ic ga -Sends the -.Dv TELNET GA -(Go Ahead) -sequence, which likely has no significance to the remote system. -.It Ic getstatus -If the remote side supports the -.Dv TELNET STATUS -command, -.Ic getstatus -will send the subnegotiation to request that the server send -its current option status. -.It Ic ip -Sends the -.Dv TELNET IP -(Interrupt Process) sequence, which should cause the remote -system to abort the currently running process. -.It Ic nop -Sends the -.Dv TELNET NOP -(No OPeration) -sequence. -.It Ic susp -Sends the -.Dv TELNET SUSP -(SUSPend process) -sequence. -.It Ic synch -Sends the -.Dv TELNET SYNCH -sequence. -This sequence causes the remote system to discard all previously typed -(but not yet read) input. -This sequence is sent as -.Tn TCP -urgent -data (and may not work if the remote system is a -.Bx 4.2 -system -- if -it doesn't work, a lower case \*(Lqr\*(Rq may be echoed on the terminal). -.It Ic do Ar cmd -.It Ic dont Ar cmd -.It Ic will Ar cmd -.It Ic wont Ar cmd -Sends the -.Dv TELNET DO -.Ar cmd -sequence. -.Ar Cmd -can be either a decimal number between 0 and 255, -or a symbolic name for a specific -.Dv TELNET -command. -.Ar Cmd -can also be either -.Ic help -or -.Ic ?\& -to print out help information, including -a list of known symbolic names. -.It Ic ?\& -Prints out help information for the -.Ic send -command. -.El -.It Ic set Ar argument value -.It Ic unset Ar argument value -The -.Ic set -command will set any one of a number of -.Nm telnet -variables to a specific value or to -.Dv TRUE . -The special value -.Ic off -turns off the function associated with -the variable, this is equivalent to using the -.Ic unset -command. -The -.Ic unset -command will disable or set to -.Dv FALSE -any of the specified functions. -The values of variables may be interrogated with the -.Ic display -command. -The variables which may be set or unset, but not toggled, are -listed here. In addition, any of the variables for the -.Ic toggle -command may be explicitly set or unset using -the -.Ic set -and -.Ic unset -commands. -.Bl -tag -width escape -.It Ic ayt -If -.Tn TELNET -is in localchars mode, or -.Dv LINEMODE -is enabled, and the status character is typed, a -.Dv TELNET AYT -sequence (see -.Ic send ayt -preceding) is sent to the -remote host. The initial value for the "Are You There" -character is the terminal's status character. -.It Ic echo -This is the value (initially \*(Lq^E\*(Rq) which, when in -\*(Lqline by line\*(Rq mode, toggles between doing local echoing -of entered characters (for normal processing), and suppressing -echoing of entered characters (for entering, say, a password). -.It Ic eof -If -.Nm telnet -is operating in -.Dv LINEMODE -or \*(Lqold line by line\*(Rq mode, entering this character -as the first character on a line will cause this character to be -sent to the remote system. -The initial value of the eof character is taken to be the terminal's -.Ic eof -character. -.It Ic erase -If -.Nm telnet -is in -.Ic localchars -mode (see -.Ic toggle -.Ic localchars -below), -.Sy and -if -.Nm telnet -is operating in \*(Lqcharacter at a time\*(Rq mode, then when this -character is typed, a -.Dv TELNET EC -sequence (see -.Ic send -.Ic ec -above) -is sent to the remote system. -The initial value for the erase character is taken to be -the terminal's -.Ic erase -character. -.It Ic escape -This is the -.Nm telnet -escape character (initially \*(Lq^[\*(Rq) which causes entry -into -.Nm telnet -command mode (when connected to a remote system). -.It Ic flushoutput -If -.Nm telnet -is in -.Ic localchars -mode (see -.Ic toggle -.Ic localchars -below) -and the -.Ic flushoutput -character is typed, a -.Dv TELNET AO -sequence (see -.Ic send -.Ic ao -above) -is sent to the remote host. -The initial value for the flush character is taken to be -the terminal's -.Ic flush -character. -.It Ic forw1 -.It Ic forw2 -If -.Tn TELNET -is operating in -.Dv LINEMODE , -these are the -characters that, when typed, cause partial lines to be -forwarded to the remote system. The initial value for -the forwarding characters are taken from the terminal's -eol and eol2 characters. -.It Ic interrupt -If -.Nm telnet -is in -.Ic localchars -mode (see -.Ic toggle -.Ic localchars -below) -and the -.Ic interrupt -character is typed, a -.Dv TELNET IP -sequence (see -.Ic send -.Ic ip -above) -is sent to the remote host. -The initial value for the interrupt character is taken to be -the terminal's -.Ic intr -character. -.It Ic kill -If -.Nm telnet -is in -.Ic localchars -mode (see -.Ic toggle -.Ic localchars -below), -.Ic and -if -.Nm telnet -is operating in \*(Lqcharacter at a time\*(Rq mode, then when this -character is typed, a -.Dv TELNET EL -sequence (see -.Ic send -.Ic el -above) -is sent to the remote system. -The initial value for the kill character is taken to be -the terminal's -.Ic kill -character. -.It Ic lnext -If -.Nm telnet -is operating in -.Dv LINEMODE -or \*(Lqold line by line\*(Lq mode, then this character is taken to -be the terminal's -.Ic lnext -character. -The initial value for the lnext character is taken to be -the terminal's -.Ic lnext -character. -.It Ic quit -If -.Nm telnet -is in -.Ic localchars -mode (see -.Ic toggle -.Ic localchars -below) -and the -.Ic quit -character is typed, a -.Dv TELNET BRK -sequence (see -.Ic send -.Ic brk -above) -is sent to the remote host. -The initial value for the quit character is taken to be -the terminal's -.Ic quit -character. -.It Ic reprint -If -.Nm telnet -is operating in -.Dv LINEMODE -or \*(Lqold line by line\*(Lq mode, then this character is taken to -be the terminal's -.Ic reprint -character. -The initial value for the reprint character is taken to be -the terminal's -.Ic reprint -character. -.It Ic rlogin -This is the rlogin escape character. -If set, the normal -.Tn TELNET -escape character is ignored unless it is -preceded by this character at the beginning of a line. -This character, at the beginning of a line followed by -a "." closes the connection; when followed by a ^Z it -suspends the telnet command. The initial state is to -disable the rlogin escape character. -.It Ic start -If the -.Dv TELNET TOGGLE-FLOW-CONTROL -option has been enabled, -then this character is taken to -be the terminal's -.Ic start -character. -The initial value for the kill character is taken to be -the terminal's -.Ic start -character. -.It Ic stop -If the -.Dv TELNET TOGGLE-FLOW-CONTROL -option has been enabled, -then this character is taken to -be the terminal's -.Ic stop -character. -The initial value for the kill character is taken to be -the terminal's -.Ic stop -character. -.It Ic susp -If -.Nm telnet -is in -.Ic localchars -mode, or -.Dv LINEMODE -is enabled, and the -.Ic suspend -character is typed, a -.Dv TELNET SUSP -sequence (see -.Ic send -.Ic susp -above) -is sent to the remote host. -The initial value for the suspend character is taken to be -the terminal's -.Ic suspend -character. -.It Ic tracefile -This is the file to which the output, caused by -.Ic netdata -or -.Ic option -tracing being -.Dv TRUE , -will be written. If it is set to -.Dq Fl , -then tracing information will be written to standard output (the default). -.It Ic worderase -If -.Nm telnet -is operating in -.Dv LINEMODE -or \*(Lqold line by line\*(Lq mode, then this character is taken to -be the terminal's -.Ic worderase -character. -The initial value for the worderase character is taken to be -the terminal's -.Ic worderase -character. -.It Ic ?\& -Displays the legal -.Ic set -.Pq Ic unset -commands. -.El -.It Ic slc Ar state -The -.Ic slc -command (Set Local Characters) is used to set -or change the state of the the special -characters when the -.Dv TELNET LINEMODE -option has -been enabled. Special characters are characters that get -mapped to -.Tn TELNET -commands sequences (like -.Ic ip -or -.Ic quit ) -or line editing characters (like -.Ic erase -and -.Ic kill ) . -By default, the local special characters are exported. -.Bl -tag -width Fl -.It Ic check -Verify the current settings for the current special characters. -The remote side is requested to send all the current special -character settings, and if there are any discrepancies with -the local side, the local side will switch to the remote value. -.It Ic export -Switch to the local defaults for the special characters. The -local default characters are those of the local terminal at -the time when -.Nm telnet -was started. -.It Ic import -Switch to the remote defaults for the special characters. -The remote default characters are those of the remote system -at the time when the -.Tn TELNET -connection was established. -.It Ic ?\& -Prints out help information for the -.Ic slc -command. -.El -.It Ic status -Show the current status of -.Nm telnet . -This includes the peer one is connected to, as well -as the current mode. -.It Ic toggle Ar arguments ... -Toggle (between -.Dv TRUE -and -.Dv FALSE ) -various flags that control how -.Nm telnet -responds to events. -These flags may be set explicitly to -.Dv TRUE -or -.Dv FALSE -using the -.Ic set -and -.Ic unset -commands listed above. -More than one argument may be specified. -The state of these flags may be interrogated with the -.Ic display -command. -Valid arguments are: -.Bl -tag -width Ar -.It Ic authdebug -Turns on debugging information for the authentication code. -.It Ic autoflush -If -.Ic autoflush -and -.Ic localchars -are both -.Dv TRUE , -then when the -.Ic ao , -or -.Ic quit -characters are recognized (and transformed into -.Tn TELNET -sequences; see -.Ic set -above for details), -.Nm telnet -refuses to display any data on the user's terminal -until the remote system acknowledges (via a -.Dv TELNET TIMING MARK -option) -that it has processed those -.Tn TELNET -sequences. -The initial value for this toggle is -.Dv TRUE -if the terminal user had not -done an "stty noflsh", otherwise -.Dv FALSE -(see -.Xr stty 1 ) . -.It Ic autodecrypt -When the -.Dv TELNET ENCRYPT -option is negotiated, by -default the actual encryption (decryption) of the data -stream does not start automatically. The autoencrypt -(autodecrypt) command states that encryption of the -output (input) stream should be enabled as soon as -possible. -.Pp -Note: Because of export controls, the -.Dv TELNET ENCRYPT -option is not supported outside the United States and Canada. -.It Ic autologin -If the remote side supports the -.Dv TELNET AUTHENTICATION -option -.Tn TELNET -attempts to use it to perform automatic authentication. If the -.Dv AUTHENTICATION -option is not supported, the user's login -name are propagated through the -.Dv TELNET ENVIRON -option. -This command is the same as specifying -.Ar a -option on the -.Ic open -command. -.It Ic autosynch -If -.Ic autosynch -and -.Ic localchars -are both -.Dv TRUE , -then when either the -.Ic intr -or -.Ic quit -characters is typed (see -.Ic set -above for descriptions of the -.Ic intr -and -.Ic quit -characters), the resulting -.Tn TELNET -sequence sent is followed by the -.Dv TELNET SYNCH -sequence. -This procedure -.Ic should -cause the remote system to begin throwing away all previously -typed input until both of the -.Tn TELNET -sequences have been read and acted upon. -The initial value of this toggle is -.Dv FALSE . -.It Ic binary -Enable or disable the -.Dv TELNET BINARY -option on both input and output. -.It Ic inbinary -Enable or disable the -.Dv TELNET BINARY -option on input. -.It Ic outbinary -Enable or disable the -.Dv TELNET BINARY -option on output. -.It Ic crlf -If this is -.Dv TRUE , -then carriage returns will be sent as -.Li \*[Lt]CR\*[Gt]\*[Lt]LF\*[Gt] . -If this is -.Dv FALSE , -then carriage returns will be send as -.Li \*[Lt]CR\*[Gt]\*[Lt]NUL\*[Gt] . -The initial value for this toggle is -.Dv FALSE . -.It Ic crmod -Toggle carriage return mode. -When this mode is enabled, most carriage return characters received from -the remote host will be mapped into a carriage return followed by -a line feed. -This mode does not affect those characters typed by the user, only -those received from the remote host. -This mode is not very useful unless the remote host -only sends carriage return, but never line feed. -The initial value for this toggle is -.Dv FALSE . -.It Ic debug -Toggles socket level debugging (useful only to the -.Ic super user ) . -The initial value for this toggle is -.Dv FALSE . -.It Ic encdebug -Turns on debugging information for the encryption code. -.It Ic localchars -If this is -.Dv TRUE , -then the -.Ic flush , -.Ic interrupt , -.Ic quit , -.Ic erase , -and -.Ic kill -characters (see -.Ic set -above) are recognized locally, and transformed into (hopefully) appropriate -.Tn TELNET -control sequences -(respectively -.Ic ao , -.Ic ip , -.Ic brk , -.Ic ec , -and -.Ic el ; -see -.Ic send -above). -The initial value for this toggle is -.Dv TRUE -in \*(Lqold line by line\*(Rq mode, -and -.Dv FALSE -in \*(Lqcharacter at a time\*(Rq mode. -When the -.Dv LINEMODE -option is enabled, the value of -.Ic localchars -is ignored, and assumed to always be -.Dv TRUE . -If -.Dv LINEMODE -has ever been enabled, then -.Ic quit -is sent as -.Ic abort , -and -.Ic eof -and -.Ic suspend -are sent as -.Ic eof -and -.Ic susp , -see -.Ic send -above). -.It Ic netdata -Toggles the display of all network data (in hexadecimal format). -The initial value for this toggle is -.Dv FALSE . -.It Ic options -Toggles the display of some internal -.Nm telnet -protocol processing (having to do with -.Tn TELNET -options). -The initial value for this toggle is -.Dv FALSE . -.It Ic prettydump -When the -.Ic netdata -toggle is enabled, if -.Ic prettydump -is enabled the output from the -.Ic netdata -command will be formatted in a more user readable format. -Spaces are put between each character in the output, and the -beginning of any -.Tn TELNET -escape sequence is preceded by a '*' to aid in locating them. -.It Ic skiprc -When the skiprc toggle is -.Dv TRUE , -.Tn TELNET -skips the reading of the -.Pa \&.telnetrc -file in the users home -directory when connections are opened. The initial -value for this toggle is -.Dv FALSE . -.It Ic termdata -Toggles the display of all terminal data (in hexadecimal format). -The initial value for this toggle is -.Dv FALSE . -.It Ic verbose_encrypt -When the -.Ic verbose_encrypt -toggle is -.Dv TRUE , -.Tn TELNET -prints out a message each time encryption is enabled or -disabled. The initial value for this toggle is -.Dv FALSE . -Note: Because of export controls, data encryption -is not supported outside of the United States and Canada. -.It Ic \&? -Displays the legal -.Ic toggle -commands. -.El -.It Ic z -Suspend -.Nm telnet . -This command only works when the user is using the -.Xr csh 1 . -.It Ic \&! Op Ar command -Execute a single command in a subshell on the local -system. If -.Ic command -is omitted, then an interactive -subshell is invoked. -.It Ic ?\& Op Ar command -Get help. With no arguments, -.Nm telnet -prints a help summary. -If a command is specified, -.Nm telnet -will print the help information for just that command. -.El -.Sh ENVIRONMENT -.Nm Telnet -uses at least the -.Ev HOME , -.Ev SHELL , -.Ev DISPLAY , -and -.Ev TERM -environment variables. -Other environment variables may be propagated -to the other side via the -.Dv TELNET ENVIRON -option. -.Sh FILES -.Bl -tag -width ~/.telnetrc -compact -.It Pa ~/.telnetrc -user customized telnet startup values -.El -.Sh HISTORY -The -.Nm Telnet -command appeared in -.Bx 4.2 . -.Sh NOTES -.Pp -On some remote systems, echo has to be turned off manually when in -\*(Lqold line by line\*(Rq mode. -.Pp -In \*(Lqold line by line\*(Rq mode or -.Dv LINEMODE -the terminal's -.Ic eof -character is only recognized (and sent to the remote system) -when it is the first character on a line. diff --git a/appl/telnet/telnet/telnet.c b/appl/telnet/telnet/telnet.c deleted file mode 100644 index 0c5c664d4..000000000 --- a/appl/telnet/telnet/telnet.c +++ /dev/null @@ -1,2420 +0,0 @@ -/* - * Copyright (c) 1988, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "telnet_locl.h" - -RCSID("$Id$"); - -#define strip(x) (eight ? (x) : ((x) & 0x7f)) - -static unsigned char subbuffer[SUBBUFSIZE], - *subpointer, *subend; /* buffer for sub-options */ -#define SB_CLEAR() subpointer = subbuffer; -#define SB_TERM() { subend = subpointer; SB_CLEAR(); } -#define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ - *subpointer++ = (c); \ - } - -#define SB_GET() ((*subpointer++)&0xff) -#define SB_PEEK() ((*subpointer)&0xff) -#define SB_EOF() (subpointer >= subend) -#define SB_LEN() (subend - subpointer) - -char options[256]; /* The combined options */ -char do_dont_resp[256]; -char will_wont_resp[256]; - -int - eight = 3, - binary = 0, - autologin = 0, /* Autologin anyone? */ - skiprc = 0, - connected, - showoptions, - ISend, /* trying to send network data in */ - debug = 0, - crmod, - netdata, /* Print out network data flow */ - crlf, /* Should '\r' be mapped to (or )? */ - telnetport, - wantencryption = 0, - SYNCHing, /* we are in TELNET SYNCH mode */ - flushout, /* flush output */ - autoflush = 0, /* flush output when interrupting? */ - autosynch, /* send interrupt characters with SYNCH? */ - localflow, /* we handle flow control locally */ - restartany, /* if flow control enabled, restart on any character */ - localchars, /* we recognize interrupt/quit */ - donelclchars, /* the user has set "localchars" */ - donebinarytoggle, /* the user has put us in binary */ - dontlecho, /* do we suppress local echoing right now? */ - globalmode; - -char *prompt = 0; - -int scheduler_lockout_tty = 0; - -cc_t escape; -cc_t rlogin; -#ifdef KLUDGELINEMODE -cc_t echoc; -#endif - -/* - * Telnet receiver states for fsm - */ -#define TS_DATA 0 -#define TS_IAC 1 -#define TS_WILL 2 -#define TS_WONT 3 -#define TS_DO 4 -#define TS_DONT 5 -#define TS_CR 6 -#define TS_SB 7 /* sub-option collection */ -#define TS_SE 8 /* looking for sub-option end */ - -static int telrcv_state; -#ifdef OLD_ENVIRON -unsigned char telopt_environ = TELOPT_NEW_ENVIRON; -#else -# define telopt_environ TELOPT_NEW_ENVIRON -#endif - -jmp_buf toplevel; -jmp_buf peerdied; - -int flushline; -int linemode; - -#ifdef KLUDGELINEMODE -int kludgelinemode = 1; -#endif - -/* - * The following are some clocks used to decide how to interpret - * the relationship between various variables. - */ - -Clocks clocks; - -static int is_unique(char *name, char **as, char **ae); - - -/* - * Initialize telnet environment. - */ - -void -init_telnet(void) -{ - env_init(); - - SB_CLEAR(); - memset(options, 0, sizeof options); - - connected = ISend = localflow = donebinarytoggle = 0; -#if defined(AUTHENTICATION) || defined(ENCRYPTION) - auth_encrypt_connect(connected); -#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ - restartany = -1; - - SYNCHing = 0; - - /* Don't change NetTrace */ - - escape = CONTROL(']'); - rlogin = _POSIX_VDISABLE; -#ifdef KLUDGELINEMODE - echoc = CONTROL('E'); -#endif - - flushline = 1; - telrcv_state = TS_DATA; -} - - -/* - * These routines are in charge of sending option negotiations - * to the other side. - * - * The basic idea is that we send the negotiation if either side - * is in disagreement as to what the current state should be. - */ - -void -send_do(int c, int init) -{ - if (init) { - if (((do_dont_resp[c] == 0) && my_state_is_do(c)) || - my_want_state_is_do(c)) - return; - set_my_want_state_do(c); - do_dont_resp[c]++; - } - NET2ADD(IAC, DO); - NETADD(c); - printoption("SENT", DO, c); -} - -void -send_dont(int c, int init) -{ - if (init) { - if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) || - my_want_state_is_dont(c)) - return; - set_my_want_state_dont(c); - do_dont_resp[c]++; - } - NET2ADD(IAC, DONT); - NETADD(c); - printoption("SENT", DONT, c); -} - -void -send_will(int c, int init) -{ - if (init) { - if (((will_wont_resp[c] == 0) && my_state_is_will(c)) || - my_want_state_is_will(c)) - return; - set_my_want_state_will(c); - will_wont_resp[c]++; - } - NET2ADD(IAC, WILL); - NETADD(c); - printoption("SENT", WILL, c); -} - -void -send_wont(int c, int init) -{ - if (init) { - if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) || - my_want_state_is_wont(c)) - return; - set_my_want_state_wont(c); - will_wont_resp[c]++; - } - NET2ADD(IAC, WONT); - NETADD(c); - printoption("SENT", WONT, c); -} - - -void -willoption(int option) -{ - int new_state_ok = 0; - - if (do_dont_resp[option]) { - --do_dont_resp[option]; - if (do_dont_resp[option] && my_state_is_do(option)) - --do_dont_resp[option]; - } - - if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) { - - switch (option) { - - case TELOPT_ECHO: - case TELOPT_BINARY: - case TELOPT_SGA: - settimer(modenegotiated); - /* FALL THROUGH */ - case TELOPT_STATUS: -#if defined(AUTHENTICATION) - case TELOPT_AUTHENTICATION: -#endif -#if defined(ENCRYPTION) - case TELOPT_ENCRYPT: -#endif - new_state_ok = 1; - break; - - case TELOPT_TM: - if (flushout) - flushout = 0; - /* - * Special case for TM. If we get back a WILL, - * pretend we got back a WONT. - */ - set_my_want_state_dont(option); - set_my_state_dont(option); - return; /* Never reply to TM will's/wont's */ - - case TELOPT_LINEMODE: - default: - break; - } - - if (new_state_ok) { - set_my_want_state_do(option); - send_do(option, 0); - setconnmode(0); /* possibly set new tty mode */ - } else { - do_dont_resp[option]++; - send_dont(option, 0); - } - } - set_my_state_do(option); -#if defined(ENCRYPTION) - if (option == TELOPT_ENCRYPT) - encrypt_send_support(); -#endif -} - -void -wontoption(int option) -{ - if (do_dont_resp[option]) { - --do_dont_resp[option]; - if (do_dont_resp[option] && my_state_is_dont(option)) - --do_dont_resp[option]; - } - - if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) { - - switch (option) { - -#ifdef KLUDGELINEMODE - case TELOPT_SGA: - if (!kludgelinemode) - break; - /* FALL THROUGH */ -#endif - case TELOPT_ECHO: - settimer(modenegotiated); - break; - - case TELOPT_TM: - if (flushout) - flushout = 0; - set_my_want_state_dont(option); - set_my_state_dont(option); - return; /* Never reply to TM will's/wont's */ - -#ifdef ENCRYPTION - case TELOPT_ENCRYPT: - encrypt_not(); - break; -#endif - default: - break; - } - set_my_want_state_dont(option); - if (my_state_is_do(option)) - send_dont(option, 0); - setconnmode(0); /* Set new tty mode */ - } else if (option == TELOPT_TM) { - /* - * Special case for TM. - */ - if (flushout) - flushout = 0; - set_my_want_state_dont(option); - } - set_my_state_dont(option); -} - -static void -dooption(int option) -{ - int new_state_ok = 0; - - if (will_wont_resp[option]) { - --will_wont_resp[option]; - if (will_wont_resp[option] && my_state_is_will(option)) - --will_wont_resp[option]; - } - - if (will_wont_resp[option] == 0) { - if (my_want_state_is_wont(option)) { - - switch (option) { - - case TELOPT_TM: - /* - * Special case for TM. We send a WILL, but pretend - * we sent WONT. - */ - send_will(option, 0); - set_my_want_state_wont(TELOPT_TM); - set_my_state_wont(TELOPT_TM); - return; - - case TELOPT_BINARY: /* binary mode */ - case TELOPT_NAWS: /* window size */ - case TELOPT_TSPEED: /* terminal speed */ - case TELOPT_LFLOW: /* local flow control */ - case TELOPT_TTYPE: /* terminal type option */ - case TELOPT_SGA: /* no big deal */ -#if defined(ENCRYPTION) - case TELOPT_ENCRYPT: /* encryption variable option */ -#endif - new_state_ok = 1; - break; - - case TELOPT_NEW_ENVIRON: /* New environment variable option */ -#ifdef OLD_ENVIRON - if (my_state_is_will(TELOPT_OLD_ENVIRON)) - send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */ - goto env_common; - case TELOPT_OLD_ENVIRON: /* Old environment variable option */ - if (my_state_is_will(TELOPT_NEW_ENVIRON)) - break; /* Don't enable if new one is in use! */ - env_common: - telopt_environ = option; -#endif - new_state_ok = 1; - break; - -#if defined(AUTHENTICATION) - case TELOPT_AUTHENTICATION: - if (autologin) - new_state_ok = 1; - break; -#endif - - case TELOPT_XDISPLOC: /* X Display location */ - if (env_getvalue((unsigned char *)"DISPLAY")) - new_state_ok = 1; - break; - - case TELOPT_LINEMODE: -#ifdef KLUDGELINEMODE - kludgelinemode = 0; - send_do(TELOPT_SGA, 1); -#endif - set_my_want_state_will(TELOPT_LINEMODE); - send_will(option, 0); - set_my_state_will(TELOPT_LINEMODE); - slc_init(); - return; - - case TELOPT_ECHO: /* We're never going to echo... */ - default: - break; - } - - if (new_state_ok) { - set_my_want_state_will(option); - send_will(option, 0); - setconnmode(0); /* Set new tty mode */ - } else { - will_wont_resp[option]++; - send_wont(option, 0); - } - } else { - /* - * Handle options that need more things done after the - * other side has acknowledged the option. - */ - switch (option) { - case TELOPT_LINEMODE: -#ifdef KLUDGELINEMODE - kludgelinemode = 0; - send_do(TELOPT_SGA, 1); -#endif - set_my_state_will(option); - slc_init(); - send_do(TELOPT_SGA, 0); - return; - } - } - } - set_my_state_will(option); -} - -static void -dontoption(int option) -{ - - if (will_wont_resp[option]) { - --will_wont_resp[option]; - if (will_wont_resp[option] && my_state_is_wont(option)) - --will_wont_resp[option]; - } - - if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) { - switch (option) { - case TELOPT_LINEMODE: - linemode = 0; /* put us back to the default state */ - break; -#ifdef OLD_ENVIRON - case TELOPT_NEW_ENVIRON: - /* - * The new environ option wasn't recognized, try - * the old one. - */ - send_will(TELOPT_OLD_ENVIRON, 1); - telopt_environ = TELOPT_OLD_ENVIRON; - break; -#endif -#if 0 -#ifdef ENCRYPTION - case TELOPT_ENCRYPT: - encrypt_not(); - break; -#endif -#endif - } - /* we always accept a DONT */ - set_my_want_state_wont(option); - if (my_state_is_will(option)) - send_wont(option, 0); - setconnmode(0); /* Set new tty mode */ - } - set_my_state_wont(option); -} - -/* - * Given a buffer returned by tgetent(), this routine will turn - * the pipe separated list of names in the buffer into an array - * of pointers to null terminated names. We toss out any bad, - * duplicate, or verbose names (names with spaces). - */ - -static char *name_unknown = "UNKNOWN"; -static char *unknown[] = { 0, 0 }; - -static char ** -mklist(char *buf, char *name) -{ - int n; - char c, *cp, **argvp, *cp2, **argv, **avt; - - if (name) { - if ((int)strlen(name) > 40) { - name = 0; - unknown[0] = name_unknown; - } else { - unknown[0] = name; - strupr(name); - } - } else - unknown[0] = name_unknown; - /* - * Count up the number of names. - */ - for (n = 1, cp = buf; *cp && *cp != ':'; cp++) { - if (*cp == '|') - n++; - } - /* - * Allocate an array to put the name pointers into - */ - argv = (char **)malloc((n+3)*sizeof(char *)); - if (argv == 0) - return(unknown); - - /* - * Fill up the array of pointers to names. - */ - *argv = 0; - argvp = argv+1; - n = 0; - for (cp = cp2 = buf; (c = *cp); cp++) { - if (c == '|' || c == ':') { - *cp++ = '\0'; - /* - * Skip entries that have spaces or are over 40 - * characters long. If this is our environment - * name, then put it up front. Otherwise, as - * long as this is not a duplicate name (case - * insensitive) add it to the list. - */ - if (n || (cp - cp2 > 41)) - ; - else if (name && (strncasecmp(name, cp2, cp-cp2) == 0)) - *argv = cp2; - else if (is_unique(cp2, argv+1, argvp)) - *argvp++ = cp2; - if (c == ':') - break; - /* - * Skip multiple delimiters. Reset cp2 to - * the beginning of the next name. Reset n, - * the flag for names with spaces. - */ - while ((c = *cp) == '|') - cp++; - cp2 = cp; - n = 0; - } - /* - * Skip entries with spaces or non-ascii values. - * Convert lower case letters to upper case. - */ -#undef ISASCII -#define ISASCII(c) (!((c)&0x80)) - if ((c == ' ') || !ISASCII(c)) - n = 1; - else if (islower((unsigned char)c)) - *cp = toupper((unsigned char)c); - } - - /* - * Check for an old V6 2 character name. If the second - * name points to the beginning of the buffer, and is - * only 2 characters long, move it to the end of the array. - */ - if ((argv[1] == buf) && (strlen(argv[1]) == 2)) { - --argvp; - for (avt = &argv[1]; avt < argvp; avt++) - *avt = *(avt+1); - *argvp++ = buf; - } - - /* - * Duplicate last name, for TTYPE option, and null - * terminate the array. If we didn't find a match on - * our terminal name, put that name at the beginning. - */ - cp = *(argvp-1); - *argvp++ = cp; - *argvp = 0; - - if (*argv == 0) { - if (name) - *argv = name; - else { - --argvp; - for (avt = argv; avt < argvp; avt++) - *avt = *(avt+1); - } - } - if (*argv) - return(argv); - else - return(unknown); -} - -static int -is_unique(char *name, char **as, char **ae) -{ - char **ap; - int n; - - n = strlen(name) + 1; - for (ap = as; ap < ae; ap++) - if (strncasecmp(*ap, name, n) == 0) - return(0); - return (1); -} - -static char termbuf[1024]; - -static int -telnet_setupterm(const char *tname, int fd, int *errp) -{ -#ifdef HAVE_TGETENT - if (tgetent(termbuf, tname) == 1) { - termbuf[1023] = '\0'; - if (errp) - *errp = 1; - return(0); - } - if (errp) - *errp = 0; - return(-1); -#else - strlcpy(termbuf, tname, sizeof(termbuf)); - if(errp) *errp = 1; - return 0; -#endif -} - -int resettermname = 1; - -static char * -gettermname() -{ - char *tname; - static char **tnamep = 0; - static char **next; - int err; - - if (resettermname) { - resettermname = 0; - if (tnamep && tnamep != unknown) - free(tnamep); - if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) && - telnet_setupterm(tname, 1, &err) == 0) { - tnamep = mklist(termbuf, tname); - } else { - if (tname && ((int)strlen(tname) <= 40)) { - unknown[0] = tname; - strupr(tname); - } else - unknown[0] = name_unknown; - tnamep = unknown; - } - next = tnamep; - } - if (*next == 0) - next = tnamep; - return(*next++); -} -/* - * suboption() - * - * Look at the sub-option buffer, and try to be helpful to the other - * side. - * - * Currently we recognize: - * - * Terminal type, send request. - * Terminal speed (send request). - * Local flow control (is request). - * Linemode - */ - -static void -suboption() -{ - unsigned char subchar; - - printsub('<', subbuffer, SB_LEN()+2); - switch (subchar = SB_GET()) { - case TELOPT_TTYPE: - if (my_want_state_is_wont(TELOPT_TTYPE)) - return; - if (SB_EOF() || SB_GET() != TELQUAL_SEND) { - return; - } else { - char *name; - unsigned char temp[50]; - int len; - - name = gettermname(); - len = strlen(name) + 4 + 2; - if (len < NETROOM()) { - snprintf((char *)temp, sizeof(temp), - "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, - TELQUAL_IS, name, IAC, SE); - ring_supply_data(&netoring, temp, len); - printsub('>', &temp[2], len-2); - } else { - ExitString("No room in buffer for terminal type.\n", 1); - /*NOTREACHED*/ - } - } - break; - case TELOPT_TSPEED: - if (my_want_state_is_wont(TELOPT_TSPEED)) - return; - if (SB_EOF()) - return; - if (SB_GET() == TELQUAL_SEND) { - long output_speed, input_speed; - unsigned char temp[50]; - int len; - - TerminalSpeeds(&input_speed, &output_speed); - - snprintf((char *)temp, sizeof(temp), - "%c%c%c%c%u,%u%c%c", IAC, SB, TELOPT_TSPEED, - TELQUAL_IS, - (unsigned)output_speed, - (unsigned)input_speed, IAC, SE); - len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ - - if (len < NETROOM()) { - ring_supply_data(&netoring, temp, len); - printsub('>', temp+2, len - 2); - } -/*@*/ else printf("lm_will: not enough room in buffer\n"); - } - break; - case TELOPT_LFLOW: - if (my_want_state_is_wont(TELOPT_LFLOW)) - return; - if (SB_EOF()) - return; - switch(SB_GET()) { - case LFLOW_RESTART_ANY: - restartany = 1; - break; - case LFLOW_RESTART_XON: - restartany = 0; - break; - case LFLOW_ON: - localflow = 1; - break; - case LFLOW_OFF: - localflow = 0; - break; - default: - return; - } - setcommandmode(); - setconnmode(0); - break; - - case TELOPT_LINEMODE: - if (my_want_state_is_wont(TELOPT_LINEMODE)) - return; - if (SB_EOF()) - return; - switch (SB_GET()) { - case WILL: - lm_will(subpointer, SB_LEN()); - break; - case WONT: - lm_wont(subpointer, SB_LEN()); - break; - case DO: - lm_do(subpointer, SB_LEN()); - break; - case DONT: - lm_dont(subpointer, SB_LEN()); - break; - case LM_SLC: - slc(subpointer, SB_LEN()); - break; - case LM_MODE: - lm_mode(subpointer, SB_LEN(), 0); - break; - default: - break; - } - break; - -#ifdef OLD_ENVIRON - case TELOPT_OLD_ENVIRON: -#endif - case TELOPT_NEW_ENVIRON: - if (SB_EOF()) - return; - switch(SB_PEEK()) { - case TELQUAL_IS: - case TELQUAL_INFO: - if (my_want_state_is_dont(subchar)) - return; - break; - case TELQUAL_SEND: - if (my_want_state_is_wont(subchar)) { - return; - } - break; - default: - return; - } - env_opt(subpointer, SB_LEN()); - break; - - case TELOPT_XDISPLOC: - if (my_want_state_is_wont(TELOPT_XDISPLOC)) - return; - if (SB_EOF()) - return; - if (SB_GET() == TELQUAL_SEND) { - unsigned char temp[50], *dp; - int len; - - if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) { - /* - * Something happened, we no longer have a DISPLAY - * variable. So, turn off the option. - */ - send_wont(TELOPT_XDISPLOC, 1); - break; - } - snprintf((char *)temp, sizeof(temp), - "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC, - TELQUAL_IS, dp, IAC, SE); - len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ - - if (len < NETROOM()) { - ring_supply_data(&netoring, temp, len); - printsub('>', temp+2, len - 2); - } -/*@*/ else printf("lm_will: not enough room in buffer\n"); - } - break; - -#if defined(AUTHENTICATION) - case TELOPT_AUTHENTICATION: { - if (!autologin) - break; - if (SB_EOF()) - return; - switch(SB_GET()) { - case TELQUAL_IS: - if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) - return; - auth_is(subpointer, SB_LEN()); - break; - case TELQUAL_SEND: - if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) - return; - auth_send(subpointer, SB_LEN()); - break; - case TELQUAL_REPLY: - if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) - return; - auth_reply(subpointer, SB_LEN()); - break; - case TELQUAL_NAME: - if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) - return; - auth_name(subpointer, SB_LEN()); - break; - } - } - break; -#endif -#if defined(ENCRYPTION) - case TELOPT_ENCRYPT: - if (SB_EOF()) - return; - switch(SB_GET()) { - case ENCRYPT_START: - if (my_want_state_is_dont(TELOPT_ENCRYPT)) - return; - encrypt_start(subpointer, SB_LEN()); - break; - case ENCRYPT_END: - if (my_want_state_is_dont(TELOPT_ENCRYPT)) - return; - encrypt_end(); - break; - case ENCRYPT_SUPPORT: - if (my_want_state_is_wont(TELOPT_ENCRYPT)) - return; - encrypt_support(subpointer, SB_LEN()); - break; - case ENCRYPT_REQSTART: - if (my_want_state_is_wont(TELOPT_ENCRYPT)) - return; - encrypt_request_start(subpointer, SB_LEN()); - break; - case ENCRYPT_REQEND: - if (my_want_state_is_wont(TELOPT_ENCRYPT)) - return; - /* - * We can always send an REQEND so that we cannot - * get stuck encrypting. We should only get this - * if we have been able to get in the correct mode - * anyhow. - */ - encrypt_request_end(); - break; - case ENCRYPT_IS: - if (my_want_state_is_dont(TELOPT_ENCRYPT)) - return; - encrypt_is(subpointer, SB_LEN()); - break; - case ENCRYPT_REPLY: - if (my_want_state_is_wont(TELOPT_ENCRYPT)) - return; - encrypt_reply(subpointer, SB_LEN()); - break; - case ENCRYPT_ENC_KEYID: - if (my_want_state_is_dont(TELOPT_ENCRYPT)) - return; - encrypt_enc_keyid(subpointer, SB_LEN()); - break; - case ENCRYPT_DEC_KEYID: - if (my_want_state_is_wont(TELOPT_ENCRYPT)) - return; - encrypt_dec_keyid(subpointer, SB_LEN()); - break; - default: - break; - } - break; -#endif - default: - break; - } -} - -static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE }; - -void -lm_will(unsigned char *cmd, int len) -{ - if (len < 1) { -/*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */ - return; - } - switch(cmd[0]) { - case LM_FORWARDMASK: /* We shouldn't ever get this... */ - default: - str_lm[3] = DONT; - str_lm[4] = cmd[0]; - if (NETROOM() > sizeof(str_lm)) { - ring_supply_data(&netoring, str_lm, sizeof(str_lm)); - printsub('>', &str_lm[2], sizeof(str_lm)-2); - } -/*@*/ else printf("lm_will: not enough room in buffer\n"); - break; - } -} - -void -lm_wont(unsigned char *cmd, int len) -{ - if (len < 1) { -/*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */ - return; - } - switch(cmd[0]) { - case LM_FORWARDMASK: /* We shouldn't ever get this... */ - default: - /* We are always DONT, so don't respond */ - return; - } -} - -void -lm_do(unsigned char *cmd, int len) -{ - if (len < 1) { -/*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */ - return; - } - switch(cmd[0]) { - case LM_FORWARDMASK: - default: - str_lm[3] = WONT; - str_lm[4] = cmd[0]; - if (NETROOM() > sizeof(str_lm)) { - ring_supply_data(&netoring, str_lm, sizeof(str_lm)); - printsub('>', &str_lm[2], sizeof(str_lm)-2); - } -/*@*/ else printf("lm_do: not enough room in buffer\n"); - break; - } -} - -void -lm_dont(unsigned char *cmd, int len) -{ - if (len < 1) { -/*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */ - return; - } - switch(cmd[0]) { - case LM_FORWARDMASK: - default: - /* we are always WONT, so don't respond */ - break; - } -} - -static unsigned char str_lm_mode[] = { - IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE -}; - -void -lm_mode(unsigned char *cmd, int len, int init) -{ - if (len != 1) - return; - if ((linemode&MODE_MASK&~MODE_ACK) == *cmd) - return; - if (*cmd&MODE_ACK) - return; - linemode = *cmd&(MODE_MASK&~MODE_ACK); - str_lm_mode[4] = linemode; - if (!init) - str_lm_mode[4] |= MODE_ACK; - if (NETROOM() > sizeof(str_lm_mode)) { - ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode)); - printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2); - } -/*@*/ else printf("lm_mode: not enough room in buffer\n"); - setconnmode(0); /* set changed mode */ -} - - - -/* - * slc() - * Handle special character suboption of LINEMODE. - */ - -struct spc { - cc_t val; - cc_t *valp; - char flags; /* Current flags & level */ - char mylevel; /* Maximum level & flags */ -} spc_data[NSLC+1]; - -#define SLC_IMPORT 0 -#define SLC_EXPORT 1 -#define SLC_RVALUE 2 -static int slc_mode = SLC_EXPORT; - -void -slc_init() -{ - struct spc *spcp; - - localchars = 1; - for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) { - spcp->val = 0; - spcp->valp = 0; - spcp->flags = spcp->mylevel = SLC_NOSUPPORT; - } - -#define initfunc(func, flags) { \ - spcp = &spc_data[func]; \ - if ((spcp->valp = tcval(func))) { \ - spcp->val = *spcp->valp; \ - spcp->mylevel = SLC_VARIABLE|flags; \ - } else { \ - spcp->val = 0; \ - spcp->mylevel = SLC_DEFAULT; \ - } \ - } - - initfunc(SLC_SYNCH, 0); - /* No BRK */ - initfunc(SLC_AO, 0); - initfunc(SLC_AYT, 0); - /* No EOR */ - initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT); - initfunc(SLC_EOF, 0); - initfunc(SLC_SUSP, SLC_FLUSHIN); - initfunc(SLC_EC, 0); - initfunc(SLC_EL, 0); - initfunc(SLC_EW, 0); - initfunc(SLC_RP, 0); - initfunc(SLC_LNEXT, 0); - initfunc(SLC_XON, 0); - initfunc(SLC_XOFF, 0); - initfunc(SLC_FORW1, 0); - initfunc(SLC_FORW2, 0); - /* No FORW2 */ - - initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT); -#undef initfunc - - if (slc_mode == SLC_EXPORT) - slc_export(); - else - slc_import(1); - -} - -void -slcstate() -{ - printf("Special characters are %s values\n", - slc_mode == SLC_IMPORT ? "remote default" : - slc_mode == SLC_EXPORT ? "local" : - "remote"); -} - -void -slc_mode_export() -{ - slc_mode = SLC_EXPORT; - if (my_state_is_will(TELOPT_LINEMODE)) - slc_export(); -} - -void -slc_mode_import(int def) -{ - slc_mode = def ? SLC_IMPORT : SLC_RVALUE; - if (my_state_is_will(TELOPT_LINEMODE)) - slc_import(def); -} - -unsigned char slc_import_val[] = { - IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE -}; -unsigned char slc_import_def[] = { - IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE -}; - -void -slc_import(int def) -{ - if (NETROOM() > sizeof(slc_import_val)) { - if (def) { - ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def)); - printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2); - } else { - ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val)); - printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2); - } - } -/*@*/ else printf("slc_import: not enough room\n"); -} - -void -slc_export() -{ - struct spc *spcp; - - TerminalDefaultChars(); - - slc_start_reply(); - for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { - if (spcp->mylevel != SLC_NOSUPPORT) { - if (spcp->val == (cc_t)(_POSIX_VDISABLE)) - spcp->flags = SLC_NOSUPPORT; - else - spcp->flags = spcp->mylevel; - if (spcp->valp) - spcp->val = *spcp->valp; - slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); - } - } - slc_end_reply(); - slc_update(); - setconnmode(1); /* Make sure the character values are set */ -} - -void -slc(unsigned char *cp, int len) -{ - struct spc *spcp; - int func,level; - - slc_start_reply(); - - for (; len >= 3; len -=3, cp +=3) { - - func = cp[SLC_FUNC]; - - if (func == 0) { - /* - * Client side: always ignore 0 function. - */ - continue; - } - if (func > NSLC) { - if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT) - slc_add_reply(func, SLC_NOSUPPORT, 0); - continue; - } - - spcp = &spc_data[func]; - - level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK); - - if ((cp[SLC_VALUE] == (unsigned char)spcp->val) && - ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) { - continue; - } - - if (level == (SLC_DEFAULT|SLC_ACK)) { - /* - * This is an error condition, the SLC_ACK - * bit should never be set for the SLC_DEFAULT - * level. Our best guess to recover is to - * ignore the SLC_ACK bit. - */ - cp[SLC_FLAGS] &= ~SLC_ACK; - } - - if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) { - spcp->val = (cc_t)cp[SLC_VALUE]; - spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */ - continue; - } - - level &= ~SLC_ACK; - - if (level <= (spcp->mylevel&SLC_LEVELBITS)) { - spcp->flags = cp[SLC_FLAGS]|SLC_ACK; - spcp->val = (cc_t)cp[SLC_VALUE]; - } - if (level == SLC_DEFAULT) { - if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT) - spcp->flags = spcp->mylevel; - else - spcp->flags = SLC_NOSUPPORT; - } - slc_add_reply(func, spcp->flags, spcp->val); - } - slc_end_reply(); - if (slc_update()) - setconnmode(1); /* set the new character values */ -} - -void -slc_check() -{ - struct spc *spcp; - - slc_start_reply(); - for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { - if (spcp->valp && spcp->val != *spcp->valp) { - spcp->val = *spcp->valp; - if (spcp->val == (cc_t)(_POSIX_VDISABLE)) - spcp->flags = SLC_NOSUPPORT; - else - spcp->flags = spcp->mylevel; - slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); - } - } - slc_end_reply(); - setconnmode(1); -} - - -unsigned char slc_reply[128]; -unsigned char const * const slc_reply_eom = &slc_reply[sizeof(slc_reply)]; -unsigned char *slc_replyp; - -void -slc_start_reply() -{ - slc_replyp = slc_reply; - *slc_replyp++ = IAC; - *slc_replyp++ = SB; - *slc_replyp++ = TELOPT_LINEMODE; - *slc_replyp++ = LM_SLC; -} - -void -slc_add_reply(unsigned char func, unsigned char flags, cc_t value) -{ - /* A sequence of up to 6 bytes my be written for this member of the SLC - * suboption list by this function. The end of negotiation command, - * which is written by slc_end_reply(), will require 2 additional - * bytes. Do not proceed unless there is sufficient space for these - * items. - */ - if (&slc_replyp[6+2] > slc_reply_eom) - return; - if ((*slc_replyp++ = func) == IAC) - *slc_replyp++ = IAC; - if ((*slc_replyp++ = flags) == IAC) - *slc_replyp++ = IAC; - if ((*slc_replyp++ = (unsigned char)value) == IAC) - *slc_replyp++ = IAC; -} - -void -slc_end_reply() -{ - int len; - - /* The end of negotiation command requires 2 bytes. */ - if (&slc_replyp[2] > slc_reply_eom) - return; - *slc_replyp++ = IAC; - *slc_replyp++ = SE; - len = slc_replyp - slc_reply; - if (len <= 6) - return; - if (NETROOM() > len) { - ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply); - printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2); - } -/*@*/else printf("slc_end_reply: not enough room\n"); -} - -int -slc_update() -{ - struct spc *spcp; - int need_update = 0; - - for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { - if (!(spcp->flags&SLC_ACK)) - continue; - spcp->flags &= ~SLC_ACK; - if (spcp->valp && (*spcp->valp != spcp->val)) { - *spcp->valp = spcp->val; - need_update = 1; - } - } - return(need_update); -} - -#ifdef OLD_ENVIRON -# define old_env_var OLD_ENV_VAR -# define old_env_value OLD_ENV_VALUE -#endif - -void -env_opt(unsigned char *buf, int len) -{ - unsigned char *ep = 0, *epc = 0; - int i; - - switch(buf[0]&0xff) { - case TELQUAL_SEND: - env_opt_start(); - if (len == 1) { - env_opt_add(NULL); - } else for (i = 1; i < len; i++) { - switch (buf[i]&0xff) { -#ifdef OLD_ENVIRON - case OLD_ENV_VAR: - case OLD_ENV_VALUE: - /* - * Although OLD_ENV_VALUE is not legal, we will - * still recognize it, just in case it is an - * old server that has VAR & VALUE mixed up... - */ - /* FALL THROUGH */ -#else - case NEW_ENV_VAR: -#endif - case ENV_USERVAR: - if (ep) { - *epc = 0; - env_opt_add(ep); - } - ep = epc = &buf[i+1]; - break; - case ENV_ESC: - i++; - /*FALL THROUGH*/ - default: - if (epc) - *epc++ = buf[i]; - break; - } - } - if (ep) { - *epc = 0; - env_opt_add(ep); - } - env_opt_end(1); - break; - - case TELQUAL_IS: - case TELQUAL_INFO: - /* Ignore for now. We shouldn't get it anyway. */ - break; - - default: - break; - } -} - -#define OPT_REPLY_SIZE (2 * SUBBUFSIZE) -unsigned char *opt_reply; -unsigned char *opt_replyp; -unsigned char *opt_replyend; - -void -env_opt_start() -{ - if (opt_reply) { - void *tmp = realloc (opt_reply, OPT_REPLY_SIZE); - if (tmp != NULL) { - opt_reply = tmp; - } else { - free (opt_reply); - opt_reply = NULL; - } - } else - opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE); - if (opt_reply == NULL) { -/*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n"); - opt_reply = opt_replyp = opt_replyend = NULL; - return; - } - opt_replyp = opt_reply; - opt_replyend = opt_reply + OPT_REPLY_SIZE; - *opt_replyp++ = IAC; - *opt_replyp++ = SB; - *opt_replyp++ = telopt_environ; - *opt_replyp++ = TELQUAL_IS; -} - -void -env_opt_start_info() -{ - env_opt_start(); - if (opt_replyp) - opt_replyp[-1] = TELQUAL_INFO; -} - -void -env_opt_add(unsigned char *ep) -{ - unsigned char *vp, c; - - if (opt_reply == NULL) /*XXX*/ - return; /*XXX*/ - - if (ep == NULL || *ep == '\0') { - /* Send user defined variables first. */ - env_default(1, 0); - while ((ep = env_default(0, 0))) - env_opt_add(ep); - - /* Now add the list of well know variables. */ - env_default(1, 1); - while ((ep = env_default(0, 1))) - env_opt_add(ep); - return; - } - vp = env_getvalue(ep); - if (opt_replyp + (vp ? 2 * strlen((char *)vp) : 0) + - 2 * strlen((char *)ep) + 6 > opt_replyend) - { - int len; - void *tmp; - opt_replyend += OPT_REPLY_SIZE; - len = opt_replyend - opt_reply; - tmp = realloc(opt_reply, len); - if (tmp == NULL) { -/*@*/ printf("env_opt_add: realloc() failed!!!\n"); - opt_reply = opt_replyp = opt_replyend = NULL; - return; - } - opt_reply = tmp; - opt_replyp = opt_reply + len - (opt_replyend - opt_replyp); - opt_replyend = opt_reply + len; - } - if (opt_welldefined((char *)ep)) { -#ifdef OLD_ENVIRON - if (telopt_environ == TELOPT_OLD_ENVIRON) - *opt_replyp++ = old_env_var; - else -#endif - *opt_replyp++ = NEW_ENV_VAR; - } else - *opt_replyp++ = ENV_USERVAR; - for (;;) { - while ((c = *ep++)) { - if (opt_replyp + (2 + 2) > opt_replyend) - return; - switch(c&0xff) { - case IAC: - *opt_replyp++ = IAC; - break; - case NEW_ENV_VAR: - case NEW_ENV_VALUE: - case ENV_ESC: - case ENV_USERVAR: - *opt_replyp++ = ENV_ESC; - break; - } - *opt_replyp++ = c; - } - if ((ep = vp)) { - if (opt_replyp + (1 + 2 + 2) > opt_replyend) - return; -#ifdef OLD_ENVIRON - if (telopt_environ == TELOPT_OLD_ENVIRON) - *opt_replyp++ = old_env_value; - else -#endif - *opt_replyp++ = NEW_ENV_VALUE; - vp = NULL; - } else - break; - } -} - -int -opt_welldefined(char *ep) -{ - if ((strcmp(ep, "USER") == 0) || - (strcmp(ep, "DISPLAY") == 0) || - (strcmp(ep, "PRINTER") == 0) || - (strcmp(ep, "SYSTEMTYPE") == 0) || - (strcmp(ep, "JOB") == 0) || - (strcmp(ep, "ACCT") == 0)) - return(1); - return(0); -} - -void -env_opt_end(int emptyok) -{ - int len; - - if (opt_replyp + 2 > opt_replyend) - return; - len = opt_replyp + 2 - opt_reply; - if (emptyok || len > 6) { - *opt_replyp++ = IAC; - *opt_replyp++ = SE; - if (NETROOM() > len) { - ring_supply_data(&netoring, opt_reply, len); - printsub('>', &opt_reply[2], len - 2); - } -/*@*/ else printf("slc_end_reply: not enough room\n"); - } - if (opt_reply) { - free(opt_reply); - opt_reply = opt_replyp = opt_replyend = NULL; - } -} - - - -int -telrcv(void) -{ - int c; - int scc; - unsigned char *sbp = NULL; - int count; - int returnValue = 0; - - scc = 0; - count = 0; - while (TTYROOM() > 2) { - if (scc == 0) { - if (count) { - ring_consumed(&netiring, count); - returnValue = 1; - count = 0; - } - sbp = netiring.consume; - scc = ring_full_consecutive(&netiring); - if (scc == 0) { - /* No more data coming in */ - break; - } - } - - c = *sbp++ & 0xff, scc--; count++; -#if defined(ENCRYPTION) - if (decrypt_input) - c = (*decrypt_input)(c); -#endif - - switch (telrcv_state) { - - case TS_CR: - telrcv_state = TS_DATA; - if (c == '\0') { - break; /* Ignore \0 after CR */ - } - else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) { - TTYADD(c); - break; - } - /* Else, fall through */ - - case TS_DATA: - if (c == IAC) { - telrcv_state = TS_IAC; - break; - } - /* - * The 'crmod' hack (see following) is needed - * since we can't set CRMOD on output only. - * Machines like MULTICS like to send \r without - * \n; since we must turn off CRMOD to get proper - * input, the mapping is done here (sigh). - */ - if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) { - if (scc > 0) { - c = *sbp&0xff; -#if defined(ENCRYPTION) - if (decrypt_input) - c = (*decrypt_input)(c); -#endif - if (c == 0) { - sbp++, scc--; count++; - /* a "true" CR */ - TTYADD('\r'); - } else if (my_want_state_is_dont(TELOPT_ECHO) && - (c == '\n')) { - sbp++, scc--; count++; - TTYADD('\n'); - } else { -#if defined(ENCRYPTION) - if (decrypt_input) - (*decrypt_input)(-1); -#endif - - TTYADD('\r'); - if (crmod) { - TTYADD('\n'); - } - } - } else { - telrcv_state = TS_CR; - TTYADD('\r'); - if (crmod) { - TTYADD('\n'); - } - } - } else { - TTYADD(c); - } - continue; - - case TS_IAC: -process_iac: - switch (c) { - - case WILL: - telrcv_state = TS_WILL; - continue; - - case WONT: - telrcv_state = TS_WONT; - continue; - - case DO: - telrcv_state = TS_DO; - continue; - - case DONT: - telrcv_state = TS_DONT; - continue; - - case DM: - /* - * We may have missed an urgent notification, - * so make sure we flush whatever is in the - * buffer currently. - */ - printoption("RCVD", IAC, DM); - SYNCHing = 1; - ttyflush(1); - SYNCHing = stilloob(); - settimer(gotDM); - break; - - case SB: - SB_CLEAR(); - telrcv_state = TS_SB; - continue; - - - case IAC: - TTYADD(IAC); - break; - - case NOP: - case GA: - default: - printoption("RCVD", IAC, c); - break; - } - telrcv_state = TS_DATA; - continue; - - case TS_WILL: - printoption("RCVD", WILL, c); - willoption(c); - telrcv_state = TS_DATA; - continue; - - case TS_WONT: - printoption("RCVD", WONT, c); - wontoption(c); - telrcv_state = TS_DATA; - continue; - - case TS_DO: - printoption("RCVD", DO, c); - dooption(c); - if (c == TELOPT_NAWS) { - sendnaws(); - } else if (c == TELOPT_LFLOW) { - localflow = 1; - setcommandmode(); - setconnmode(0); - } - telrcv_state = TS_DATA; - continue; - - case TS_DONT: - printoption("RCVD", DONT, c); - dontoption(c); - flushline = 1; - setconnmode(0); /* set new tty mode (maybe) */ - telrcv_state = TS_DATA; - continue; - - case TS_SB: - if (c == IAC) { - telrcv_state = TS_SE; - } else { - SB_ACCUM(c); - } - continue; - - case TS_SE: - if (c != SE) { - if (c != IAC) { - /* - * This is an error. We only expect to get - * "IAC IAC" or "IAC SE". Several things may - * have happened. An IAC was not doubled, the - * IAC SE was left off, or another option got - * inserted into the suboption are all possibilities. - * If we assume that the IAC was not doubled, - * and really the IAC SE was left off, we could - * get into an infinite loop here. So, instead, - * we terminate the suboption, and process the - * partial suboption if we can. - */ - SB_ACCUM(IAC); - SB_ACCUM(c); - subpointer -= 2; - SB_TERM(); - - printoption("In SUBOPTION processing, RCVD", IAC, c); - suboption(); /* handle sub-option */ - telrcv_state = TS_IAC; - goto process_iac; - } - SB_ACCUM(c); - telrcv_state = TS_SB; - } else { - SB_ACCUM(IAC); - SB_ACCUM(SE); - subpointer -= 2; - SB_TERM(); - suboption(); /* handle sub-option */ - telrcv_state = TS_DATA; - } - } - } - if (count) - ring_consumed(&netiring, count); - return returnValue||count; -} - -static int bol = 1, local = 0; - -int -rlogin_susp(void) -{ - if (local) { - local = 0; - bol = 1; - command(0, "z\n", 2); - return(1); - } - return(0); -} - -static int -telsnd() -{ - int tcc; - int count; - int returnValue = 0; - unsigned char *tbp = NULL; - - tcc = 0; - count = 0; - while (NETROOM() > 2) { - int sc; - int c; - - if (tcc == 0) { - if (count) { - ring_consumed(&ttyiring, count); - returnValue = 1; - count = 0; - } - tbp = ttyiring.consume; - tcc = ring_full_consecutive(&ttyiring); - if (tcc == 0) { - break; - } - } - c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; - if (rlogin != _POSIX_VDISABLE) { - if (bol) { - bol = 0; - if (sc == rlogin) { - local = 1; - continue; - } - } else if (local) { - local = 0; - if (sc == '.' || c == termEofChar) { - bol = 1; - command(0, "close\n", 6); - continue; - } - if (sc == termSuspChar) { - bol = 1; - command(0, "z\n", 2); - continue; - } - if (sc == escape) { - command(0, (char *)tbp, tcc); - bol = 1; - count += tcc; - tcc = 0; - flushline = 1; - break; - } - if (sc != rlogin) { - ++tcc; - --tbp; - --count; - c = sc = rlogin; - } - } - if ((sc == '\n') || (sc == '\r')) - bol = 1; - } else if (sc == escape) { - /* - * Double escape is a pass through of a single escape character. - */ - if (tcc && strip(*tbp) == escape) { - tbp++; - tcc--; - count++; - bol = 0; - } else { - command(0, (char *)tbp, tcc); - bol = 1; - count += tcc; - tcc = 0; - flushline = 1; - break; - } - } else - bol = 0; -#ifdef KLUDGELINEMODE - if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) { - if (tcc > 0 && strip(*tbp) == echoc) { - tcc--; tbp++; count++; - } else { - dontlecho = !dontlecho; - settimer(echotoggle); - setconnmode(0); - flushline = 1; - break; - } - } -#endif - if (MODE_LOCAL_CHARS(globalmode)) { - if (TerminalSpecialChars(sc) == 0) { - bol = 1; - break; - } - } - if (my_want_state_is_wont(TELOPT_BINARY)) { - switch (c) { - case '\n': - /* - * If we are in CRMOD mode (\r ==> \n) - * on our local machine, then probably - * a newline (unix) is CRLF (TELNET). - */ - if (MODE_LOCAL_CHARS(globalmode)) { - NETADD('\r'); - } - NETADD('\n'); - bol = flushline = 1; - break; - case '\r': - if (!crlf) { - NET2ADD('\r', '\0'); - } else { - NET2ADD('\r', '\n'); - } - bol = flushline = 1; - break; - case IAC: - NET2ADD(IAC, IAC); - break; - default: - NETADD(c); - break; - } - } else if (c == IAC) { - NET2ADD(IAC, IAC); - } else { - NETADD(c); - } - } - if (count) - ring_consumed(&ttyiring, count); - return returnValue||count; /* Non-zero if we did anything */ -} - -/* - * Scheduler() - * - * Try to do something. - * - * If we do something useful, return 1; else return 0. - * - */ - - - int -Scheduler(int block) /* should we block in the select ? */ -{ - /* One wants to be a bit careful about setting returnValue - * to one, since a one implies we did some useful work, - * and therefore probably won't be called to block next - * time (TN3270 mode only). - */ - int returnValue; - int netin, netout, netex, ttyin, ttyout; - - /* Decide which rings should be processed */ - - netout = ring_full_count(&netoring) && - (flushline || - (my_want_state_is_wont(TELOPT_LINEMODE) -#ifdef KLUDGELINEMODE - && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA)) -#endif - ) || - my_want_state_is_will(TELOPT_BINARY)); - ttyout = ring_full_count(&ttyoring); - - ttyin = ring_empty_count(&ttyiring); - - netin = !ISend && ring_empty_count(&netiring); - - netex = !SYNCHing; - - /* If we have seen a signal recently, reset things */ - - if (scheduler_lockout_tty) { - ttyin = ttyout = 0; - } - - /* Call to system code to process rings */ - - returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); - - /* Now, look at the input rings, looking for work to do. */ - - if (ring_full_count(&ttyiring)) { - returnValue |= telsnd(); - } - - if (ring_full_count(&netiring)) { - returnValue |= telrcv(); - } - return returnValue; -} - -extern int auth_has_failed; /* XXX should be somewhere else */ - -/* - * Select from tty and network... - */ -void -my_telnet(char *user) -{ - int printed_encrypt = 0; - - sys_telnet_init(); - -#if defined(AUTHENTICATION) || defined(ENCRYPTION) - { - static char local_host[256] = { 0 }; - - if (!local_host[0]) { - /* XXX - should be k_gethostname? */ - gethostname(local_host, sizeof(local_host)); - local_host[sizeof(local_host)-1] = 0; - } - auth_encrypt_init(local_host, hostname, "TELNET", 0); - auth_encrypt_user(user); - } -#endif - if (telnetport) { -#if defined(AUTHENTICATION) - if (autologin) - send_will(TELOPT_AUTHENTICATION, 1); -#endif -#if defined(ENCRYPTION) - send_do(TELOPT_ENCRYPT, 1); - send_will(TELOPT_ENCRYPT, 1); -#endif - send_do(TELOPT_SGA, 1); - send_will(TELOPT_TTYPE, 1); - send_will(TELOPT_NAWS, 1); - send_will(TELOPT_TSPEED, 1); - send_will(TELOPT_LFLOW, 1); - send_will(TELOPT_LINEMODE, 1); - send_will(TELOPT_NEW_ENVIRON, 1); - send_do(TELOPT_STATUS, 1); - if (env_getvalue((unsigned char *)"DISPLAY")) - send_will(TELOPT_XDISPLOC, 1); - if (binary) - tel_enter_binary(binary); - } - -#ifdef ENCRYPTION - /* - * Note: we assume a tie to the authentication option here. This - * is necessary so that authentication fails, we don't spin - * forever. - */ - if (telnetport && wantencryption) { - time_t timeout = time(0) + 60; - - send_do(TELOPT_ENCRYPT, 1); - send_will(TELOPT_ENCRYPT, 1); - while (1) { - if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) { - if (wantencryption == -1) { - break; - } else { - printf("\nServer refused to negotiate authentication,\n"); - printf("which is required for encryption.\n"); - Exit(1); - } - } - if (auth_has_failed) { - printf("\nAuthentication negotiation has failed,\n"); - printf("which is required for encryption.\n"); - Exit(1); - } - if (my_want_state_is_dont(TELOPT_ENCRYPT) || - my_want_state_is_wont(TELOPT_ENCRYPT)) { - printf("\nServer refused to negotiate encryption.\n"); - Exit(1); - } - if (encrypt_is_encrypting()) - break; - if (time(0) > timeout) { - printf("\nEncryption could not be enabled.\n"); - Exit(1); - } - if (printed_encrypt == 0) { - printed_encrypt = 1; - printf("Waiting for encryption to be negotiated...\n"); - /* - * Turn on MODE_TRAPSIG and then turn off localchars - * so that ^C will cause telnet to exit. - */ - TerminalNewMode(getconnmode()|MODE_TRAPSIG); - intr_waiting = 1; - } - if (intr_happened) { - printf("\nUser interrupt.\n"); - Exit(1); - } - if (telnet_spin()) { - printf("\nServer disconnected.\n"); - Exit(1); - } - - } - if (printed_encrypt) { - printf("Encryption negotiated.\n"); - intr_waiting = 0; - setconnmode(0); - } - } -#endif - - for (;;) { - int schedValue; - - while ((schedValue = Scheduler(0)) != 0) { - if (schedValue == -1) { - setcommandmode(); - return; - } - } - - if (Scheduler(1) == -1) { - setcommandmode(); - return; - } - } -} - -/* - * netclear() - * - * We are about to do a TELNET SYNCH operation. Clear - * the path to the network. - * - * Things are a bit tricky since we may have sent the first - * byte or so of a previous TELNET command into the network. - * So, we have to scan the network buffer from the beginning - * until we are up to where we want to be. - * - * A side effect of what we do, just to keep things - * simple, is to clear the urgent data pointer. The principal - * caller should be setting the urgent data pointer AFTER calling - * us in any case. - */ - -static void -netclear() -{ -#if 0 /* XXX */ - char *thisitem, *next; - char *good; -#define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ - ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) - - thisitem = netobuf; - - while ((next = nextitem(thisitem)) <= netobuf.send) { - thisitem = next; - } - - /* Now, thisitem is first before/at boundary. */ - - good = netobuf; /* where the good bytes go */ - - while (netoring.add > thisitem) { - if (wewant(thisitem)) { - int length; - - next = thisitem; - do { - next = nextitem(next); - } while (wewant(next) && (nfrontp > next)); - length = next-thisitem; - memmove(good, thisitem, length); - good += length; - thisitem = next; - } else { - thisitem = nextitem(thisitem); - } - } - -#endif /* 0 */ -} - -/* - * These routines add various telnet commands to the data stream. - */ - -static void -doflush() -{ - NET2ADD(IAC, DO); - NETADD(TELOPT_TM); - flushline = 1; - flushout = 1; - ttyflush(1); /* Flush/drop output */ - /* do printoption AFTER flush, otherwise the output gets tossed... */ - printoption("SENT", DO, TELOPT_TM); -} - -void -xmitAO(void) -{ - NET2ADD(IAC, AO); - printoption("SENT", IAC, AO); - if (autoflush) { - doflush(); - } -} - - -void -xmitEL(void) -{ - NET2ADD(IAC, EL); - printoption("SENT", IAC, EL); -} - -void -xmitEC(void) -{ - NET2ADD(IAC, EC); - printoption("SENT", IAC, EC); -} - - -int -dosynch() -{ - netclear(); /* clear the path to the network */ - NETADD(IAC); - setneturg(); - NETADD(DM); - printoption("SENT", IAC, DM); - return 1; -} - -int want_status_response = 0; - -int -get_status() -{ - unsigned char tmp[16]; - unsigned char *cp; - - if (my_want_state_is_dont(TELOPT_STATUS)) { - printf("Remote side does not support STATUS option\n"); - return 0; - } - cp = tmp; - - *cp++ = IAC; - *cp++ = SB; - *cp++ = TELOPT_STATUS; - *cp++ = TELQUAL_SEND; - *cp++ = IAC; - *cp++ = SE; - if (NETROOM() >= cp - tmp) { - ring_supply_data(&netoring, tmp, cp-tmp); - printsub('>', tmp+2, cp - tmp - 2); - } - ++want_status_response; - return 1; -} - -void -intp(void) -{ - NET2ADD(IAC, IP); - printoption("SENT", IAC, IP); - flushline = 1; - if (autoflush) { - doflush(); - } - if (autosynch) { - dosynch(); - } -} - -void -sendbrk(void) -{ - NET2ADD(IAC, BREAK); - printoption("SENT", IAC, BREAK); - flushline = 1; - if (autoflush) { - doflush(); - } - if (autosynch) { - dosynch(); - } -} - -void -sendabort(void) -{ - NET2ADD(IAC, ABORT); - printoption("SENT", IAC, ABORT); - flushline = 1; - if (autoflush) { - doflush(); - } - if (autosynch) { - dosynch(); - } -} - -void -sendsusp(void) -{ - NET2ADD(IAC, SUSP); - printoption("SENT", IAC, SUSP); - flushline = 1; - if (autoflush) { - doflush(); - } - if (autosynch) { - dosynch(); - } -} - -void -sendeof(void) -{ - NET2ADD(IAC, xEOF); - printoption("SENT", IAC, xEOF); -} - -void -sendayt(void) -{ - NET2ADD(IAC, AYT); - printoption("SENT", IAC, AYT); -} - -/* - * Send a window size update to the remote system. - */ - -void -sendnaws() -{ - long rows, cols; - unsigned char tmp[16]; - unsigned char *cp; - - if (my_state_is_wont(TELOPT_NAWS)) - return; - -#undef PUTSHORT -#define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \ - if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; } - - if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */ - return; - } - - cp = tmp; - - *cp++ = IAC; - *cp++ = SB; - *cp++ = TELOPT_NAWS; - PUTSHORT(cp, cols); - PUTSHORT(cp, rows); - *cp++ = IAC; - *cp++ = SE; - if (NETROOM() >= cp - tmp) { - ring_supply_data(&netoring, tmp, cp-tmp); - printsub('>', tmp+2, cp - tmp - 2); - } -} - -void -tel_enter_binary(int rw) -{ - if (rw&1) - send_do(TELOPT_BINARY, 1); - if (rw&2) - send_will(TELOPT_BINARY, 1); -} - -void -tel_leave_binary(int rw) -{ - if (rw&1) - send_dont(TELOPT_BINARY, 1); - if (rw&2) - send_wont(TELOPT_BINARY, 1); -} diff --git a/appl/telnet/telnet/telnet_locl.h b/appl/telnet/telnet/telnet_locl.h deleted file mode 100644 index 1d387e7d7..000000000 --- a/appl/telnet/telnet/telnet_locl.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 1995 - 2000 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* $Id$ */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#ifdef HAVE_SIGNAL_H -#include -#endif -#include -#include -#ifdef HAVE_BSDSETJMP_H -#include -#endif - -#ifdef HAVE_SYS_TYPES_H -#include -#endif - -#ifdef HAVE_UNISTD_H -#include -#endif - -/* termios.h *must* be included before curses.h, but not on Solaris 9, - at least, where we end up with - "/usr/include/term.h", line 1060: incomplete struct/union/enum termio: Ottyb -*/ -#if defined HAVE_TERMIOS_H && !defined __sun -#include -#endif - -#if defined(HAVE_CURSES_H) -#include -#ifdef HAVE_TERM_H -#include -#endif -#elif defined(HAVE_TERMCAP_H) -#include -#endif - -#if defined(HAVE_SYS_TERMIO_H) && !defined(HAVE_TERMIOS_H) -#include -#endif - -#ifdef HAVE_FCNTL_H -#include -#endif - -#ifdef HAVE_NETDB_H -#include -#endif - -#ifdef HAVE_PWD_H -#include -#endif - -#ifdef HAVE_SYS_SELECT_H -#include -#endif -#ifdef TIME_WITH_SYS_TIME -#include -#include -#elif defined(HAVE_SYS_TIME_H) -#include -#else -#include -#endif -#ifdef HAVE_SYS_PARAM_H -#include -#endif -/* not with SunOS 4 */ -#if defined(HAVE_SYS_IOCTL_H) && SunOS != 40 -#include -#endif -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif /* HAVE_SYS_RESOURCE_H */ -#ifdef HAVE_SYS_WAIT_H -#include -#endif -#ifdef HAVE_SYS_FILIO_H -#include -#endif -#ifdef HAVE_SYS_FILE_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETINET_IN6_H -#include -#endif -#ifdef HAVE_NETINET6_IN6_H -#include -#endif - -#ifdef HAVE_NETINET_IN_SYSTM_H -#include -#endif -#ifdef HAVE_NETINET_IP_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#ifdef _AIX -struct sockaddr_dl; /* AIX fun */ -struct ether_addr; -#endif -#include -#endif - -#ifdef HAVE_ARPA_TELNET_H -#include -#endif - -#ifdef SOCKS -#include -#endif - -#if defined(AUTHENTICATION) || defined(ENCRYPTION) -#include -#include -#endif -#include -#include - -#define LINEMODE -#ifndef KLUDGELINEMODE -#define KLUDGELINEMODE -#endif - -#include -#include - -#include "ring.h" -#include "externs.h" -#include "defines.h" -#include "types.h" - -/* prototypes */ - diff --git a/appl/telnet/telnet/terminal.c b/appl/telnet/telnet/terminal.c deleted file mode 100644 index f9f001711..000000000 --- a/appl/telnet/telnet/terminal.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (c) 1988, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "telnet_locl.h" - -RCSID("$Id$"); - -Ring ttyoring, ttyiring; -unsigned char ttyobuf[2*BUFSIZ], ttyibuf[BUFSIZ]; - -int termdata; /* Debugging flag */ - -# ifndef VDISCARD -cc_t termFlushChar; -# endif -# ifndef VLNEXT -cc_t termLiteralNextChar; -# endif -# ifndef VSUSP -cc_t termSuspChar; -# endif -# ifndef VWERASE -cc_t termWerasChar; -# endif -# ifndef VREPRINT -cc_t termRprntChar; -# endif -# ifndef VSTART -cc_t termStartChar; -# endif -# ifndef VSTOP -cc_t termStopChar; -# endif -# ifndef VEOL -cc_t termForw1Char; -# endif -# ifndef VEOL2 -cc_t termForw2Char; -# endif -# ifndef VSTATUS -cc_t termAytChar; -# endif - -/* - * initialize the terminal data structures. - */ - -void -init_terminal(void) -{ - if (ring_init(&ttyoring, ttyobuf, sizeof ttyobuf) != 1) { - exit(1); - } - if (ring_init(&ttyiring, ttyibuf, sizeof ttyibuf) != 1) { - exit(1); - } - autoflush = TerminalAutoFlush(); -} - - -/* - * Send as much data as possible to the terminal. - * - * Return value: - * -1: No useful work done, data waiting to go out. - * 0: No data was waiting, so nothing was done. - * 1: All waiting data was written out. - * n: All data - n was written out. - */ - - -int -ttyflush(int drop) -{ - int n, n0, n1; - - n0 = ring_full_count(&ttyoring); - if ((n1 = n = ring_full_consecutive(&ttyoring)) > 0) { - if (drop) { - TerminalFlushOutput(); - /* we leave 'n' alone! */ - } else { - n = TerminalWrite((char *)ttyoring.consume, n); - } - } - if (n > 0) { - if (termdata && n) { - Dump('>', ttyoring.consume, n); - } - /* - * If we wrote everything, and the full count is - * larger than what we wrote, then write the - * rest of the buffer. - */ - if (n1 == n && n0 > n) { - n1 = n0 - n; - if (!drop) - n1 = TerminalWrite((char *)ttyoring.bottom, n1); - if (n1 > 0) - n += n1; - } - ring_consumed(&ttyoring, n); - } - if (n < 0) - return -1; - if (n == n0) { - if (n0) - return -1; - return 0; - } - return n0 - n + 1; -} - - -/* - * These routines decides on what the mode should be (based on the values - * of various global variables). - */ - - -int -getconnmode(void) -{ - int mode = 0; - - if (my_want_state_is_dont(TELOPT_ECHO)) - mode |= MODE_ECHO; - - if (localflow) - mode |= MODE_FLOW; - - if ((eight & 1) || my_want_state_is_will(TELOPT_BINARY)) - mode |= MODE_INBIN; - - if (eight & 2) - mode |= MODE_OUT8; - if (his_want_state_is_will(TELOPT_BINARY)) - mode |= MODE_OUTBIN; - -#ifdef KLUDGELINEMODE - if (kludgelinemode) { - if (my_want_state_is_dont(TELOPT_SGA)) { - mode |= (MODE_TRAPSIG|MODE_EDIT); - if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) { - mode &= ~MODE_ECHO; - } - } - return(mode); - } -#endif - if (my_want_state_is_will(TELOPT_LINEMODE)) - mode |= linemode; - return(mode); -} - - void -setconnmode(force) - int force; -{ -#ifdef ENCRYPTION - static int enc_passwd = 0; -#endif - int newmode; - - newmode = getconnmode()|(force?MODE_FORCE:0); - - TerminalNewMode(newmode); - -#ifdef ENCRYPTION - if ((newmode & (MODE_ECHO|MODE_EDIT)) == MODE_EDIT) { - if (my_want_state_is_will(TELOPT_ENCRYPT) - && (enc_passwd == 0) && !encrypt_output) { - encrypt_request_start(0, 0); - enc_passwd = 1; - } - } else { - if (enc_passwd) { - encrypt_request_end(); - enc_passwd = 0; - } - } -#endif - -} - - - void -setcommandmode() -{ - TerminalNewMode(-1); -} diff --git a/appl/telnet/telnet/utilities.c b/appl/telnet/telnet/utilities.c deleted file mode 100644 index c2b84f713..000000000 --- a/appl/telnet/telnet/utilities.c +++ /dev/null @@ -1,865 +0,0 @@ -/* - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#define TELOPTS -#define TELCMDS -#define SLC_NAMES - -#include "telnet_locl.h" - -RCSID("$Id$"); - -FILE *NetTrace = 0; /* Not in bss, since needs to stay */ -int prettydump; - -/* - * SetSockOpt() - * - * Compensate for differences in 4.2 and 4.3 systems. - */ - -int -SetSockOpt(int fd, int level, int option, int yesno) -{ -#ifdef HAVE_SETSOCKOPT -#ifndef NOT43 - return setsockopt(fd, level, option, - (void *)&yesno, sizeof yesno); -#else /* NOT43 */ - if (yesno == 0) { /* Can't do that in 4.2! */ - fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n", - option); - return -1; - } - return setsockopt(fd, level, option, 0, 0); -#endif /* NOT43 */ -#else - return -1; -#endif -} - -/* - * The following are routines used to print out debugging information. - */ - -char NetTraceFile[256] = "(standard output)"; - -void -SetNetTrace(char *file) -{ - if (NetTrace && NetTrace != stdout) - fclose(NetTrace); - if (file && (strcmp(file, "-") != 0)) { - NetTrace = fopen(file, "w"); - if (NetTrace) { - strlcpy(NetTraceFile, file, sizeof(NetTraceFile)); - return; - } - fprintf(stderr, "Cannot open %s.\n", file); - } - NetTrace = stdout; - strlcpy(NetTraceFile, "(standard output)", sizeof(NetTraceFile)); -} - -void -Dump(char direction, unsigned char *buffer, int length) -{ -# define BYTES_PER_LINE 32 - unsigned char *pThis; - int offset; - - offset = 0; - - while (length) { - /* print one line */ - fprintf(NetTrace, "%c 0x%x\t", direction, offset); - pThis = buffer; - if (prettydump) { - buffer = buffer + min(length, BYTES_PER_LINE/2); - while (pThis < buffer) { - fprintf(NetTrace, "%c%.2x", - (((*pThis)&0xff) == 0xff) ? '*' : ' ', - (*pThis)&0xff); - pThis++; - } - length -= BYTES_PER_LINE/2; - offset += BYTES_PER_LINE/2; - } else { - buffer = buffer + min(length, BYTES_PER_LINE); - while (pThis < buffer) { - fprintf(NetTrace, "%.2x", (*pThis)&0xff); - pThis++; - } - length -= BYTES_PER_LINE; - offset += BYTES_PER_LINE; - } - if (NetTrace == stdout) { - fprintf(NetTrace, "\r\n"); - } else { - fprintf(NetTrace, "\n"); - } - if (length < 0) { - fflush(NetTrace); - return; - } - /* find next unique line */ - } - fflush(NetTrace); -} - - -void -printoption(char *direction, int cmd, int option) -{ - if (!showoptions) - return; - if (cmd == IAC) { - if (TELCMD_OK(option)) - fprintf(NetTrace, "%s IAC %s", direction, TELCMD(option)); - else - fprintf(NetTrace, "%s IAC %d", direction, option); - } else { - char *fmt; - fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" : - (cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0; - if (fmt) { - fprintf(NetTrace, "%s %s ", direction, fmt); - if (TELOPT_OK(option)) - fprintf(NetTrace, "%s", TELOPT(option)); - else if (option == TELOPT_EXOPL) - fprintf(NetTrace, "EXOPL"); - else - fprintf(NetTrace, "%d", option); - } else - fprintf(NetTrace, "%s %d %d", direction, cmd, option); - } - if (NetTrace == stdout) { - fprintf(NetTrace, "\r\n"); - fflush(NetTrace); - } else { - fprintf(NetTrace, "\n"); - } - return; -} - -void -optionstatus(void) -{ - int i; - - for (i = 0; i < 256; i++) { - if (do_dont_resp[i]) { - if (TELOPT_OK(i)) - printf("resp DO_DONT %s: %d\n", TELOPT(i), do_dont_resp[i]); - else if (TELCMD_OK(i)) - printf("resp DO_DONT %s: %d\n", TELCMD(i), do_dont_resp[i]); - else - printf("resp DO_DONT %d: %d\n", i, - do_dont_resp[i]); - if (my_want_state_is_do(i)) { - if (TELOPT_OK(i)) - printf("want DO %s\n", TELOPT(i)); - else if (TELCMD_OK(i)) - printf("want DO %s\n", TELCMD(i)); - else - printf("want DO %d\n", i); - } else { - if (TELOPT_OK(i)) - printf("want DONT %s\n", TELOPT(i)); - else if (TELCMD_OK(i)) - printf("want DONT %s\n", TELCMD(i)); - else - printf("want DONT %d\n", i); - } - } else { - if (my_state_is_do(i)) { - if (TELOPT_OK(i)) - printf(" DO %s\n", TELOPT(i)); - else if (TELCMD_OK(i)) - printf(" DO %s\n", TELCMD(i)); - else - printf(" DO %d\n", i); - } - } - if (will_wont_resp[i]) { - if (TELOPT_OK(i)) - printf("resp WILL_WONT %s: %d\n", TELOPT(i), will_wont_resp[i]); - else if (TELCMD_OK(i)) - printf("resp WILL_WONT %s: %d\n", TELCMD(i), will_wont_resp[i]); - else - printf("resp WILL_WONT %d: %d\n", - i, will_wont_resp[i]); - if (my_want_state_is_will(i)) { - if (TELOPT_OK(i)) - printf("want WILL %s\n", TELOPT(i)); - else if (TELCMD_OK(i)) - printf("want WILL %s\n", TELCMD(i)); - else - printf("want WILL %d\n", i); - } else { - if (TELOPT_OK(i)) - printf("want WONT %s\n", TELOPT(i)); - else if (TELCMD_OK(i)) - printf("want WONT %s\n", TELCMD(i)); - else - printf("want WONT %d\n", i); - } - } else { - if (my_state_is_will(i)) { - if (TELOPT_OK(i)) - printf(" WILL %s\n", TELOPT(i)); - else if (TELCMD_OK(i)) - printf(" WILL %s\n", TELCMD(i)); - else - printf(" WILL %d\n", i); - } - } - } - -} - -static void __attribute__((format (printf, 3, 4))) -qprintf(int quote, FILE *f, const char *fmt, ...) - -{ - va_list va; - if (quote) - fprintf(f, "\" "); - va_start(va, fmt); - vfprintf(f, fmt, va); - va_end(va); -} - -void -printsub(int direction, unsigned char *pointer, size_t length) -{ - int i; - unsigned char buf[512]; - - if (showoptions || direction == 0 || - (want_status_response && (pointer[0] == TELOPT_STATUS))) { - if (direction) { - fprintf(NetTrace, "%s IAC SB ", - (direction == '<')? "RCVD":"SENT"); - if (length >= 3) { - int j; - - i = pointer[length-2]; - j = pointer[length-1]; - - if (i != IAC || j != SE) { - fprintf(NetTrace, "(terminated by "); - if (TELOPT_OK(i)) - fprintf(NetTrace, "%s ", TELOPT(i)); - else if (TELCMD_OK(i)) - fprintf(NetTrace, "%s ", TELCMD(i)); - else - fprintf(NetTrace, "%d ", i); - if (TELOPT_OK(j)) - fprintf(NetTrace, "%s", TELOPT(j)); - else if (TELCMD_OK(j)) - fprintf(NetTrace, "%s", TELCMD(j)); - else - fprintf(NetTrace, "%d", j); - fprintf(NetTrace, ", not IAC SE!) "); - } - } - length -= 2; - } - if (length < 1) { - fprintf(NetTrace, "(Empty suboption??\?)"); - if (NetTrace == stdout) - fflush(NetTrace); - return; - } - switch (pointer[0]) { - case TELOPT_TTYPE: - fprintf(NetTrace, "TERMINAL-TYPE "); - switch (pointer[1]) { - case TELQUAL_IS: - fprintf(NetTrace, "IS \"%.*s\"", - (int)(length-2), - (char *)pointer+2); - break; - case TELQUAL_SEND: - fprintf(NetTrace, "SEND"); - break; - default: - fprintf(NetTrace, - "- unknown qualifier %d (0x%x).", - pointer[1], pointer[1]); - } - break; - case TELOPT_TSPEED: - fprintf(NetTrace, "TERMINAL-SPEED"); - if (length < 2) { - fprintf(NetTrace, " (empty suboption??\?)"); - break; - } - switch (pointer[1]) { - case TELQUAL_IS: - fprintf(NetTrace, " IS "); - fprintf(NetTrace, "%.*s", (int)(length-2), (char *)pointer+2); - break; - default: - if (pointer[1] == 1) - fprintf(NetTrace, " SEND"); - else - fprintf(NetTrace, " %d (unknown)", pointer[1]); - for (i = 2; i < length; i++) - fprintf(NetTrace, " ?%d?", pointer[i]); - break; - } - break; - - case TELOPT_LFLOW: - fprintf(NetTrace, "TOGGLE-FLOW-CONTROL"); - if (length < 2) { - fprintf(NetTrace, " (empty suboption??\?)"); - break; - } - switch (pointer[1]) { - case LFLOW_OFF: - fprintf(NetTrace, " OFF"); break; - case LFLOW_ON: - fprintf(NetTrace, " ON"); break; - case LFLOW_RESTART_ANY: - fprintf(NetTrace, " RESTART-ANY"); break; - case LFLOW_RESTART_XON: - fprintf(NetTrace, " RESTART-XON"); break; - default: - fprintf(NetTrace, " %d (unknown)", pointer[1]); - } - for (i = 2; i < length; i++) - fprintf(NetTrace, " ?%d?", pointer[i]); - break; - - case TELOPT_NAWS: - fprintf(NetTrace, "NAWS"); - if (length < 2) { - fprintf(NetTrace, " (empty suboption??\?)"); - break; - } - if (length == 2) { - fprintf(NetTrace, " ?%d?", pointer[1]); - break; - } - fprintf(NetTrace, " %d %d (%d)", - pointer[1], pointer[2], - (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2]))); - if (length == 4) { - fprintf(NetTrace, " ?%d?", pointer[3]); - break; - } - fprintf(NetTrace, " %d %d (%d)", - pointer[3], pointer[4], - (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4]))); - for (i = 5; i < length; i++) - fprintf(NetTrace, " ?%d?", pointer[i]); - break; - -#if defined(AUTHENTICATION) - case TELOPT_AUTHENTICATION: - fprintf(NetTrace, "AUTHENTICATION"); - if (length < 2) { - fprintf(NetTrace, " (empty suboption??\?)"); - break; - } - switch (pointer[1]) { - case TELQUAL_REPLY: - case TELQUAL_IS: - fprintf(NetTrace, " %s ", (pointer[1] == TELQUAL_IS) ? - "IS" : "REPLY"); - if (AUTHTYPE_NAME_OK(pointer[2])) - fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[2])); - else - fprintf(NetTrace, "%d ", pointer[2]); - if (length < 3) { - fprintf(NetTrace, "(partial suboption??\?)"); - break; - } - fprintf(NetTrace, "%s|%s", - ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? - "CLIENT" : "SERVER", - ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? - "MUTUAL" : "ONE-WAY"); - - auth_printsub(&pointer[1], length - 1, buf, sizeof(buf)); - fprintf(NetTrace, "%s", buf); - break; - - case TELQUAL_SEND: - i = 2; - fprintf(NetTrace, " SEND "); - while (i < length) { - if (AUTHTYPE_NAME_OK(pointer[i])) - fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[i])); - else - fprintf(NetTrace, "%d ", pointer[i]); - if (++i >= length) { - fprintf(NetTrace, "(partial suboption??\?)"); - break; - } - fprintf(NetTrace, "%s|%s ", - ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? - "CLIENT" : "SERVER", - ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? - "MUTUAL" : "ONE-WAY"); - ++i; - } - break; - - case TELQUAL_NAME: - i = 2; - fprintf(NetTrace, " NAME \""); - while (i < length) - putc(pointer[i++], NetTrace); - putc('"', NetTrace); - break; - - default: - for (i = 2; i < length; i++) - fprintf(NetTrace, " ?%d?", pointer[i]); - break; - } - break; -#endif - -#if defined(ENCRYPTION) - case TELOPT_ENCRYPT: - fprintf(NetTrace, "ENCRYPT"); - if (length < 2) { - fprintf(NetTrace, " (empty suboption?)"); - break; - } - switch (pointer[1]) { - case ENCRYPT_START: - fprintf(NetTrace, " START"); - break; - - case ENCRYPT_END: - fprintf(NetTrace, " END"); - break; - - case ENCRYPT_REQSTART: - fprintf(NetTrace, " REQUEST-START"); - break; - - case ENCRYPT_REQEND: - fprintf(NetTrace, " REQUEST-END"); - break; - - case ENCRYPT_IS: - case ENCRYPT_REPLY: - fprintf(NetTrace, " %s ", (pointer[1] == ENCRYPT_IS) ? - "IS" : "REPLY"); - if (length < 3) { - fprintf(NetTrace, " (partial suboption?)"); - break; - } - if (ENCTYPE_NAME_OK(pointer[2])) - fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[2])); - else - fprintf(NetTrace, " %d (unknown)", pointer[2]); - - encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf)); - fprintf(NetTrace, "%s", buf); - break; - - case ENCRYPT_SUPPORT: - i = 2; - fprintf(NetTrace, " SUPPORT "); - while (i < length) { - if (ENCTYPE_NAME_OK(pointer[i])) - fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[i])); - else - fprintf(NetTrace, "%d ", pointer[i]); - i++; - } - break; - - case ENCRYPT_ENC_KEYID: - fprintf(NetTrace, " ENC_KEYID "); - goto encommon; - - case ENCRYPT_DEC_KEYID: - fprintf(NetTrace, " DEC_KEYID "); - goto encommon; - - default: - fprintf(NetTrace, " %d (unknown)", pointer[1]); - encommon: - for (i = 2; i < length; i++) - fprintf(NetTrace, " %d", pointer[i]); - break; - } - break; -#endif - - case TELOPT_LINEMODE: - fprintf(NetTrace, "LINEMODE "); - if (length < 2) { - fprintf(NetTrace, " (empty suboption??\?)"); - break; - } - switch (pointer[1]) { - case WILL: - fprintf(NetTrace, "WILL "); - goto common; - case WONT: - fprintf(NetTrace, "WONT "); - goto common; - case DO: - fprintf(NetTrace, "DO "); - goto common; - case DONT: - fprintf(NetTrace, "DONT "); - common: - if (length < 3) { - fprintf(NetTrace, "(no option??\?)"); - break; - } - switch (pointer[2]) { - case LM_FORWARDMASK: - fprintf(NetTrace, "Forward Mask"); - for (i = 3; i < length; i++) - fprintf(NetTrace, " %x", pointer[i]); - break; - default: - fprintf(NetTrace, "%d (unknown)", pointer[2]); - for (i = 3; i < length; i++) - fprintf(NetTrace, " %d", pointer[i]); - break; - } - break; - - case LM_SLC: - fprintf(NetTrace, "SLC"); - for (i = 2; i < length - 2; i += 3) { - if (SLC_NAME_OK(pointer[i+SLC_FUNC])) - fprintf(NetTrace, " %s", SLC_NAME(pointer[i+SLC_FUNC])); - else - fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]); - switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { - case SLC_NOSUPPORT: - fprintf(NetTrace, " NOSUPPORT"); break; - case SLC_CANTCHANGE: - fprintf(NetTrace, " CANTCHANGE"); break; - case SLC_VARIABLE: - fprintf(NetTrace, " VARIABLE"); break; - case SLC_DEFAULT: - fprintf(NetTrace, " DEFAULT"); break; - } - fprintf(NetTrace, "%s%s%s", - pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", - pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", - pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); - if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN| - SLC_FLUSHOUT| SLC_LEVELBITS)) - fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]); - fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]); - if ((pointer[i+SLC_VALUE] == IAC) && - (pointer[i+SLC_VALUE+1] == IAC)) - i++; - } - for (; i < length; i++) - fprintf(NetTrace, " ?%d?", pointer[i]); - break; - - case LM_MODE: - fprintf(NetTrace, "MODE "); - if (length < 3) { - fprintf(NetTrace, "(no mode??\?)"); - break; - } - { - char tbuf[64]; - snprintf(tbuf, sizeof(tbuf), - "%s%s%s%s%s", - pointer[2]&MODE_EDIT ? "|EDIT" : "", - pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "", - pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "", - pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "", - pointer[2]&MODE_ACK ? "|ACK" : ""); - fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0"); - } - if (pointer[2]&~(MODE_MASK)) - fprintf(NetTrace, " (0x%x)", pointer[2]); - for (i = 3; i < length; i++) - fprintf(NetTrace, " ?0x%x?", pointer[i]); - break; - default: - fprintf(NetTrace, "%d (unknown)", pointer[1]); - for (i = 2; i < length; i++) - fprintf(NetTrace, " %d", pointer[i]); - } - break; - - case TELOPT_STATUS: { - char *cp; - int j, k; - - fprintf(NetTrace, "STATUS"); - - switch (pointer[1]) { - default: - if (pointer[1] == TELQUAL_SEND) - fprintf(NetTrace, " SEND"); - else - fprintf(NetTrace, " %d (unknown)", pointer[1]); - for (i = 2; i < length; i++) - fprintf(NetTrace, " ?%d?", pointer[i]); - break; - case TELQUAL_IS: - if (--want_status_response < 0) - want_status_response = 0; - if (NetTrace == stdout) - fprintf(NetTrace, " IS\r\n"); - else - fprintf(NetTrace, " IS\n"); - - for (i = 2; i < length; i++) { - switch(pointer[i]) { - case DO: cp = "DO"; goto common2; - case DONT: cp = "DONT"; goto common2; - case WILL: cp = "WILL"; goto common2; - case WONT: cp = "WONT"; goto common2; - common2: - i++; - if (TELOPT_OK((int)pointer[i])) - fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i])); - else - fprintf(NetTrace, " %s %d", cp, pointer[i]); - - if (NetTrace == stdout) - fprintf(NetTrace, "\r\n"); - else - fprintf(NetTrace, "\n"); - break; - - case SB: - fprintf(NetTrace, " SB "); - i++; - j = k = i; - while (j < length) { - if (pointer[j] == SE) { - if (j+1 == length) - break; - if (pointer[j+1] == SE) - j++; - else - break; - } - pointer[k++] = pointer[j++]; - } - printsub(0, &pointer[i], k - i); - if (i < length) { - fprintf(NetTrace, " SE"); - i = j; - } else - i = j - 1; - - if (NetTrace == stdout) - fprintf(NetTrace, "\r\n"); - else - fprintf(NetTrace, "\n"); - - break; - - default: - fprintf(NetTrace, " %d", pointer[i]); - break; - } - } - break; - } - break; - } - - case TELOPT_XDISPLOC: - fprintf(NetTrace, "X-DISPLAY-LOCATION "); - switch (pointer[1]) { - case TELQUAL_IS: - fprintf(NetTrace, "IS \"%.*s\"", (int)(length-2), (char *)pointer+2); - break; - case TELQUAL_SEND: - fprintf(NetTrace, "SEND"); - break; - default: - fprintf(NetTrace, "- unknown qualifier %d (0x%x).", - pointer[1], pointer[1]); - } - break; - - case TELOPT_NEW_ENVIRON: - fprintf(NetTrace, "NEW-ENVIRON "); -#ifdef OLD_ENVIRON - goto env_common1; - case TELOPT_OLD_ENVIRON: - fprintf(NetTrace, "OLD-ENVIRON"); - env_common1: -#endif - switch (pointer[1]) { - case TELQUAL_IS: - fprintf(NetTrace, "IS "); - goto env_common; - case TELQUAL_SEND: - fprintf(NetTrace, "SEND "); - goto env_common; - case TELQUAL_INFO: - fprintf(NetTrace, "INFO "); - env_common: - { - int quote = 0; - for (i = 2; i < length; i++ ) { - switch (pointer[i]) { - case NEW_ENV_VAR: - qprintf(quote, NetTrace, "VAR "); - quote = 0; - break; - - case NEW_ENV_VALUE: - qprintf(quote, NetTrace, "VALUE"); - quote = 0; - break; - - case ENV_ESC: - qprintf(quote, NetTrace, "ESC "); - quote = 0; - break; - - case ENV_USERVAR: - qprintf(quote, NetTrace, "USERVAR "); - quote = 0; - break; - - default: - if (isprint(pointer[i]) && pointer[i] != '"') { - if (!quote) { - putc('"', NetTrace); - quote = 1; - } - putc(pointer[i], NetTrace); - } else { - qprintf(quote, NetTrace, "%03o ", pointer[i]); - quote = 0; - } - break; - } - } - if (quote) - putc('"', NetTrace); - break; - } - } - break; - - default: - if (TELOPT_OK(pointer[0])) - fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0])); - else - fprintf(NetTrace, "%d (unknown)", pointer[0]); - for (i = 1; i < length; i++) - fprintf(NetTrace, " %d", pointer[i]); - break; - } - if (direction) { - if (NetTrace == stdout) - fprintf(NetTrace, "\r\n"); - else - fprintf(NetTrace, "\n"); - } - if (NetTrace == stdout) - fflush(NetTrace); - } -} - -/* EmptyTerminal - called to make sure that the terminal buffer is empty. - * Note that we consider the buffer to run all the - * way to the kernel (thus the select). - */ - -void -EmptyTerminal(void) -{ - fd_set outs; - - FD_ZERO(&outs); - - if (tout >= FD_SETSIZE) - ExitString("fd too large", 1); - - if (TTYBYTES() == 0) { - FD_SET(tout, &outs); - select(tout+1, 0, &outs, 0, - (struct timeval *) 0); /* wait for TTLOWAT */ - } else { - while (TTYBYTES()) { - ttyflush(0); - FD_SET(tout, &outs); - select(tout+1, 0, &outs, 0, - (struct timeval *) 0); /* wait for TTLOWAT */ - } - } -} - -void -SetForExit(void) -{ - setconnmode(0); - do { - telrcv(); /* Process any incoming data */ - EmptyTerminal(); - } while (ring_full_count(&netiring)); /* While there is any */ - setcommandmode(); - fflush(stdout); - fflush(stderr); - setconnmode(0); - EmptyTerminal(); /* Flush the path to the tty */ - setcommandmode(); -} - -void -Exit(int returnCode) -{ - SetForExit(); - exit(returnCode); -} - -void -ExitString(char *string, int returnCode) -{ - SetForExit(); - fwrite(string, 1, strlen(string), stderr); - exit(returnCode); -} diff --git a/appl/telnet/telnetd/Makefile.am b/appl/telnet/telnetd/Makefile.am deleted file mode 100644 index f1a111975..000000000 --- a/appl/telnet/telnetd/Makefile.am +++ /dev/null @@ -1,27 +0,0 @@ -# $Id$ - -include $(top_srcdir)/Makefile.am.common - -AM_CPPFLAGS += -I$(srcdir)/.. $(INCLUDE_hcrypto) - -libexec_PROGRAMS = telnetd - -CHECK_LOCAL = - -telnetd_SOURCES = telnetd.c state.c termstat.c slc.c sys_term.c \ - utility.c global.c authenc.c defs.h ext.h telnetd.h - -man_MANS = telnetd.8 - -LDADD = \ - ../libtelnet/libtelnet.a \ - $(LIB_krb5) \ - $(LIB_hcrypto) \ - $(LIB_tgetent) \ - $(LIB_logwtmp) \ - $(LIB_logout) \ - $(LIB_openpty) \ - $(LIB_kdfs) \ - $(LIB_roken) - -EXTRA_DIST = $(man_MANS) diff --git a/appl/telnet/telnetd/authenc.c b/appl/telnet/telnetd/authenc.c deleted file mode 100644 index f077a468f..000000000 --- a/appl/telnet/telnetd/authenc.c +++ /dev/null @@ -1,80 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "telnetd.h" - -RCSID("$Id$"); - -#ifdef AUTHENTICATION - -int -telnet_net_write(unsigned char *str, int len) -{ - if (nfrontp + len < netobuf + BUFSIZ) { - memmove(nfrontp, str, len); - nfrontp += len; - return(len); - } - return(0); -} - -void -net_encrypt(void) -{ -#ifdef ENCRYPTION - char *s = (nclearto > nbackp) ? nclearto : nbackp; - if (s < nfrontp && encrypt_output) { - (*encrypt_output)((unsigned char *)s, nfrontp - s); - } - nclearto = nfrontp; -#endif -} - -int -telnet_spin(void) -{ - return ttloop(); -} - -char * -telnet_getenv(const char *val) -{ - return(getenv(val)); -} - -char * -telnet_gets(char *prompt, char *result, int length, int echo) -{ - return NULL; -} -#endif diff --git a/appl/telnet/telnetd/defs.h b/appl/telnet/telnetd/defs.h deleted file mode 100644 index dde22cbe3..000000000 --- a/appl/telnet/telnetd/defs.h +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)defs.h 8.1 (Berkeley) 6/4/93 - */ - -/* - * Telnet server defines - */ - -#ifndef __DEFS_H__ -#define __DEFS_H__ - -#ifndef BSD -# define BSD 43 -#endif - -#if defined(PRINTOPTIONS) && defined(DIAGNOSTICS) -#define TELOPTS -#define TELCMDS -#define SLC_NAMES -#endif - -#if !defined(TIOCSCTTY) && defined(TCSETCTTY) -# define TIOCSCTTY TCSETCTTY -#endif - -#ifndef TIOCPKT_FLUSHWRITE -#define TIOCPKT_FLUSHWRITE 0x02 -#endif - -#ifndef TIOCPKT_NOSTOP -#define TIOCPKT_NOSTOP 0x10 -#endif - -#ifndef TIOCPKT_DOSTOP -#define TIOCPKT_DOSTOP 0x20 -#endif - -/* - * I/O data buffers defines - */ -#define NETSLOP 64 -#ifdef _CRAY -#undef BUFSIZ -#define BUFSIZ 2048 -#endif - -#define NIACCUM(c) { *netip++ = c; \ - ncc++; \ - } - -/* clock manipulations */ -#define settimer(x) (clocks.x = ++clocks.system) -#define sequenceIs(x,y) (clocks.x < clocks.y) - -/* - * Structures of information for each special character function. - */ -typedef struct { - unsigned char flag; /* the flags for this function */ - cc_t val; /* the value of the special character */ -} slcent, *Slcent; - -typedef struct { - slcent defset; /* the default settings */ - slcent current; /* the current settings */ - cc_t *sptr; /* a pointer to the char in */ - /* system data structures */ -} slcfun, *Slcfun; - -#ifdef DIAGNOSTICS -/* - * Diagnostics capabilities - */ -#define TD_REPORT 0x01 /* Report operations to client */ -#define TD_EXERCISE 0x02 /* Exercise client's implementation */ -#define TD_NETDATA 0x04 /* Display received data stream */ -#define TD_PTYDATA 0x08 /* Display data passed to pty */ -#define TD_OPTIONS 0x10 /* Report just telnet options */ -#endif /* DIAGNOSTICS */ - -/* - * We keep track of each side of the option negotiation. - */ - -#define MY_STATE_WILL 0x01 -#define MY_WANT_STATE_WILL 0x02 -#define MY_STATE_DO 0x04 -#define MY_WANT_STATE_DO 0x08 - -/* - * Macros to check the current state of things - */ - -#define my_state_is_do(opt) (options[opt]&MY_STATE_DO) -#define my_state_is_will(opt) (options[opt]&MY_STATE_WILL) -#define my_want_state_is_do(opt) (options[opt]&MY_WANT_STATE_DO) -#define my_want_state_is_will(opt) (options[opt]&MY_WANT_STATE_WILL) - -#define my_state_is_dont(opt) (!my_state_is_do(opt)) -#define my_state_is_wont(opt) (!my_state_is_will(opt)) -#define my_want_state_is_dont(opt) (!my_want_state_is_do(opt)) -#define my_want_state_is_wont(opt) (!my_want_state_is_will(opt)) - -#define set_my_state_do(opt) (options[opt] |= MY_STATE_DO) -#define set_my_state_will(opt) (options[opt] |= MY_STATE_WILL) -#define set_my_want_state_do(opt) (options[opt] |= MY_WANT_STATE_DO) -#define set_my_want_state_will(opt) (options[opt] |= MY_WANT_STATE_WILL) - -#define set_my_state_dont(opt) (options[opt] &= ~MY_STATE_DO) -#define set_my_state_wont(opt) (options[opt] &= ~MY_STATE_WILL) -#define set_my_want_state_dont(opt) (options[opt] &= ~MY_WANT_STATE_DO) -#define set_my_want_state_wont(opt) (options[opt] &= ~MY_WANT_STATE_WILL) - -/* - * Tricky code here. What we want to know is if the MY_STATE_WILL - * and MY_WANT_STATE_WILL bits have the same value. Since the two - * bits are adjacent, a little arithmatic will show that by adding - * in the lower bit, the upper bit will be set if the two bits were - * different, and clear if they were the same. - */ -#define my_will_wont_is_changing(opt) \ - ((options[opt]+MY_STATE_WILL) & MY_WANT_STATE_WILL) - -#define my_do_dont_is_changing(opt) \ - ((options[opt]+MY_STATE_DO) & MY_WANT_STATE_DO) - -/* - * Make everything symmetrical - */ - -#define HIS_STATE_WILL MY_STATE_DO -#define HIS_WANT_STATE_WILL MY_WANT_STATE_DO -#define HIS_STATE_DO MY_STATE_WILL -#define HIS_WANT_STATE_DO MY_WANT_STATE_WILL - -#define his_state_is_do my_state_is_will -#define his_state_is_will my_state_is_do -#define his_want_state_is_do my_want_state_is_will -#define his_want_state_is_will my_want_state_is_do - -#define his_state_is_dont my_state_is_wont -#define his_state_is_wont my_state_is_dont -#define his_want_state_is_dont my_want_state_is_wont -#define his_want_state_is_wont my_want_state_is_dont - -#define set_his_state_do set_my_state_will -#define set_his_state_will set_my_state_do -#define set_his_want_state_do set_my_want_state_will -#define set_his_want_state_will set_my_want_state_do - -#define set_his_state_dont set_my_state_wont -#define set_his_state_wont set_my_state_dont -#define set_his_want_state_dont set_my_want_state_wont -#define set_his_want_state_wont set_my_want_state_dont - -#define his_will_wont_is_changing my_do_dont_is_changing -#define his_do_dont_is_changing my_will_wont_is_changing - -#endif /* __DEFS_H__ */ diff --git a/appl/telnet/telnetd/ext.h b/appl/telnet/telnetd/ext.h deleted file mode 100644 index ef54ba7a3..000000000 --- a/appl/telnet/telnetd/ext.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)ext.h 8.2 (Berkeley) 12/15/93 - */ - -/* $Id$ */ - -#ifndef __EXT_H__ -#define __EXT_H__ - -/* - * Telnet server variable declarations - */ -extern char options[256]; -extern char do_dont_resp[256]; -extern char will_wont_resp[256]; -extern int flowmode; /* current flow control state */ -extern int restartany; /* restart output on any character state */ -#ifdef DIAGNOSTICS -extern int diagnostic; /* telnet diagnostic capabilities */ -#endif /* DIAGNOSTICS */ -extern int require_otp; -#ifdef AUTHENTICATION -extern int auth_level; -#endif -extern const char *new_login; - -extern slcfun slctab[NSLC + 1]; /* slc mapping table */ - -extern char terminaltype[41]; - -/* - * I/O data buffers, pointers, and counters. - */ -extern char ptyobuf[BUFSIZ+NETSLOP], *pfrontp, *pbackp; - -extern char netibuf[BUFSIZ], *netip; - -extern char netobuf[BUFSIZ+NETSLOP], *nfrontp, *nbackp; -extern char *neturg; /* one past last bye of urgent data */ - -extern int pcc, ncc; - -extern int ourpty, net; -extern char *line; -extern int SYNCHing; /* we are in TELNET SYNCH mode */ - -int telnet_net_write (unsigned char *str, int len); -void net_encrypt (void); -int telnet_spin (void); -char *telnet_getenv (const char *val); -char *telnet_gets (char *prompt, char *result, int length, int echo); -void get_slc_defaults (void); -void telrcv (void); -void send_do (int option, int init); -void willoption (int option); -void send_dont (int option, int init); -void wontoption (int option); -void send_will (int option, int init); -void dooption (int option); -void send_wont (int option, int init); -void dontoption (int option); -void suboption (void); -void doclientstat (void); -void send_status (void); -void init_termbuf (void); -void set_termbuf (void); -int spcset (int func, cc_t *valp, cc_t **valpp); -void set_utid (void); -int getpty (int *ptynum); -int tty_isecho (void); -int tty_flowmode (void); -int tty_restartany (void); -void tty_setecho (int on); -int tty_israw (void); -void tty_binaryin (int on); -void tty_binaryout (int on); -int tty_isbinaryin (void); -int tty_isbinaryout (void); -int tty_issofttab (void); -void tty_setsofttab (int on); -int tty_islitecho (void); -void tty_setlitecho (int on); -int tty_iscrnl (void); -void tty_tspeed (int val); -void tty_rspeed (int val); -void getptyslave (void); -int cleanopen (char *); -void startslave (const char *host, const char *, int autologin, char *autoname); -void init_env (void); -void start_login (const char *host, int autologin, char *name); -void cleanup (int sig); -int main (int argc, char **argv); -int getterminaltype (char *name, size_t); -void _gettermname (void); -int terminaltypeok (char *s); -void my_telnet (int f, int p, const char*, const char *, int, char*); -void interrupt (void); -void sendbrk (void); -void sendsusp (void); -void recv_ayt (void); -void doeof (void); -void flowstat (void); -void clientstat (int code, int parm1, int parm2); -int ttloop (void); -int stilloob (int s); -void ptyflush (void); -char *nextitem (char *current); -void netclear (void); -void netflush (void); -void writenet (const void *, size_t); -void fatal (int f, char *msg); -void fatalperror (int f, const char *msg); -void fatalperror_errno (int f, const char *msg, int error); -void edithost (char *pat, char *host); -void putstr (char *s); -void putchr (int cc); -void putf (char *cp, char *where); -void printoption (char *fmt, int option); -void printsub (int direction, unsigned char *pointer, size_t length); -void printdata (char *tag, char *ptr, size_t cnt); -int login_tty(int t); - -#ifdef ENCRYPTION -extern void (*encrypt_output) (unsigned char *, int); -extern int (*decrypt_input) (int); -extern char *nclearto; -#endif - - -/* - * The following are some clocks used to decide how to interpret - * the relationship between various variables. - */ - -struct clocks_t{ - int - system, /* what the current time is */ - echotoggle, /* last time user entered echo character */ - modenegotiated, /* last time operating mode negotiated */ - didnetreceive, /* last time we read data from network */ - ttypesubopt, /* ttype subopt is received */ - tspeedsubopt, /* tspeed subopt is received */ - environsubopt, /* environ subopt is received */ - oenvironsubopt, /* old environ subopt is received */ - xdisplocsubopt, /* xdisploc subopt is received */ - baseline, /* time started to do timed action */ - gotDM; /* when did we last see a data mark */ -}; -extern struct clocks_t clocks; - -extern int log_unauth; -extern int no_warn; - -extern int def_tspeed, def_rspeed; -#ifdef TIOCSWINSZ -extern int def_row, def_col; -#endif - -#ifdef STREAMSPTY -extern int really_stream; -#endif - -#ifndef USE_IM -# ifdef CRAY -# define USE_IM "Cray UNICOS (%h) (%t)" -# endif -# ifdef _AIX -# define USE_IM "%s %v.%r (%h) (%t)" -# endif -# ifndef USE_IM -# define USE_IM "%s %r (%h) (%t)" -# endif -#endif - -#define DEFAULT_IM "\r\n\r\n" USE_IM "\r\n\r\n\r\n" - -#endif /* __EXT_H__ */ diff --git a/appl/telnet/telnetd/global.c b/appl/telnet/telnetd/global.c deleted file mode 100644 index e9ad94fcb..000000000 --- a/appl/telnet/telnetd/global.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* a *lot* of ugly global definitions that really should be removed... - */ - -#include "telnetd.h" - -RCSID("$Id$"); - -/* - * Telnet server variable declarations - */ -char options[256]; -char do_dont_resp[256]; -char will_wont_resp[256]; -int linemode; /* linemode on/off */ -int flowmode; /* current flow control state */ -int restartany; /* restart output on any character state */ -#ifdef DIAGNOSTICS -int diagnostic; /* telnet diagnostic capabilities */ -#endif /* DIAGNOSTICS */ -int require_otp; - -slcfun slctab[NSLC + 1]; /* slc mapping table */ - -char terminaltype[41]; - -/* - * I/O data buffers, pointers, and counters. - */ -char ptyobuf[BUFSIZ+NETSLOP], *pfrontp, *pbackp; - -char netibuf[BUFSIZ], *netip; - -char netobuf[BUFSIZ+NETSLOP], *nfrontp, *nbackp; -char *neturg; /* one past last bye of urgent data */ - -int pcc, ncc; - -int ourpty, net; -int SYNCHing; /* we are in TELNET SYNCH mode */ - -/* - * The following are some clocks used to decide how to interpret - * the relationship between various variables. - */ - -struct clocks_t clocks; - - -/* whether to log unauthenticated login attempts */ -int log_unauth; - -/* do not print warning if connection is not encrypted */ -int no_warn; - -/* - * This function appends data to nfrontp and advances nfrontp. - */ - -int -output_data (const char *format, ...) -{ - va_list args; - int remaining, ret; - - va_start(args, format); - remaining = BUFSIZ - (nfrontp - netobuf); - ret = vsnprintf (nfrontp, - remaining, - format, - args); - nfrontp += min(ret, remaining-1); - va_end(args); - return ret; -} diff --git a/appl/telnet/telnetd/state.c b/appl/telnet/telnetd/state.c deleted file mode 100644 index bfa3c6fe3..000000000 --- a/appl/telnet/telnetd/state.c +++ /dev/null @@ -1,1360 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "telnetd.h" - -RCSID("$Id$"); - -unsigned char doopt[] = { IAC, DO, '%', 'c', 0 }; -unsigned char dont[] = { IAC, DONT, '%', 'c', 0 }; -unsigned char will[] = { IAC, WILL, '%', 'c', 0 }; -unsigned char wont[] = { IAC, WONT, '%', 'c', 0 }; -int not42 = 1; - -/* - * Buffer for sub-options, and macros - * for suboptions buffer manipulations - */ -unsigned char subbuffer[1024*64], *subpointer= subbuffer, *subend= subbuffer; - -#define SB_CLEAR() subpointer = subbuffer -#define SB_TERM() { subend = subpointer; SB_CLEAR(); } -#define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ - *subpointer++ = (c); \ - } -#define SB_GET() ((*subpointer++)&0xff) -#define SB_EOF() (subpointer >= subend) -#define SB_LEN() (subend - subpointer) - -#ifdef ENV_HACK -unsigned char *subsave; -#define SB_SAVE() subsave = subpointer; -#define SB_RESTORE() subpointer = subsave; -#endif - - -/* - * State for recv fsm - */ -#define TS_DATA 0 /* base state */ -#define TS_IAC 1 /* look for double IAC's */ -#define TS_CR 2 /* CR-LF ->'s CR */ -#define TS_SB 3 /* throw away begin's... */ -#define TS_SE 4 /* ...end's (suboption negotiation) */ -#define TS_WILL 5 /* will option negotiation */ -#define TS_WONT 6 /* wont -''- */ -#define TS_DO 7 /* do -''- */ -#define TS_DONT 8 /* dont -''- */ - -void -telrcv(void) -{ - int c; - static int state = TS_DATA; - - while (ncc > 0) { - if ((&ptyobuf[BUFSIZ] - pfrontp) < 2) - break; - c = *netip++ & 0377, ncc--; -#ifdef ENCRYPTION - if (decrypt_input) - c = (*decrypt_input)(c); -#endif - switch (state) { - - case TS_CR: - state = TS_DATA; - /* Strip off \n or \0 after a \r */ - if ((c == 0) || (c == '\n')) { - break; - } - /* FALL THROUGH */ - - case TS_DATA: - if (c == IAC) { - state = TS_IAC; - break; - } - /* - * We now map \r\n ==> \r for pragmatic reasons. - * Many client implementations send \r\n when - * the user hits the CarriageReturn key. - * - * We USED to map \r\n ==> \n, since \r\n says - * that we want to be in column 1 of the next - * printable line, and \n is the standard - * unix way of saying that (\r is only good - * if CRMOD is set, which it normally is). - */ - if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) { - int nc = *netip; -#ifdef ENCRYPTION - if (decrypt_input) - nc = (*decrypt_input)(nc & 0xff); -#endif - { -#ifdef ENCRYPTION - if (decrypt_input) - (void)(*decrypt_input)(-1); -#endif - state = TS_CR; - } - } - *pfrontp++ = c; - break; - - case TS_IAC: - gotiac: switch (c) { - - /* - * Send the process on the pty side an - * interrupt. Do this with a NULL or - * interrupt char; depending on the tty mode. - */ - case IP: - DIAG(TD_OPTIONS, - printoption("td: recv IAC", c)); - interrupt(); - break; - - case BREAK: - DIAG(TD_OPTIONS, - printoption("td: recv IAC", c)); - sendbrk(); - break; - - /* - * Are You There? - */ - case AYT: - DIAG(TD_OPTIONS, - printoption("td: recv IAC", c)); - recv_ayt(); - break; - - /* - * Abort Output - */ - case AO: - { - DIAG(TD_OPTIONS, - printoption("td: recv IAC", c)); - ptyflush(); /* half-hearted */ - init_termbuf(); - - if (slctab[SLC_AO].sptr && - *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) { - *pfrontp++ = - (unsigned char)*slctab[SLC_AO].sptr; - } - - netclear(); /* clear buffer back */ - output_data ("%c%c", IAC, DM); - neturg = nfrontp-1; /* off by one XXX */ - DIAG(TD_OPTIONS, - printoption("td: send IAC", DM)); - break; - } - - /* - * Erase Character and - * Erase Line - */ - case EC: - case EL: - { - cc_t ch; - - DIAG(TD_OPTIONS, - printoption("td: recv IAC", c)); - ptyflush(); /* half-hearted */ - init_termbuf(); - if (c == EC) - ch = *slctab[SLC_EC].sptr; - else - ch = *slctab[SLC_EL].sptr; - if (ch != (cc_t)(_POSIX_VDISABLE)) - *pfrontp++ = (unsigned char)ch; - break; - } - - /* - * Check for urgent data... - */ - case DM: - DIAG(TD_OPTIONS, - printoption("td: recv IAC", c)); - SYNCHing = stilloob(net); - settimer(gotDM); - break; - - - /* - * Begin option subnegotiation... - */ - case SB: - state = TS_SB; - SB_CLEAR(); - continue; - - case WILL: - state = TS_WILL; - continue; - - case WONT: - state = TS_WONT; - continue; - - case DO: - state = TS_DO; - continue; - - case DONT: - state = TS_DONT; - continue; - case EOR: - if (his_state_is_will(TELOPT_EOR)) - doeof(); - break; - - /* - * Handle RFC 10xx Telnet linemode option additions - * to command stream (EOF, SUSP, ABORT). - */ - case xEOF: - doeof(); - break; - - case SUSP: - sendsusp(); - break; - - case ABORT: - sendbrk(); - break; - - case IAC: - *pfrontp++ = c; - break; - } - state = TS_DATA; - break; - - case TS_SB: - if (c == IAC) { - state = TS_SE; - } else { - SB_ACCUM(c); - } - break; - - case TS_SE: - if (c != SE) { - if (c != IAC) { - /* - * bad form of suboption negotiation. - * handle it in such a way as to avoid - * damage to local state. Parse - * suboption buffer found so far, - * then treat remaining stream as - * another command sequence. - */ - - /* for DIAGNOSTICS */ - SB_ACCUM(IAC); - SB_ACCUM(c); - subpointer -= 2; - - SB_TERM(); - suboption(); - state = TS_IAC; - goto gotiac; - } - SB_ACCUM(c); - state = TS_SB; - } else { - /* for DIAGNOSTICS */ - SB_ACCUM(IAC); - SB_ACCUM(SE); - subpointer -= 2; - - SB_TERM(); - suboption(); /* handle sub-option */ - state = TS_DATA; - } - break; - - case TS_WILL: - willoption(c); - state = TS_DATA; - continue; - - case TS_WONT: - wontoption(c); - if (c==TELOPT_ENCRYPT && his_do_dont_is_changing(TELOPT_ENCRYPT) ) - dontoption(c); - state = TS_DATA; - continue; - - case TS_DO: - dooption(c); - state = TS_DATA; - continue; - - case TS_DONT: - dontoption(c); - state = TS_DATA; - continue; - - default: - syslog(LOG_ERR, "telnetd: panic state=%d\n", state); - printf("telnetd: panic state=%d\n", state); - exit(1); - } - } -} /* end of telrcv */ - -/* - * The will/wont/do/dont state machines are based on Dave Borman's - * Telnet option processing state machine. - * - * These correspond to the following states: - * my_state = the last negotiated state - * want_state = what I want the state to go to - * want_resp = how many requests I have sent - * All state defaults are negative, and resp defaults to 0. - * - * When initiating a request to change state to new_state: - * - * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) { - * do nothing; - * } else { - * want_state = new_state; - * send new_state; - * want_resp++; - * } - * - * When receiving new_state: - * - * if (want_resp) { - * want_resp--; - * if (want_resp && (new_state == my_state)) - * want_resp--; - * } - * if ((want_resp == 0) && (new_state != want_state)) { - * if (ok_to_switch_to new_state) - * want_state = new_state; - * else - * want_resp++; - * send want_state; - * } - * my_state = new_state; - * - * Note that new_state is implied in these functions by the function itself. - * will and do imply positive new_state, wont and dont imply negative. - * - * Finally, there is one catch. If we send a negative response to a - * positive request, my_state will be the positive while want_state will - * remain negative. my_state will revert to negative when the negative - * acknowlegment arrives from the peer. Thus, my_state generally tells - * us not only the last negotiated state, but also tells us what the peer - * wants to be doing as well. It is important to understand this difference - * as we may wish to be processing data streams based on our desired state - * (want_state) or based on what the peer thinks the state is (my_state). - * - * This all works fine because if the peer sends a positive request, the data - * that we receive prior to negative acknowlegment will probably be affected - * by the positive state, and we can process it as such (if we can; if we - * can't then it really doesn't matter). If it is that important, then the - * peer probably should be buffering until this option state negotiation - * is complete. - * - */ -void -send_do(int option, int init) -{ - if (init) { - if ((do_dont_resp[option] == 0 && his_state_is_will(option)) || - his_want_state_is_will(option)) - return; - /* - * Special case for TELOPT_TM: We send a DO, but pretend - * that we sent a DONT, so that we can send more DOs if - * we want to. - */ - if (option == TELOPT_TM) - set_his_want_state_wont(option); - else - set_his_want_state_will(option); - do_dont_resp[option]++; - } - output_data((const char *)doopt, option); - - DIAG(TD_OPTIONS, printoption("td: send do", option)); -} - -#ifdef AUTHENTICATION -extern void auth_request(void); -#endif -#ifdef ENCRYPTION -extern void encrypt_send_support(void); -#endif - -void -willoption(int option) -{ - int changeok = 0; - void (*func)(void) = NULL; - - /* - * process input from peer. - */ - - DIAG(TD_OPTIONS, printoption("td: recv will", option)); - - if (do_dont_resp[option]) { - do_dont_resp[option]--; - if (do_dont_resp[option] && his_state_is_will(option)) - do_dont_resp[option]--; - } - if (do_dont_resp[option] == 0) { - if (his_want_state_is_wont(option)) { - switch (option) { - - case TELOPT_BINARY: - init_termbuf(); - tty_binaryin(1); - set_termbuf(); - changeok++; - break; - - case TELOPT_ECHO: - /* - * See comments below for more info. - */ - not42 = 0; /* looks like a 4.2 system */ - break; - - case TELOPT_TM: - /* - * We never respond to a WILL TM, and - * we leave the state WONT. - */ - return; - - case TELOPT_LFLOW: - /* - * If we are going to support flow control - * option, then don't worry peer that we can't - * change the flow control characters. - */ - slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; - slctab[SLC_XON].defset.flag |= SLC_DEFAULT; - slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; - slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT; - case TELOPT_TTYPE: - case TELOPT_SGA: - case TELOPT_NAWS: - case TELOPT_TSPEED: - case TELOPT_XDISPLOC: - case TELOPT_NEW_ENVIRON: - case TELOPT_OLD_ENVIRON: - changeok++; - break; - - -#ifdef AUTHENTICATION - case TELOPT_AUTHENTICATION: - func = auth_request; - changeok++; - break; -#endif - -#ifdef ENCRYPTION - case TELOPT_ENCRYPT: - func = encrypt_send_support; - changeok++; - break; -#endif - - default: - break; - } - if (changeok) { - set_his_want_state_will(option); - send_do(option, 0); - } else { - do_dont_resp[option]++; - send_dont(option, 0); - } - } else { - /* - * Option processing that should happen when - * we receive conformation of a change in - * state that we had requested. - */ - switch (option) { - case TELOPT_ECHO: - not42 = 0; /* looks like a 4.2 system */ - /* - * Egads, he responded "WILL ECHO". Turn - * it off right now! - */ - send_dont(option, 1); - /* - * "WILL ECHO". Kludge upon kludge! - * A 4.2 client is now echoing user input at - * the tty. This is probably undesireable and - * it should be stopped. The client will - * respond WONT TM to the DO TM that we send to - * check for kludge linemode. When the WONT TM - * arrives, linemode will be turned off and a - * change propogated to the pty. This change - * will cause us to process the new pty state - * in localstat(), which will notice that - * linemode is off and send a WILL ECHO - * so that we are properly in character mode and - * all is well. - */ - break; - -#ifdef AUTHENTICATION - case TELOPT_AUTHENTICATION: - func = auth_request; - break; -#endif - -#ifdef ENCRYPTION - case TELOPT_ENCRYPT: - func = encrypt_send_support; - break; -#endif - - case TELOPT_LFLOW: - func = flowstat; - break; - } - } - } - set_his_state_will(option); - if (func) - (*func)(); -} /* end of willoption */ - -void -send_dont(int option, int init) -{ - if (init) { - if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) || - his_want_state_is_wont(option)) - return; - set_his_want_state_wont(option); - do_dont_resp[option]++; - } - output_data((const char *)dont, option); - - DIAG(TD_OPTIONS, printoption("td: send dont", option)); -} - -void -wontoption(int option) -{ - /* - * Process client input. - */ - - DIAG(TD_OPTIONS, printoption("td: recv wont", option)); - - if (do_dont_resp[option]) { - do_dont_resp[option]--; - if (do_dont_resp[option] && his_state_is_wont(option)) - do_dont_resp[option]--; - } - if (do_dont_resp[option] == 0) { - if (his_want_state_is_will(option)) { - /* it is always ok to change to negative state */ - switch (option) { - case TELOPT_ECHO: - not42 = 1; /* doesn't seem to be a 4.2 system */ - break; - - case TELOPT_BINARY: - init_termbuf(); - tty_binaryin(0); - set_termbuf(); - break; - - case TELOPT_TM: - /* - * If we get a WONT TM, and had sent a DO TM, - * don't respond with a DONT TM, just leave it - * as is. Short circut the state machine to - * achive this. - */ - set_his_want_state_wont(TELOPT_TM); - return; - - case TELOPT_LFLOW: - /* - * If we are not going to support flow control - * option, then let peer know that we can't - * change the flow control characters. - */ - slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; - slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE; - slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; - slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE; - break; - -#ifdef AUTHENTICATION - case TELOPT_AUTHENTICATION: - auth_finished(0, AUTH_REJECT); - break; -#endif - - /* - * For options that we might spin waiting for - * sub-negotiation, if the client turns off the - * option rather than responding to the request, - * we have to treat it here as if we got a response - * to the sub-negotiation, (by updating the timers) - * so that we'll break out of the loop. - */ - case TELOPT_TTYPE: - settimer(ttypesubopt); - break; - - case TELOPT_TSPEED: - settimer(tspeedsubopt); - break; - - case TELOPT_XDISPLOC: - settimer(xdisplocsubopt); - break; - - case TELOPT_OLD_ENVIRON: - settimer(oenvironsubopt); - break; - - case TELOPT_NEW_ENVIRON: - settimer(environsubopt); - break; - - default: - break; - } - set_his_want_state_wont(option); - if (his_state_is_will(option)) - send_dont(option, 0); - } else { - switch (option) { - case TELOPT_TM: - break; - -#ifdef AUTHENTICATION - case TELOPT_AUTHENTICATION: - auth_finished(0, AUTH_REJECT); - break; -#endif - default: - break; - } - } - } - set_his_state_wont(option); - -} /* end of wontoption */ - -void -send_will(int option, int init) -{ - if (init) { - if ((will_wont_resp[option] == 0 && my_state_is_will(option))|| - my_want_state_is_will(option)) - return; - set_my_want_state_will(option); - will_wont_resp[option]++; - } - output_data ((const char *)will, option); - - DIAG(TD_OPTIONS, printoption("td: send will", option)); -} - -/* - * When we get a DONT SGA, we will try once to turn it - * back on. If the other side responds DONT SGA, we - * leave it at that. This is so that when we talk to - * clients that understand KLUDGELINEMODE but not LINEMODE, - * we'll keep them in char-at-a-time mode. - */ -int turn_on_sga = 0; - -void -dooption(int option) -{ - int changeok = 0; - - /* - * Process client input. - */ - - DIAG(TD_OPTIONS, printoption("td: recv do", option)); - - if (will_wont_resp[option]) { - will_wont_resp[option]--; - if (will_wont_resp[option] && my_state_is_will(option)) - will_wont_resp[option]--; - } - if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) { - switch (option) { - case TELOPT_ECHO: - { - init_termbuf(); - tty_setecho(1); - set_termbuf(); - } - changeok++; - break; - - case TELOPT_BINARY: - init_termbuf(); - tty_binaryout(1); - set_termbuf(); - changeok++; - break; - - case TELOPT_SGA: - turn_on_sga = 0; - changeok++; - break; - - case TELOPT_STATUS: - changeok++; - break; - - case TELOPT_TM: - /* - * Special case for TM. We send a WILL, but - * pretend we sent a WONT. - */ - send_will(option, 0); - set_my_want_state_wont(option); - set_my_state_wont(option); - return; - - case TELOPT_LOGOUT: - /* - * When we get a LOGOUT option, respond - * with a WILL LOGOUT, make sure that - * it gets written out to the network, - * and then just go away... - */ - set_my_want_state_will(TELOPT_LOGOUT); - send_will(TELOPT_LOGOUT, 0); - set_my_state_will(TELOPT_LOGOUT); - netflush(); - cleanup(0); - /* NOT REACHED */ - break; - -#ifdef ENCRYPTION - case TELOPT_ENCRYPT: - changeok++; - break; -#endif - case TELOPT_LINEMODE: - case TELOPT_TTYPE: - case TELOPT_NAWS: - case TELOPT_TSPEED: - case TELOPT_LFLOW: - case TELOPT_XDISPLOC: -#ifdef TELOPT_ENVIRON - case TELOPT_NEW_ENVIRON: -#endif - case TELOPT_OLD_ENVIRON: - default: - break; - } - if (changeok) { - set_my_want_state_will(option); - send_will(option, 0); - } else { - will_wont_resp[option]++; - send_wont(option, 0); - } - } - set_my_state_will(option); - -} /* end of dooption */ - -void -send_wont(int option, int init) -{ - if (init) { - if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) || - my_want_state_is_wont(option)) - return; - set_my_want_state_wont(option); - will_wont_resp[option]++; - } - output_data ((const char *)wont, option); - - DIAG(TD_OPTIONS, printoption("td: send wont", option)); -} - -void -dontoption(int option) -{ - /* - * Process client input. - */ - - - DIAG(TD_OPTIONS, printoption("td: recv dont", option)); - - if (will_wont_resp[option]) { - will_wont_resp[option]--; - if (will_wont_resp[option] && my_state_is_wont(option)) - will_wont_resp[option]--; - } - if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) { - switch (option) { - case TELOPT_BINARY: - init_termbuf(); - tty_binaryout(0); - set_termbuf(); - break; - - case TELOPT_ECHO: /* we should stop echoing */ - { - init_termbuf(); - tty_setecho(0); - set_termbuf(); - } - break; - - case TELOPT_SGA: - set_my_want_state_wont(option); - if (my_state_is_will(option)) - send_wont(option, 0); - set_my_state_wont(option); - if (turn_on_sga ^= 1) - send_will(option, 1); - return; - - default: - break; - } - - set_my_want_state_wont(option); - if (my_state_is_will(option)) - send_wont(option, 0); - } - set_my_state_wont(option); - -} /* end of dontoption */ - -#ifdef ENV_HACK -int env_ovar = -1; -int env_ovalue = -1; -#else /* ENV_HACK */ -# define env_ovar OLD_ENV_VAR -# define env_ovalue OLD_ENV_VALUE -#endif /* ENV_HACK */ - -/* - * suboption() - * - * Look at the sub-option buffer, and try to be helpful to the other - * side. - * - * Currently we recognize: - * - * Terminal type is - * Linemode - * Window size - * Terminal speed - */ -void -suboption(void) -{ - int subchar; - - DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);}); - - subchar = SB_GET(); - switch (subchar) { - case TELOPT_TSPEED: { - int xspeed, rspeed; - - if (his_state_is_wont(TELOPT_TSPEED)) /* Ignore if option disabled */ - break; - - settimer(tspeedsubopt); - - if (SB_EOF() || SB_GET() != TELQUAL_IS) - return; - - xspeed = atoi((char *)subpointer); - - while (SB_GET() != ',' && !SB_EOF()); - if (SB_EOF()) - return; - - rspeed = atoi((char *)subpointer); - clientstat(TELOPT_TSPEED, xspeed, rspeed); - - break; - - } /* end of case TELOPT_TSPEED */ - - case TELOPT_TTYPE: { /* Yaaaay! */ - char *p; - - if (his_state_is_wont(TELOPT_TTYPE)) /* Ignore if option disabled */ - break; - settimer(ttypesubopt); - - if (SB_EOF() || SB_GET() != TELQUAL_IS) { - return; /* ??? XXX but, this is the most robust */ - } - - p = terminaltype; - - while ((p < (terminaltype + sizeof terminaltype-1)) && - !SB_EOF()) { - int c; - - c = SB_GET(); - if (isupper(c)) { - c = tolower(c); - } - *p++ = c; /* accumulate name */ - } - *p = 0; - break; - } /* end of case TELOPT_TTYPE */ - - case TELOPT_NAWS: { - int xwinsize, ywinsize; - - if (his_state_is_wont(TELOPT_NAWS)) /* Ignore if option disabled */ - break; - - if (SB_EOF()) - return; - xwinsize = SB_GET() << 8; - if (SB_EOF()) - return; - xwinsize |= SB_GET(); - if (SB_EOF()) - return; - ywinsize = SB_GET() << 8; - if (SB_EOF()) - return; - ywinsize |= SB_GET(); - clientstat(TELOPT_NAWS, xwinsize, ywinsize); - - break; - - } /* end of case TELOPT_NAWS */ - - case TELOPT_STATUS: { - int mode; - - if (SB_EOF()) - break; - mode = SB_GET(); - switch (mode) { - case TELQUAL_SEND: - if (my_state_is_will(TELOPT_STATUS)) - send_status(); - break; - - case TELQUAL_IS: - break; - - default: - break; - } - break; - } /* end of case TELOPT_STATUS */ - - case TELOPT_XDISPLOC: { - if (SB_EOF() || SB_GET() != TELQUAL_IS) - return; - settimer(xdisplocsubopt); - subpointer[SB_LEN()] = '\0'; - esetenv("DISPLAY", (char *)subpointer, 1); - break; - } /* end of case TELOPT_XDISPLOC */ - -#ifdef TELOPT_NEW_ENVIRON - case TELOPT_NEW_ENVIRON: -#endif - case TELOPT_OLD_ENVIRON: { - int c; - char *cp, *varp, *valp; - - if (SB_EOF()) - return; - c = SB_GET(); - if (c == TELQUAL_IS) { - if (subchar == TELOPT_OLD_ENVIRON) - settimer(oenvironsubopt); - else - settimer(environsubopt); - } else if (c != TELQUAL_INFO) { - return; - } - -#ifdef TELOPT_NEW_ENVIRON - if (subchar == TELOPT_NEW_ENVIRON) { - while (!SB_EOF()) { - c = SB_GET(); - if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR)) - break; - } - } else -#endif - { -#ifdef ENV_HACK - /* - * We only want to do this if we haven't already decided - * whether or not the other side has its VALUE and VAR - * reversed. - */ - if (env_ovar < 0) { - int last = -1; /* invalid value */ - int empty = 0; - int got_var = 0, got_value = 0, got_uservar = 0; - - /* - * The other side might have its VALUE and VAR values - * reversed. To be interoperable, we need to determine - * which way it is. If the first recognized character - * is a VAR or VALUE, then that will tell us what - * type of client it is. If the fist recognized - * character is a USERVAR, then we continue scanning - * the suboption looking for two consecutive - * VAR or VALUE fields. We should not get two - * consecutive VALUE fields, so finding two - * consecutive VALUE or VAR fields will tell us - * what the client is. - */ - SB_SAVE(); - while (!SB_EOF()) { - c = SB_GET(); - switch(c) { - case OLD_ENV_VAR: - if (last < 0 || last == OLD_ENV_VAR - || (empty && (last == OLD_ENV_VALUE))) - goto env_ovar_ok; - got_var++; - last = OLD_ENV_VAR; - break; - case OLD_ENV_VALUE: - if (last < 0 || last == OLD_ENV_VALUE - || (empty && (last == OLD_ENV_VAR))) - goto env_ovar_wrong; - got_value++; - last = OLD_ENV_VALUE; - break; - case ENV_USERVAR: - /* count strings of USERVAR as one */ - if (last != ENV_USERVAR) - got_uservar++; - if (empty) { - if (last == OLD_ENV_VALUE) - goto env_ovar_ok; - if (last == OLD_ENV_VAR) - goto env_ovar_wrong; - } - last = ENV_USERVAR; - break; - case ENV_ESC: - if (!SB_EOF()) - c = SB_GET(); - /* FALL THROUGH */ - default: - empty = 0; - continue; - } - empty = 1; - } - if (empty) { - if (last == OLD_ENV_VALUE) - goto env_ovar_ok; - if (last == OLD_ENV_VAR) - goto env_ovar_wrong; - } - /* - * Ok, the first thing was a USERVAR, and there - * are not two consecutive VAR or VALUE commands, - * and none of the VAR or VALUE commands are empty. - * If the client has sent us a well-formed option, - * then the number of VALUEs received should always - * be less than or equal to the number of VARs and - * USERVARs received. - * - * If we got exactly as many VALUEs as VARs and - * USERVARs, the client has the same definitions. - * - * If we got exactly as many VARs as VALUEs and - * USERVARS, the client has reversed definitions. - */ - if (got_uservar + got_var == got_value) { - env_ovar_ok: - env_ovar = OLD_ENV_VAR; - env_ovalue = OLD_ENV_VALUE; - } else if (got_uservar + got_value == got_var) { - env_ovar_wrong: - env_ovar = OLD_ENV_VALUE; - env_ovalue = OLD_ENV_VAR; - DIAG(TD_OPTIONS, { - output_data("ENVIRON VALUE and VAR are reversed!\r\n"); - }); - - } - } - SB_RESTORE(); -#endif - - while (!SB_EOF()) { - c = SB_GET(); - if ((c == env_ovar) || (c == ENV_USERVAR)) - break; - } - } - - if (SB_EOF()) - return; - - cp = varp = (char *)subpointer; - valp = 0; - - while (!SB_EOF()) { - c = SB_GET(); - if (subchar == TELOPT_OLD_ENVIRON) { - if (c == env_ovar) - c = NEW_ENV_VAR; - else if (c == env_ovalue) - c = NEW_ENV_VALUE; - } - switch (c) { - - case NEW_ENV_VALUE: - *cp = '\0'; - cp = valp = (char *)subpointer; - break; - - case NEW_ENV_VAR: - case ENV_USERVAR: - *cp = '\0'; - if (valp) - esetenv(varp, valp, 1); - else - unsetenv(varp); - cp = varp = (char *)subpointer; - valp = 0; - break; - - case ENV_ESC: - if (SB_EOF()) - break; - c = SB_GET(); - /* FALL THROUGH */ - default: - *cp++ = c; - break; - } - } - *cp = '\0'; - if (valp) - esetenv(varp, valp, 1); - else - unsetenv(varp); - break; - } /* end of case TELOPT_NEW_ENVIRON */ -#ifdef AUTHENTICATION - case TELOPT_AUTHENTICATION: - if (SB_EOF()) - break; - switch(SB_GET()) { - case TELQUAL_SEND: - case TELQUAL_REPLY: - /* - * These are sent by us and cannot be sent by - * the client. - */ - break; - case TELQUAL_IS: - auth_is(subpointer, SB_LEN()); - break; - case TELQUAL_NAME: - auth_name(subpointer, SB_LEN()); - break; - } - break; -#endif -#ifdef ENCRYPTION - case TELOPT_ENCRYPT: - if (SB_EOF()) - break; - switch(SB_GET()) { - case ENCRYPT_SUPPORT: - encrypt_support(subpointer, SB_LEN()); - break; - case ENCRYPT_IS: - encrypt_is(subpointer, SB_LEN()); - break; - case ENCRYPT_REPLY: - encrypt_reply(subpointer, SB_LEN()); - break; - case ENCRYPT_START: - encrypt_start(subpointer, SB_LEN()); - break; - case ENCRYPT_END: - if (require_encryption) - fatal(net, "Output encryption is not possible to turn off"); - encrypt_end(); - break; - case ENCRYPT_REQSTART: - encrypt_request_start(subpointer, SB_LEN()); - break; - case ENCRYPT_REQEND: - /* - * We can always send an REQEND so that we cannot - * get stuck encrypting. We should only get this - * if we have been able to get in the correct mode - * anyhow. - */ - if (require_encryption) - fatal(net, "Input encryption is not possible to turn off"); - encrypt_request_end(); - break; - case ENCRYPT_ENC_KEYID: - encrypt_enc_keyid(subpointer, SB_LEN()); - break; - case ENCRYPT_DEC_KEYID: - encrypt_dec_keyid(subpointer, SB_LEN()); - break; - default: - break; - } - break; -#endif - - default: - break; - } /* end of switch */ - -} /* end of suboption */ - -void -doclientstat(void) -{ - clientstat(TELOPT_LINEMODE, WILL, 0); -} - -#undef ADD -#define ADD(c) *ncp++ = c -#define ADD_DATA(c) { *ncp++ = c; if (c == SE || c == IAC) *ncp++ = c; } - -void -send_status(void) -{ - unsigned char statusbuf[256]; - unsigned char *ncp; - unsigned char i; - - ncp = statusbuf; - - netflush(); /* get rid of anything waiting to go out */ - - ADD(IAC); - ADD(SB); - ADD(TELOPT_STATUS); - ADD(TELQUAL_IS); - - /* - * We check the want_state rather than the current state, - * because if we received a DO/WILL for an option that we - * don't support, and the other side didn't send a DONT/WONT - * in response to our WONT/DONT, then the "state" will be - * WILL/DO, and the "want_state" will be WONT/DONT. We - * need to go by the latter. - */ - for (i = 0; i < (unsigned char)NTELOPTS; i++) { - if (my_want_state_is_will(i)) { - ADD(WILL); - ADD_DATA(i); - } - if (his_want_state_is_will(i)) { - ADD(DO); - ADD_DATA(i); - } - } - - if (his_want_state_is_will(TELOPT_LFLOW)) { - ADD(SB); - ADD(TELOPT_LFLOW); - if (flowmode) { - ADD(LFLOW_ON); - } else { - ADD(LFLOW_OFF); - } - ADD(SE); - - if (restartany >= 0) { - ADD(SB); - ADD(TELOPT_LFLOW); - if (restartany) { - ADD(LFLOW_RESTART_ANY); - } else { - ADD(LFLOW_RESTART_XON); - } - ADD(SE); - } - } - - - ADD(IAC); - ADD(SE); - - writenet(statusbuf, ncp - statusbuf); - netflush(); /* Send it on its way */ - - DIAG(TD_OPTIONS, - {printsub('>', statusbuf, ncp - statusbuf); netflush();}); -} diff --git a/appl/telnet/telnetd/sys_term.c b/appl/telnet/telnetd/sys_term.c deleted file mode 100644 index 0a3bbff4a..000000000 --- a/appl/telnet/telnetd/sys_term.c +++ /dev/null @@ -1,1910 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "telnetd.h" - -RCSID("$Id$"); - -#if defined(_CRAY) || (defined(__hpux) && !defined(HAVE_UTMPX_H)) -# define PARENT_DOES_UTMP -#endif - -#ifdef HAVE_UTMP_H -#include -#endif - -#ifdef HAVE_UTMPX_H -#include -#endif - -#ifdef HAVE_UTMPX_H -struct utmpx wtmp; -#elif defined(HAVE_UTMP_H) -struct utmp wtmp; -#endif /* HAVE_UTMPX_H */ - -#ifdef HAVE_STRUCT_UTMP_UT_HOST -int utmp_len = sizeof(wtmp.ut_host); -#else -int utmp_len = MaxHostNameLen; -#endif - -#ifndef UTMP_FILE -#ifdef _PATH_UTMP -#define UTMP_FILE _PATH_UTMP -#else -#define UTMP_FILE "/etc/utmp" -#endif -#endif - -/* really, mac os uses wtmpx (or asl) */ -#ifdef __APPLE__ -#undef _PATH_WTMP -#endif - -#if !defined(WTMP_FILE) && defined(_PATH_WTMP) -#define WTMP_FILE _PATH_WTMP -#endif - -#ifndef PARENT_DOES_UTMP -#ifdef WTMP_FILE -char wtmpf[] = WTMP_FILE; -#else -char wtmpf[] = "/usr/adm/wtmp"; -#endif -char utmpf[] = UTMP_FILE; -#else /* PARENT_DOES_UTMP */ -#ifdef WTMP_FILE -char wtmpf[] = WTMP_FILE; -#else -char wtmpf[] = "/etc/wtmp"; -#endif -#endif /* PARENT_DOES_UTMP */ - -#ifdef HAVE_TMPDIR_H -#include -#endif /* CRAY */ - -#if !(defined(__sgi) || defined(__linux) || defined(_AIX)) && defined(HAVE_SYS_TTY) -#include -#endif -#ifdef t_erase -#undef t_erase -#undef t_kill -#undef t_intrc -#undef t_quitc -#undef t_startc -#undef t_stopc -#undef t_eofc -#undef t_brkc -#undef t_suspc -#undef t_dsuspc -#undef t_rprntc -#undef t_flushc -#undef t_werasc -#undef t_lnextc -#endif - -#ifdef HAVE_TERMIOS_H -#include -#else -#ifdef HAVE_TERMIO_H -#include -#endif -#endif - -#ifdef HAVE_UTIL_H -#include -#endif -#ifdef HAVE_LIBUTIL_H -#include -#endif - -# ifndef TCSANOW -# ifdef TCSETS -# define TCSANOW TCSETS -# define TCSADRAIN TCSETSW -# define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t) -# else -# ifdef TCSETA -# define TCSANOW TCSETA -# define TCSADRAIN TCSETAW -# define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t) -# else -# define TCSANOW TIOCSETA -# define TCSADRAIN TIOCSETAW -# define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t) -# endif -# endif -# define tcsetattr(f, a, t) ioctl(f, a, t) -# define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \ -(tp)->c_cflag |= (val) -# define cfgetospeed(tp) ((tp)->c_cflag & CBAUD) -# ifdef CIBAUD -# define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \ - (tp)->c_cflag |= ((val)<c_cflag & CIBAUD)>>IBSHIFT) -# else -# define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \ - (tp)->c_cflag |= (val) -# define cfgetispeed(tp) ((tp)->c_cflag & CBAUD) -# endif -# endif /* TCSANOW */ - struct termios termbuf, termbuf2; /* pty control structure */ -# ifdef STREAMSPTY - static int ttyfd = -1; - int really_stream = 0; -# else -#define really_stream 0 -# endif - - const char *new_login = _PATH_LOGIN; - -/* - * init_termbuf() - * copy_termbuf(cp) - * set_termbuf() - * - * These three routines are used to get and set the "termbuf" structure - * to and from the kernel. init_termbuf() gets the current settings. - * copy_termbuf() hands in a new "termbuf" to write to the kernel, and - * set_termbuf() writes the structure into the kernel. - */ - - void - init_termbuf(void) -{ -# ifdef STREAMSPTY - if (really_stream) - tcgetattr(ttyfd, &termbuf); - else -# endif - tcgetattr(ourpty, &termbuf); - termbuf2 = termbuf; -} - -void -set_termbuf(void) -{ - /* - * Only make the necessary changes. - */ - if (memcmp(&termbuf, &termbuf2, sizeof(termbuf))) { -# ifdef STREAMSPTY - if (really_stream) - tcsetattr(ttyfd, TCSANOW, &termbuf); - else -# endif - tcsetattr(ourpty, TCSANOW, &termbuf); - } -} - - -/* - * spcset(func, valp, valpp) - * - * This function takes various special characters (func), and - * sets *valp to the current value of that character, and - * *valpp to point to where in the "termbuf" structure that - * value is kept. - * - * It returns the SLC_ level of support for this function. - */ - - -int -spcset(int func, cc_t *valp, cc_t **valpp) -{ - -#define setval(a, b) *valp = termbuf.c_cc[a]; \ - *valpp = &termbuf.c_cc[a]; \ - return(b); -#define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT); - - switch(func) { - case SLC_EOF: - setval(VEOF, SLC_VARIABLE); - case SLC_EC: - setval(VERASE, SLC_VARIABLE); - case SLC_EL: - setval(VKILL, SLC_VARIABLE); - case SLC_IP: - setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); - case SLC_ABORT: - setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); - case SLC_XON: -#ifdef VSTART - setval(VSTART, SLC_VARIABLE); -#else - defval(0x13); -#endif - case SLC_XOFF: -#ifdef VSTOP - setval(VSTOP, SLC_VARIABLE); -#else - defval(0x11); -#endif - case SLC_EW: -#ifdef VWERASE - setval(VWERASE, SLC_VARIABLE); -#else - defval(0); -#endif - case SLC_RP: -#ifdef VREPRINT - setval(VREPRINT, SLC_VARIABLE); -#else - defval(0); -#endif - case SLC_LNEXT: -#ifdef VLNEXT - setval(VLNEXT, SLC_VARIABLE); -#else - defval(0); -#endif - case SLC_AO: -#if !defined(VDISCARD) && defined(VFLUSHO) -# define VDISCARD VFLUSHO -#endif -#ifdef VDISCARD - setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT); -#else - defval(0); -#endif - case SLC_SUSP: -#ifdef VSUSP - setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN); -#else - defval(0); -#endif -#ifdef VEOL - case SLC_FORW1: - setval(VEOL, SLC_VARIABLE); -#endif -#ifdef VEOL2 - case SLC_FORW2: - setval(VEOL2, SLC_VARIABLE); -#endif - case SLC_AYT: -#ifdef VSTATUS - setval(VSTATUS, SLC_VARIABLE); -#else - defval(0); -#endif - - case SLC_BRK: - case SLC_SYNCH: - case SLC_EOR: - defval(0); - - default: - *valp = 0; - *valpp = 0; - return(SLC_NOSUPPORT); - } -} - -#ifdef _CRAY -/* - * getnpty() - * - * Return the number of pty's configured into the system. - */ -int -getnpty() -{ -#ifdef _SC_CRAY_NPTY - int numptys; - - if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1) - return numptys; - else -#endif /* _SC_CRAY_NPTY */ - return 128; -} -#endif /* CRAY */ - -/* - * getpty() - * - * Allocate a pty. As a side effect, the external character - * array "line" contains the name of the slave side. - * - * Returns the file descriptor of the opened pty. - */ - -static int ptyslavefd = -1; - -static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; -char *line = Xline; - -#ifdef _CRAY -char myline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; -#endif /* CRAY */ - -#if !defined(HAVE_PTSNAME) && defined(STREAMSPTY) -static char *ptsname(int fd) -{ -#ifdef HAVE_TTYNAME - return ttyname(fd); -#else - return NULL; -#endif -} -#endif - -int getpty(int *ptynum) -{ -#if defined(HAVE_OPENPTY) || defined(__linux) || defined(__osf__) /* XXX */ - { - int master; - int slave; - if(openpty(&master, &slave, line, 0, 0) == 0){ - ptyslavefd = slave; - return master; - } - } -#endif /* HAVE_OPENPTY .... */ -#ifdef HAVE__GETPTY - { - int master; - char *p; - p = _getpty(&master, O_RDWR, 0600, 1); - if(p == NULL) - return -1; - strlcpy(line, p, sizeof(Xline)); - return master; - } -#endif - -#ifdef STREAMSPTY - { - char *clone[] = { "/dev/ptc", "/dev/ptmx", "/dev/ptm", - "/dev/ptym/clone", 0 }; - - char **q; - int p; - for(q=clone; *q; q++){ - p=open(*q, O_RDWR); - if(p >= 0){ -#ifdef HAVE_GRANTPT - grantpt(p); -#endif -#ifdef HAVE_UNLOCKPT - unlockpt(p); -#endif - strlcpy(line, ptsname(p), sizeof(Xline)); - really_stream = 1; - return p; - } - } - } -#endif /* STREAMSPTY */ -#ifndef _CRAY - { - int p; - char *cp, *p1, *p2; - int i; - -#ifndef __hpux - snprintf(line, sizeof(Xline), "/dev/ptyXX"); - p1 = &line[8]; - p2 = &line[9]; -#else - snprintf(line, sizeof(Xline), "/dev/ptym/ptyXX"); - p1 = &line[13]; - p2 = &line[14]; -#endif - - - for (cp = "pqrstuvwxyzPQRST"; *cp; cp++) { - struct stat stb; - - *p1 = *cp; - *p2 = '0'; - /* - * This stat() check is just to keep us from - * looping through all 256 combinations if there - * aren't that many ptys available. - */ - if (stat(line, &stb) < 0) - break; - for (i = 0; i < 16; i++) { - *p2 = "0123456789abcdef"[i]; - p = open(line, O_RDWR); - if (p > 0) { -#if SunOS == 40 - int dummy; -#endif - -#ifndef __hpux - line[5] = 't'; -#else - for (p1 = &line[8]; *p1; p1++) - *p1 = *(p1+1); - line[9] = 't'; -#endif - chown(line, 0, 0); - chmod(line, 0600); -#if SunOS == 40 - if (ioctl(p, TIOCGPGRP, &dummy) == 0 - || errno != EIO) { - chmod(line, 0666); - close(p); - line[5] = 'p'; - } else -#endif /* SunOS == 40 */ - return(p); - } - } - } - } -#else /* CRAY */ - { - extern lowpty, highpty; - struct stat sb; - int p; - - for (*ptynum = lowpty; *ptynum <= highpty; (*ptynum)++) { - snprintf(myline, sizeof(myline), "/dev/pty/%03d", *ptynum); - p = open(myline, 2); - if (p < 0) - continue; - snprintf(line, sizeof(Xline), "/dev/ttyp%03d", *ptynum); - /* - * Here are some shenanigans to make sure that there - * are no listeners lurking on the line. - */ - if(stat(line, &sb) < 0) { - close(p); - continue; - } - if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) { - chown(line, 0, 0); - chmod(line, 0600); - close(p); - p = open(myline, 2); - if (p < 0) - continue; - } - /* - * Now it should be safe...check for accessability. - */ - if (access(line, 6) == 0) - return(p); - else { - /* no tty side to pty so skip it */ - close(p); - } - } - } -#endif /* CRAY */ - return(-1); -} - - -int -tty_isecho(void) -{ - return (termbuf.c_lflag & ECHO); -} - -int -tty_flowmode(void) -{ - return((termbuf.c_iflag & IXON) ? 1 : 0); -} - -int -tty_restartany(void) -{ - return((termbuf.c_iflag & IXANY) ? 1 : 0); -} - -void -tty_setecho(int on) -{ - if (on) - termbuf.c_lflag |= ECHO; - else - termbuf.c_lflag &= ~ECHO; -} - -int -tty_israw(void) -{ - return(!(termbuf.c_lflag & ICANON)); -} - -void -tty_binaryin(int on) -{ - if (on) { - termbuf.c_iflag &= ~ISTRIP; - } else { - termbuf.c_iflag |= ISTRIP; - } -} - -void -tty_binaryout(int on) -{ - if (on) { - termbuf.c_cflag &= ~(CSIZE|PARENB); - termbuf.c_cflag |= CS8; - termbuf.c_oflag &= ~OPOST; - } else { - termbuf.c_cflag &= ~CSIZE; - termbuf.c_cflag |= CS7|PARENB; - termbuf.c_oflag |= OPOST; - } -} - -int -tty_isbinaryin(void) -{ - return(!(termbuf.c_iflag & ISTRIP)); -} - -int -tty_isbinaryout(void) -{ - return(!(termbuf.c_oflag&OPOST)); -} - - -int -tty_issofttab(void) -{ -# ifdef OXTABS - return (termbuf.c_oflag & OXTABS); -# endif -# ifdef TABDLY - return ((termbuf.c_oflag & TABDLY) == TAB3); -# endif -} - -void -tty_setsofttab(int on) -{ - if (on) { -# ifdef OXTABS - termbuf.c_oflag |= OXTABS; -# endif -# ifdef TABDLY - termbuf.c_oflag &= ~TABDLY; - termbuf.c_oflag |= TAB3; -# endif - } else { -# ifdef OXTABS - termbuf.c_oflag &= ~OXTABS; -# endif -# ifdef TABDLY - termbuf.c_oflag &= ~TABDLY; - termbuf.c_oflag |= TAB0; -# endif - } -} - -int -tty_islitecho(void) -{ -# ifdef ECHOCTL - return (!(termbuf.c_lflag & ECHOCTL)); -# endif -# ifdef TCTLECH - return (!(termbuf.c_lflag & TCTLECH)); -# endif -# if !defined(ECHOCTL) && !defined(TCTLECH) - return (0); /* assumes ctl chars are echoed '^x' */ -# endif -} - -void -tty_setlitecho(int on) -{ -# ifdef ECHOCTL - if (on) - termbuf.c_lflag &= ~ECHOCTL; - else - termbuf.c_lflag |= ECHOCTL; -# endif -# ifdef TCTLECH - if (on) - termbuf.c_lflag &= ~TCTLECH; - else - termbuf.c_lflag |= TCTLECH; -# endif -} - -int -tty_iscrnl(void) -{ - return (termbuf.c_iflag & ICRNL); -} - -/* - * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD). - */ -#if B4800 != 4800 -#define DECODE_BAUD -#endif - -#ifdef DECODE_BAUD - -/* - * A table of available terminal speeds - */ -struct termspeeds { - int speed; - int value; -} termspeeds[] = { - { 0, B0 }, { 50, B50 }, { 75, B75 }, - { 110, B110 }, { 134, B134 }, { 150, B150 }, - { 200, B200 }, { 300, B300 }, { 600, B600 }, - { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, - { 4800, B4800 }, -#ifdef B7200 - { 7200, B7200 }, -#endif - { 9600, B9600 }, -#ifdef B14400 - { 14400, B14400 }, -#endif -#ifdef B19200 - { 19200, B19200 }, -#endif -#ifdef B28800 - { 28800, B28800 }, -#endif -#ifdef B38400 - { 38400, B38400 }, -#endif -#ifdef B57600 - { 57600, B57600 }, -#endif -#ifdef B115200 - { 115200, B115200 }, -#endif -#ifdef B230400 - { 230400, B230400 }, -#endif - { -1, 0 } -}; -#endif /* DECODE_BUAD */ - -void -tty_tspeed(int val) -{ -#ifdef DECODE_BAUD - struct termspeeds *tp; - - for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) - ; - if (tp->speed == -1) /* back up to last valid value */ - --tp; - cfsetospeed(&termbuf, tp->value); -#else /* DECODE_BUAD */ - cfsetospeed(&termbuf, val); -#endif /* DECODE_BUAD */ -} - -void -tty_rspeed(int val) -{ -#ifdef DECODE_BAUD - struct termspeeds *tp; - - for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) - ; - if (tp->speed == -1) /* back up to last valid value */ - --tp; - cfsetispeed(&termbuf, tp->value); -#else /* DECODE_BAUD */ - cfsetispeed(&termbuf, val); -#endif /* DECODE_BAUD */ -} - -#ifdef PARENT_DOES_UTMP -extern struct utmp wtmp; -extern char wtmpf[]; - -extern void utmp_sig_init (void); -extern void utmp_sig_reset (void); -extern void utmp_sig_wait (void); -extern void utmp_sig_notify (int); -# endif /* PARENT_DOES_UTMP */ - -#ifdef STREAMSPTY - -/* I_FIND seems to live a life of its own */ -static int my_find(int fd, char *module) -{ -#if defined(I_FIND) && defined(I_LIST) - static int flag; - static struct str_list sl; - int n; - int i; - - if(!flag){ - n = ioctl(fd, I_LIST, 0); - if(n < 0){ - perror("ioctl(fd, I_LIST, 0)"); - return -1; - } - sl.sl_modlist=(struct str_mlist*)malloc(n * sizeof(struct str_mlist)); - sl.sl_nmods = n; - n = ioctl(fd, I_LIST, &sl); - if(n < 0){ - perror("ioctl(fd, I_LIST, n)"); - return -1; - } - flag = 1; - } - - for(i=0; i= modules; p--){ - err = ioctl(fd, I_PUSH, *p); - if(err < 0 && errno != EINVAL) - fatalperror(net, "I_PUSH"); - } -} -#endif - -/* - * getptyslave() - * - * Open the slave side of the pty, and do any initialization - * that is necessary. The return value is a file descriptor - * for the slave side. - */ -void getptyslave(void) -{ - int t = -1; - - struct winsize ws; - /* - * Opening the slave side may cause initilization of the - * kernel tty structure. We need remember the state of - * if linemode was turned on - * terminal window size - * terminal speed - * so that we can re-set them if we need to. - */ - - - /* - * Make sure that we don't have a controlling tty, and - * that we are the session (process group) leader. - */ - -#ifdef HAVE_SETSID - if(setsid()<0) - fatalperror(net, "setsid()"); -#else -# ifdef TIOCNOTTY - t = open(_PATH_TTY, O_RDWR); - if (t >= 0) { - ioctl(t, TIOCNOTTY, (char *)0); - close(t); - } -# endif -#endif - -# ifdef PARENT_DOES_UTMP - /* - * Wait for our parent to get the utmp stuff to get done. - */ - utmp_sig_wait(); -# endif - - t = cleanopen(line); - if (t < 0) - fatalperror(net, line); - -#ifdef STREAMSPTY - ttyfd = t; - - - /* - * Not all systems have (or need) modules ttcompat and pckt so - * don't flag it as a fatal error if they don't exist. - */ - - if (really_stream) - { - /* these are the streams modules that we want pushed. note - that they are in reverse order, ptem will be pushed - first. maybe_push_modules() will try to push all modules - before the first one that isn't already pushed. i.e if - ldterm is pushed, only ttcompat will be attempted. - - all this is because we don't know which modules are - available, and we don't know which modules are already - pushed (via autopush, for instance). - - */ - - char *ttymodules[] = { "ttcompat", "ldterm", "ptem", NULL }; - char *ptymodules[] = { "pckt", NULL }; - - maybe_push_modules(t, ttymodules); - maybe_push_modules(ourpty, ptymodules); - } -#endif - /* - * set up the tty modes as we like them to be. - */ - init_termbuf(); -# ifdef TIOCSWINSZ - if (def_row || def_col) { - memset(&ws, 0, sizeof(ws)); - ws.ws_col = def_col; - ws.ws_row = def_row; - ioctl(t, TIOCSWINSZ, (char *)&ws); - } -# endif - - /* - * Settings for sgtty based systems - */ - - /* - * Settings for UNICOS (and HPUX) - */ -# if defined(_CRAY) || defined(__hpux) - termbuf.c_oflag = OPOST|ONLCR|TAB3; - termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON; - termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK; - termbuf.c_cflag = EXTB|HUPCL|CS8; -# endif - - /* - * Settings for all other termios/termio based - * systems, other than 4.4BSD. In 4.4BSD the - * kernel does the initial terminal setup. - */ -# if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43) -# ifndef OXTABS -# define OXTABS 0 -# endif - termbuf.c_lflag |= ECHO; - termbuf.c_oflag |= ONLCR|OXTABS; - termbuf.c_iflag |= ICRNL; - termbuf.c_iflag &= ~IXOFF; -# endif - tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600); - tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600); - - /* - * Set the tty modes, and make this our controlling tty. - */ - set_termbuf(); - if (login_tty(t) == -1) - fatalperror(net, "login_tty"); - if (net > 2) - close(net); - if (ourpty > 2) { - close(ourpty); - ourpty = -1; - } -} - -#ifndef O_NOCTTY -#define O_NOCTTY 0 -#endif -/* - * Open the specified slave side of the pty, - * making sure that we have a clean tty. - */ - -int cleanopen(char *line) -{ - int t; - - if (ptyslavefd != -1) - return ptyslavefd; - -#ifdef STREAMSPTY - if (!really_stream) -#endif - { - /* - * Make sure that other people can't open the - * slave side of the connection. - */ - chown(line, 0, 0); - chmod(line, 0600); - } - -#ifdef HAVE_REVOKE - revoke(line); -#endif - - t = open(line, O_RDWR|O_NOCTTY); - - if (t < 0) - return(-1); - - /* - * Hangup anybody else using this ttyp, then reopen it for - * ourselves. - */ -# if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY) - signal(SIGHUP, SIG_IGN); -#ifdef HAVE_VHANGUP - vhangup(); -#else -#endif - signal(SIGHUP, SIG_DFL); - t = open(line, O_RDWR|O_NOCTTY); - if (t < 0) - return(-1); -# endif -# if defined(_CRAY) && defined(TCVHUP) - { - int i; - signal(SIGHUP, SIG_IGN); - ioctl(t, TCVHUP, (char *)0); - signal(SIGHUP, SIG_DFL); - - i = open(line, O_RDWR); - - if (i < 0) - return(-1); - close(t); - t = i; - } -# endif /* defined(CRAY) && defined(TCVHUP) */ - return(t); -} - -#if !defined(BSD4_4) - -int login_tty(int t) -{ - /* Dont need to set this as the controlling PTY on steams sockets, - * don't abort on failure. */ -# if defined(TIOCSCTTY) && !defined(__hpux) - if (ioctl(t, TIOCSCTTY, (char *)0) < 0 && !really_stream) - fatalperror(net, "ioctl(sctty)"); -# ifdef _CRAY - /* - * Close the hard fd to /dev/ttypXXX, and re-open through - * the indirect /dev/tty interface. - */ - close(t); - if ((t = open("/dev/tty", O_RDWR)) < 0) - fatalperror(net, "open(/dev/tty)"); -# endif -# else - /* - * We get our controlling tty assigned as a side-effect - * of opening up a tty device. But on BSD based systems, - * this only happens if our process group is zero. The - * setsid() call above may have set our pgrp, so clear - * it out before opening the tty... - */ -#ifdef HAVE_SETPGID - setpgid(0, 0); -#else - setpgrp(0, 0); /* if setpgid isn't available, setpgrp - probably takes arguments */ -#endif - close(open(line, O_RDWR)); -# endif - if (t != 0) - dup2(t, 0); - if (t != 1) - dup2(t, 1); - if (t != 2) - dup2(t, 2); - if (t > 2) - close(t); - return(0); -} -#endif /* BSD <= 43 */ - -/* - * This comes from ../../bsd/tty.c and should not really be here. - */ - -/* - * Clean the tty name. Return a pointer to the cleaned version. - */ - -static char * clean_ttyname (char *) __attribute__((unused)); - -static char * -clean_ttyname (char *tty) -{ - char *res = tty; - - if (strncmp (res, _PATH_DEV, strlen(_PATH_DEV)) == 0) - res += strlen(_PATH_DEV); - if (strncmp (res, "pty/", 4) == 0) - res += 4; - if (strncmp (res, "ptym/", 5) == 0) - res += 5; - return res; -} - -/* - * Generate a name usable as an `ut_id', typically without `tty'. - */ - -#ifdef HAVE_STRUCT_UTMP_UT_ID -static char * -make_id (char *tty) -{ - char *res = tty; - - if (strncmp (res, "pts/", 4) == 0) - res += 4; - if (strncmp (res, "tty", 3) == 0) - res += 3; - return res; -} -#endif - -/* - * startslave(host) - * - * Given a hostname, do whatever - * is necessary to startup the login process on the slave side of the pty. - */ - -/* ARGSUSED */ -void -startslave(const char *host, const char *utmp_host, - int autologin, char *autoname) -{ - int i; - -#ifdef AUTHENTICATION - if (!autoname || !autoname[0]) - autologin = 0; - - if (autologin < auth_level) { - fatal(net, "Authorization failed"); - exit(1); - } -#endif - - { - char *tbuf = - "\r\n*** Connection not encrypted! " - "Communication may be eavesdropped. ***\r\n"; -#ifdef ENCRYPTION - if (!no_warn && (encrypt_output == 0 || decrypt_input == 0)) -#endif - writenet(tbuf, strlen(tbuf)); - } -# ifdef PARENT_DOES_UTMP - utmp_sig_init(); -# endif /* PARENT_DOES_UTMP */ - - if ((i = fork()) < 0) - fatalperror(net, "fork"); - if (i) { -# ifdef PARENT_DOES_UTMP - /* - * Cray parent will create utmp entry for child and send - * signal to child to tell when done. Child waits for signal - * before doing anything important. - */ - int pid = i; - void sigjob (int); - - setpgrp(); - utmp_sig_reset(); /* reset handler to default */ - /* - * Create utmp entry for child - */ - wtmp.ut_time = time(NULL); - wtmp.ut_type = LOGIN_PROCESS; - wtmp.ut_pid = pid; - strncpy(wtmp.ut_user, "LOGIN", sizeof(wtmp.ut_user)); - strncpy(wtmp.ut_host, utmp_host, sizeof(wtmp.ut_host)); - strncpy(wtmp.ut_line, clean_ttyname(line), sizeof(wtmp.ut_line)); -#ifdef HAVE_STRUCT_UTMP_UT_ID - strncpy(wtmp.ut_id, wtmp.ut_line + 3, sizeof(wtmp.ut_id)); -#endif - - pututline(&wtmp); - endutent(); - if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) { - write(i, &wtmp, sizeof(struct utmp)); - close(i); - } -#ifdef _CRAY - signal(WJSIGNAL, sigjob); -#endif - utmp_sig_notify(pid); -# endif /* PARENT_DOES_UTMP */ - } else { - getptyslave(); -#if defined(DCE) - /* if we authenticated via K5, try and join the PAG */ - kerberos5_dfspag(); -#endif - start_login(host, autologin, autoname); - /*NOTREACHED*/ - } -} - -char *envinit[3]; -#if !HAVE_DECL_ENVIRON -extern char **environ; -#endif - -void -init_env(void) -{ - char **envp; - - envp = envinit; - if ((*envp = getenv("TZ"))) - *envp++ -= 3; -#if defined(_CRAY) || defined(__hpux) - else - *envp++ = "TZ=GMT0"; -#endif - *envp = 0; - environ = envinit; -} - -/* - * scrub_env() - * - * We only accept the environment variables listed below. - */ - -static void -scrub_env(void) -{ - static const char *reject[] = { - "TERMCAP=/", - NULL - }; - - static const char *accept[] = { - "XAUTH=", "XAUTHORITY=", "DISPLAY=", - "TERM=", - "EDITOR=", - "PAGER=", - "PRINTER=", - "LOGNAME=", - "POSIXLY_CORRECT=", - "TERMCAP=", - NULL - }; - - char **cpp, **cpp2; - const char **p; - - for (cpp2 = cpp = environ; *cpp; cpp++) { - int reject_it = 0; - - for(p = reject; *p; p++) - if(strncmp(*cpp, *p, strlen(*p)) == 0) { - reject_it = 1; - break; - } - if (reject_it) - continue; - - for(p = accept; *p; p++) - if(strncmp(*cpp, *p, strlen(*p)) == 0) - break; - if(*p != NULL) - *cpp2++ = *cpp; - } - *cpp2 = NULL; -} - - -struct arg_val { - int size; - int argc; - char **argv; -}; - -static void addarg(struct arg_val*, const char*); - -/* - * start_login(host) - * - * Assuming that we are now running as a child processes, this - * function will turn us into the login process. - */ - -void -start_login(const char *host, int autologin, char *name) -{ - struct arg_val argv; - char *user; - int save_errno; - -#ifdef ENCRYPTION - encrypt_output = NULL; - decrypt_input = NULL; -#endif - -#ifdef HAVE_UTMPX_H - { - int pid = getpid(); - struct utmpx utmpx; - struct timeval tv; - char *clean_tty; - - /* - * Create utmp entry for child - */ - - clean_tty = clean_ttyname(line); - memset(&utmpx, 0, sizeof(utmpx)); - strncpy(utmpx.ut_user, ".telnet", sizeof(utmpx.ut_user)); - strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line)); -#ifdef HAVE_STRUCT_UTMP_UT_ID - strncpy(utmpx.ut_id, make_id(clean_tty), sizeof(utmpx.ut_id)); -#endif - utmpx.ut_pid = pid; - - utmpx.ut_type = LOGIN_PROCESS; - - gettimeofday (&tv, NULL); - utmpx.ut_tv.tv_sec = tv.tv_sec; - utmpx.ut_tv.tv_usec = tv.tv_usec; - - if (pututxline(&utmpx) == NULL) - fatal(net, "pututxline failed"); - } -#endif - - scrub_env(); - - /* - * -h : pass on name of host. - * WARNING: -h is accepted by login if and only if - * getuid() == 0. - * -p : don't clobber the environment (so terminal type stays set). - * - * -f : force this login, he has already been authenticated - */ - - /* init argv structure */ - argv.size=0; - argv.argc=0; - argv.argv=malloc(0); /*so we can call realloc later */ - addarg(&argv, "login"); - addarg(&argv, "-h"); - addarg(&argv, host); - addarg(&argv, "-p"); - if(name && name[0]) - user = name; - else - user = getenv("USER"); -#ifdef AUTHENTICATION - if (auth_level < 0 || autologin != AUTH_VALID) { - if(!no_warn) { - printf("User not authenticated. "); - if (require_otp) - printf("Using one-time password\r\n"); - else - printf("Using plaintext username and password\r\n"); - } - if (require_otp) { - addarg(&argv, "-a"); - addarg(&argv, "otp"); - } - if(log_unauth) - syslog(LOG_INFO, "unauthenticated access from %s (%s)", - host, user ? user : "unknown user"); - } - if (auth_level >= 0 && autologin == AUTH_VALID) - addarg(&argv, "-f"); -#endif - if(user){ - addarg(&argv, "--"); - addarg(&argv, strdup(user)); - } - if (getenv("USER")) { - /* - * Assume that login will set the USER variable - * correctly. For SysV systems, this means that - * USER will no longer be set, just LOGNAME by - * login. (The problem is that if the auto-login - * fails, and the user then specifies a different - * account name, he can get logged in with both - * LOGNAME and USER in his environment, but the - * USER value will be wrong. - */ - unsetenv("USER"); - } - closelog(); - /* - * This sleep(1) is in here so that telnetd can - * finish up with the tty. There's a race condition - * the login banner message gets lost... - */ - sleep(1); - - execv(new_login, argv.argv); - save_errno = errno; - syslog(LOG_ERR, "%s: %m", new_login); - fatalperror_errno(net, new_login, save_errno); - /*NOTREACHED*/ -} - -static void -addarg(struct arg_val *argv, const char *val) -{ - if(argv->size <= argv->argc+1) { - argv->argv = realloc(argv->argv, sizeof(char*) * (argv->size + 10)); - if (argv->argv == NULL) - fatal (net, "realloc: out of memory"); - argv->size+=10; - } - if((argv->argv[argv->argc++] = strdup(val)) == NULL) - fatal (net, "strdup: out of memory"); - argv->argv[argv->argc] = NULL; -} - - -/* - * rmut() - * - * This is the function called by cleanup() to - * remove the utmp entry for this person. - */ - -#ifdef HAVE_UTMPX_H -static void -rmut(void) -{ - struct utmpx utmpx, *non_save_utxp; - char *clean_tty = clean_ttyname(line); - - /* - * This updates the utmpx and utmp entries and make a wtmp/x entry - */ - - setutxent(); - memset(&utmpx, 0, sizeof(utmpx)); - strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line)); - utmpx.ut_type = LOGIN_PROCESS; - non_save_utxp = getutxline(&utmpx); - if (non_save_utxp) { - struct utmpx *utxp; - struct timeval tv; - char user0; - - utxp = malloc(sizeof(struct utmpx)); - *utxp = *non_save_utxp; - user0 = utxp->ut_user[0]; - utxp->ut_user[0] = '\0'; - utxp->ut_type = DEAD_PROCESS; -#ifdef HAVE_STRUCT_UTMPX_UT_EXIT -#ifdef _STRUCT___EXIT_STATUS - utxp->ut_exit.__e_termination = 0; - utxp->ut_exit.__e_exit = 0; -#elif defined(__osf__) /* XXX */ - utxp->ut_exit.ut_termination = 0; - utxp->ut_exit.ut_exit = 0; -#else - utxp->ut_exit.e_termination = 0; - utxp->ut_exit.e_exit = 0; -#endif -#endif - gettimeofday (&tv, NULL); - utxp->ut_tv.tv_sec = tv.tv_sec; - utxp->ut_tv.tv_usec = tv.tv_usec; - - pututxline(utxp); -#ifdef WTMPX_FILE - utxp->ut_user[0] = user0; - updwtmpx(WTMPX_FILE, utxp); -#elif defined(WTMP_FILE) - /* This is a strange system with a utmpx and a wtmp! */ - { - int f = open(wtmpf, O_WRONLY|O_APPEND); - struct utmp wtmp; - if (f >= 0) { - strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line)); - strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name)); -#ifdef HAVE_STRUCT_UTMP_UT_HOST - strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host)); -#endif - wtmp.ut_time = time(NULL); - write(f, &wtmp, sizeof(wtmp)); - close(f); - } - } -#endif - free (utxp); - } - endutxent(); -} /* end of rmut */ -#endif - -#if !defined(HAVE_UTMPX_H) && !(defined(_CRAY) || defined(__hpux)) && BSD <= 43 -static void -rmut(void) -{ - int f; - int found = 0; - struct utmp *u, *utmp; - int nutmp; - struct stat statbf; - char *clean_tty = clean_ttyname(line); - - f = open(utmpf, O_RDWR); - if (f >= 0) { - fstat(f, &statbf); - utmp = (struct utmp *)malloc((unsigned)statbf.st_size); - if (!utmp) - syslog(LOG_ERR, "utmp malloc failed"); - if (statbf.st_size && utmp) { - nutmp = read(f, utmp, (int)statbf.st_size); - nutmp /= sizeof(struct utmp); - - for (u = utmp ; u < &utmp[nutmp] ; u++) { - if (strncmp(u->ut_line, - clean_tty, - sizeof(u->ut_line)) || - u->ut_name[0]==0) - continue; - lseek(f, ((long)u)-((long)utmp), L_SET); - strncpy(u->ut_name, "", sizeof(u->ut_name)); -#ifdef HAVE_STRUCT_UTMP_UT_HOST - strncpy(u->ut_host, "", sizeof(u->ut_host)); -#endif - u->ut_time = time(NULL); - write(f, u, sizeof(wtmp)); - found++; - } - } - close(f); - } - if (found) { - f = open(wtmpf, O_WRONLY|O_APPEND); - if (f >= 0) { - strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line)); - strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name)); -#ifdef HAVE_STRUCT_UTMP_UT_HOST - strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host)); -#endif - wtmp.ut_time = time(NULL); - write(f, &wtmp, sizeof(wtmp)); - close(f); - } - } - chmod(line, 0666); - chown(line, 0, 0); - line[strlen("/dev/")] = 'p'; - chmod(line, 0666); - chown(line, 0, 0); -} /* end of rmut */ -#endif /* CRAY */ - -#if defined(__hpux) && !defined(HAVE_UTMPX_H) -static void -rmut (char *line) -{ - struct utmp utmp; - struct utmp *utptr; - int fd; /* for /etc/wtmp */ - - utmp.ut_type = USER_PROCESS; - strncpy(utmp.ut_line, clean_ttyname(line), sizeof(utmp.ut_line)); - setutent(); - utptr = getutline(&utmp); - /* write it out only if it exists */ - if (utptr) { - utptr->ut_type = DEAD_PROCESS; - utptr->ut_time = time(NULL); - pututline(utptr); - /* set wtmp entry if wtmp file exists */ - if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) { - write(fd, utptr, sizeof(utmp)); - close(fd); - } - } - endutent(); - - chmod(line, 0666); - chown(line, 0, 0); - line[14] = line[13]; - line[13] = line[12]; - line[8] = 'm'; - line[9] = '/'; - line[10] = 'p'; - line[11] = 't'; - line[12] = 'y'; - chmod(line, 0666); - chown(line, 0, 0); -} -#endif - -/* - * cleanup() - * - * This is the routine to call when we are all through, to - * clean up anything that needs to be cleaned up. - */ - -#ifdef PARENT_DOES_UTMP - -void -cleanup(int sig) -{ -#ifdef _CRAY - static int incleanup = 0; - int t; - int child_status; /* status of child process as returned by waitpid */ - int flags = WNOHANG|WUNTRACED; - - /* - * 1: Pick up the zombie, if we are being called - * as the signal handler. - * 2: If we are a nested cleanup(), return. - * 3: Try to clean up TMPDIR. - * 4: Fill in utmp with shutdown of process. - * 5: Close down the network and pty connections. - * 6: Finish up the TMPDIR cleanup, if needed. - */ - if (sig == SIGCHLD) { - while (waitpid(-1, &child_status, flags) > 0) - ; /* VOID */ - /* Check if the child process was stopped - * rather than exited. We want cleanup only if - * the child has died. - */ - if (WIFSTOPPED(child_status)) { - return; - } - } - t = sigblock(sigmask(SIGCHLD)); - if (incleanup) { - sigsetmask(t); - return; - } - incleanup = 1; - sigsetmask(t); - - t = cleantmp(&wtmp); - setutent(); /* just to make sure */ -#endif /* CRAY */ - rmut(line); - close(ourpty); - shutdown(net, 2); -#ifdef _CRAY - if (t == 0) - cleantmp(&wtmp); -#endif /* CRAY */ - exit(1); -} - -#else /* PARENT_DOES_UTMP */ - -void -cleanup(int sig) -{ -#if defined(HAVE_UTMPX_H) || !defined(HAVE_LOGWTMP) - rmut(); -#ifdef HAVE_VHANGUP -#ifndef __sgi - vhangup(); /* XXX */ -#endif -#endif -#else - char *p; - - p = line + sizeof("/dev/") - 1; - if (logout(p)) - logwtmp(p, "", ""); - chmod(line, 0666); - chown(line, 0, 0); - *p = 'p'; - chmod(line, 0666); - chown(line, 0, 0); -#endif - shutdown(net, 2); - exit(1); -} - -#endif /* PARENT_DOES_UTMP */ - -#ifdef PARENT_DOES_UTMP -/* - * _utmp_sig_rcv - * utmp_sig_init - * utmp_sig_wait - * These three functions are used to coordinate the handling of - * the utmp file between the server and the soon-to-be-login shell. - * The server actually creates the utmp structure, the child calls - * utmp_sig_wait(), until the server calls utmp_sig_notify() and - * signals the future-login shell to proceed. - */ -static int caught=0; /* NZ when signal intercepted */ -static void (*func)(); /* address of previous handler */ - -void -_utmp_sig_rcv(sig) - int sig; -{ - caught = 1; - signal(SIGUSR1, func); -} - -void -utmp_sig_init() -{ - /* - * register signal handler for UTMP creation - */ - if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1) - fatalperror(net, "telnetd/signal"); -} - -void -utmp_sig_reset() -{ - signal(SIGUSR1, func); /* reset handler to default */ -} - -# ifdef __hpux -# define sigoff() /* do nothing */ -# define sigon() /* do nothing */ -# endif - -void -utmp_sig_wait() -{ - /* - * Wait for parent to write our utmp entry. - */ - sigoff(); - while (caught == 0) { - pause(); /* wait until we get a signal (sigon) */ - sigoff(); /* turn off signals while we check caught */ - } - sigon(); /* turn on signals again */ -} - -void -utmp_sig_notify(pid) -{ - kill(pid, SIGUSR1); -} - -#ifdef _CRAY -static int gotsigjob = 0; - - /*ARGSUSED*/ -void -sigjob(sig) - int sig; -{ - int jid; - struct jobtemp *jp; - - while ((jid = waitjob(NULL)) != -1) { - if (jid == 0) { - return; - } - gotsigjob++; - jobend(jid, NULL, NULL); - } -} - -/* - * jid_getutid: - * called by jobend() before calling cleantmp() - * to find the correct $TMPDIR to cleanup. - */ - -struct utmp * -jid_getutid(jid) - int jid; -{ - struct utmp *cur = NULL; - - setutent(); /* just to make sure */ - while (cur = getutent()) { - if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) { - return(cur); - } - } - - return(0); -} - -/* - * Clean up the TMPDIR that login created. - * The first time this is called we pick up the info - * from the utmp. If the job has already gone away, - * then we'll clean up and be done. If not, then - * when this is called the second time it will wait - * for the signal that the job is done. - */ -int -cleantmp(wtp) - struct utmp *wtp; -{ - struct utmp *utp; - static int first = 1; - int mask, omask, ret; - extern struct utmp *getutid (const struct utmp *_Id); - - - mask = sigmask(WJSIGNAL); - - if (first == 0) { - omask = sigblock(mask); - while (gotsigjob == 0) - sigpause(omask); - return(1); - } - first = 0; - setutent(); /* just to make sure */ - - utp = getutid(wtp); - if (utp == 0) { - syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR"); - return(-1); - } - /* - * Nothing to clean up if the user shell was never started. - */ - if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0) - return(1); - - /* - * Block the WJSIGNAL while we are in jobend(). - */ - omask = sigblock(mask); - ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user); - sigsetmask(omask); - return(ret); -} - -int -jobend(jid, path, user) - int jid; - char *path; - char *user; -{ - static int saved_jid = 0; - static int pty_saved_jid = 0; - static char saved_path[sizeof(wtmp.ut_tpath)+1]; - static char saved_user[sizeof(wtmp.ut_user)+1]; - - /* - * this little piece of code comes into play - * only when ptyreconnect is used to reconnect - * to an previous session. - * - * this is the only time when the - * "saved_jid != jid" code is executed. - */ - - if ( saved_jid && saved_jid != jid ) { - if (!path) { /* called from signal handler */ - pty_saved_jid = jid; - } else { - pty_saved_jid = saved_jid; - } - } - - if (path) { - strlcpy(saved_path, path, sizeof(saved_path)); - strlcpy(saved_user, user, sizeof(saved_user)); - } - if (saved_jid == 0) { - saved_jid = jid; - return(0); - } - - /* if the jid has changed, get the correct entry from the utmp file */ - - if ( saved_jid != jid ) { - struct utmp *utp = NULL; - struct utmp *jid_getutid(); - - utp = jid_getutid(pty_saved_jid); - - if (utp == 0) { - syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR"); - return(-1); - } - - cleantmpdir(jid, utp->ut_tpath, utp->ut_user); - return(1); - } - - cleantmpdir(jid, saved_path, saved_user); - return(1); -} - -/* - * Fork a child process to clean up the TMPDIR - */ -cleantmpdir(jid, tpath, user) - int jid; - char *tpath; - char *user; -{ - switch(fork()) { - case -1: - syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n", - tpath); - break; - case 0: - execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, NULL); - syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n", - tpath, CLEANTMPCMD); - exit(1); - default: - /* - * Forget about child. We will exit, and - * /etc/init will pick it up. - */ - break; - } -} -#endif /* CRAY */ -#endif /* defined(PARENT_DOES_UTMP) */ diff --git a/appl/telnet/telnetd/telnetd.8 b/appl/telnet/telnetd/telnetd.8 deleted file mode 100644 index a7dd67024..000000000 --- a/appl/telnet/telnetd/telnetd.8 +++ /dev/null @@ -1,536 +0,0 @@ -.\" Copyright (c) 1983, 1993 -.\" The Regents of the University of California. All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. -.\" 4. Neither the name of the University nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" @(#)telnetd.8 8.4 (Berkeley) 6/1/94 -.\" -.Dd September 19, 2006 -.Dt TELNETD 8 -.Os BSD 4.2 -.Sh NAME -.Nm telnetd -.Nd DARPA -.Tn TELNET -protocol server -.Sh SYNOPSIS -.Nm telnetd -.Op Fl BeUhkln -.Op Fl D Ar debugmode -.Op Fl S Ar tos -.Op Fl X Ar authtype -.Op Fl a Ar authmode -.Op Fl r Ns Ar lowpty-highpty -.Op Fl u Ar len -.Op Fl debug -.Op Fl L Ar /bin/login -.Op Fl y -.Op Ar port -.Sh DESCRIPTION -The -.Nm telnetd -command is a server which supports the -.Tn DARPA -standard -.Tn TELNET -virtual terminal protocol. -.Nm Telnetd -is normally invoked by the internet server (see -.Xr inetd 8 ) -for requests to connect to the -.Tn TELNET -port as indicated by the -.Pa /etc/services -file (see -.Xr services 5 ) . -The -.Fl debug -option may be used to start up -.Nm telnetd -manually, instead of through -.Xr inetd 8 . -If started up this way, -.Ar port -may be specified to run -.Nm telnetd -on an alternate -.Tn TCP -port number. -.Pp -The -.Nm telnetd -command accepts the following options: -.Bl -tag -width "-a authmode" -.It Fl a Ar authmode -This option may be used for specifying what mode should -be used for authentication. -Note that this option is only useful if -.Nm telnetd -has been compiled with support for the -.Dv AUTHENTICATION -option. -There are several valid values for -.Ar authmode : -.Bl -tag -width debug -.It debug -Turns on authentication debugging code. -.It user -Only allow connections when the remote user -can provide valid authentication information -to identify the remote user, -and is allowed access to the specified account -without providing a password. -.It valid -Only allow connections when the remote user -can provide valid authentication information -to identify the remote user. -The -.Xr login 1 -command will provide any additional user verification -needed if the remote user is not allowed automatic -access to the specified account. -.It other -Only allow connections that supply some authentication information. -This option is currently not supported -by any of the existing authentication mechanisms, -and is thus the same as specifying -.Fl a -.Cm valid . -.It otp -Only allow authenticated connections (as with -.Fl a -.Cm user ) -and also logins with one-time passwords (OTPs). This option will call -login with an option so that only OTPs are accepted. The user can of -course still type secret information at the prompt. -.It none -This is the default state. -Authentication information is not required. -If no or insufficient authentication information -is provided, then the -.Xr login 1 -program will provide the necessary user -verification. -.It off -This disables the authentication code. -All user verification will happen through the -.Xr login 1 -program. -.El -.It Fl B -Ignored. -.It Fl D Ar debugmode -This option may be used for debugging purposes. -This allows -.Nm telnetd -to print out debugging information -to the connection, allowing the user to see what -.Nm telnetd -is doing. -There are several possible values for -.Ar debugmode : -.Bl -tag -width exercise -.It Cm options -Prints information about the negotiation of -.Tn TELNET -options. -.It Cm report -Prints the -.Cm options -information, plus some additional information -about what processing is going on. -.It Cm netdata -Displays the data stream received by -.Nm telnetd . -.It Cm ptydata -Displays data written to the pty. -.It Cm exercise -Has not been implemented yet. -.El -.It Fl e -require encryption to be turned on (in both direction) by the client -and disconnects if the client tries to turn the encryption off (in -either direction). -.It Fl h -Disables the printing of host-specific information before -login has been completed. -.It Fl k -.It Fl l -Ignored. -.It Fl n -Disable -.Dv TCP -keep-alives. Normally -.Nm telnetd -enables the -.Tn TCP -keep-alive mechanism to probe connections that -have been idle for some period of time to determine -if the client is still there, so that idle connections -from machines that have crashed or can no longer -be reached may be cleaned up. -.It Fl r Ar lowpty-highpty -This option is only enabled when -.Nm telnetd -is compiled for -.Dv UNICOS . -It specifies an inclusive range of pseudo-terminal devices to -use. If the system has sysconf variable -.Dv _SC_CRAY_NPTY -configured, the default pty search range is 0 to -.Dv _SC_CRAY_NPTY ; -otherwise, the default range is 0 to 128. Either -.Ar lowpty -or -.Ar highpty -may be omitted to allow changing -either end of the search range. If -.Ar lowpty -is omitted, the - character is still required so that -.Nm telnetd -can differentiate -.Ar highpty -from -.Ar lowpty . -.It Fl S Ar tos -.It Fl u Ar len -This option is used to specify the size of the field -in the -.Dv utmp -structure that holds the remote host name. -If the resolved host name is longer than -.Ar len , -the dotted decimal value will be used instead. -This allows hosts with very long host names that -overflow this field to still be uniquely identified. -Specifying -.Fl u0 -indicates that only dotted decimal addresses -should be put into the -.Pa utmp -file. -.It Fl U -This option causes -.Nm telnetd -to refuse connections from addresses that -cannot be mapped back into a symbolic name -via the -.Xr gethostbyaddr 3 -routine. -.It Fl X Ar authtype -This option is only valid if -.Nm telnetd -has been built with support for the authentication option. -It disables the use of -.Ar authtype -authentication, and -can be used to temporarily disable -a specific authentication type without having to recompile -.Nm telnetd . -.It Fl L Ar pathname -Specify pathname to an alternative login program. -.It Fl y -Makes -.Nm -not warn when a user is trying to login with a cleartext password. -.El -.Pp -.Nm Telnetd -operates by allocating a pseudo-terminal device (see -.Xr pty 4 ) -for a client, then creating a login process which has -the slave side of the pseudo-terminal as -.Dv stdin , -.Dv stdout -and -.Dv stderr . -.Nm Telnetd -manipulates the master side of the pseudo-terminal, -implementing the -.Tn TELNET -protocol and passing characters -between the remote client and the login process. -.Pp -When a -.Tn TELNET -session is started up, -.Nm telnetd -sends -.Tn TELNET -options to the client side indicating -a willingness to do the -following -.Tn TELNET -options, which are described in more detail below: -.Bd -literal -offset indent -DO AUTHENTICATION -WILL ENCRYPT -DO TERMINAL TYPE -DO TSPEED -DO XDISPLOC -DO NEW-ENVIRON -DO ENVIRON -WILL SUPPRESS GO AHEAD -DO ECHO -DO LINEMODE -DO NAWS -WILL STATUS -DO LFLOW -DO TIMING-MARK -.Ed -.Pp -The pseudo-terminal allocated to the client is configured -to operate in -.Dq cooked -mode, and with -.Dv XTABS and -.Dv CRMOD -enabled (see -.Xr tty 4 ) . -.Pp -.Nm Telnetd -has support for enabling locally the following -.Tn TELNET -options: -.Bl -tag -width "DO AUTHENTICATION" -.It "WILL ECHO" -When the -.Dv LINEMODE -option is enabled, a -.Dv WILL ECHO -or -.Dv WONT ECHO -will be sent to the client to indicate the -current state of terminal echoing. -When terminal echo is not desired, a -.Dv WILL ECHO -is sent to indicate that -.Tn telnetd -will take care of echoing any data that needs to be -echoed to the terminal, and then nothing is echoed. -When terminal echo is desired, a -.Dv WONT ECHO -is sent to indicate that -.Tn telnetd -will not be doing any terminal echoing, so the -client should do any terminal echoing that is needed. -.It "WILL BINARY" -Indicates that the client is willing to send a -8 bits of data, rather than the normal 7 bits -of the Network Virtual Terminal. -.It "WILL SGA" -Indicates that it will not be sending -.Dv IAC GA , -go ahead, commands. -.It "WILL STATUS" -Indicates a willingness to send the client, upon -request, of the current status of all -.Tn TELNET -options. -.It "WILL TIMING-MARK" -Whenever a -.Dv DO TIMING-MARK -command is received, it is always responded -to with a -.Dv WILL TIMING-MARK -.It "WILL LOGOUT" -When a -.Dv DO LOGOUT -is received, a -.Dv WILL LOGOUT -is sent in response, and the -.Tn TELNET -session is shut down. -.It "WILL ENCRYPT" -Only sent if -.Nm telnetd -is compiled with support for data encryption, and -indicates a willingness to decrypt -the data stream. -.El -.Pp -.Nm Telnetd -has support for enabling remotely the following -.Tn TELNET -options: -.Bl -tag -width "DO AUTHENTICATION" -.It "DO BINARY" -Sent to indicate that -.Tn telnetd -is willing to receive an 8 bit data stream. -.It "DO LFLOW" -Requests that the client handle flow control -characters remotely. -.It "DO ECHO" -This is not really supported, but is sent to identify a 4.2BSD -.Xr telnet 1 -client, which will improperly respond with -.Dv WILL ECHO . -If a -.Dv WILL ECHO -is received, a -.Dv DONT ECHO -will be sent in response. -.It "DO TERMINAL-TYPE" -Indicates a desire to be able to request the -name of the type of terminal that is attached -to the client side of the connection. -.It "DO SGA" -Indicates that it does not need to receive -.Dv IAC GA , -the go ahead command. -.It "DO NAWS" -Requests that the client inform the server when -the window (display) size changes. -.It "DO TERMINAL-SPEED" -Indicates a desire to be able to request information -about the speed of the serial line to which -the client is attached. -.It "DO XDISPLOC" -Indicates a desire to be able to request the name -of the X windows display that is associated with -the telnet client. -.It "DO NEW-ENVIRON" -Indicates a desire to be able to request environment -variable information, as described in RFC 1572. -.It "DO ENVIRON" -Indicates a desire to be able to request environment -variable information, as described in RFC 1408. -.It "DO LINEMODE" -Only sent if -.Nm telnetd -is compiled with support for linemode, and -requests that the client do line by line processing. -.It "DO TIMING-MARK" -Only sent if -.Nm telnetd -is compiled with support for both linemode and -kludge linemode, and the client responded with -.Dv WONT LINEMODE . -If the client responds with -.Dv WILL TM , -the it is assumed that the client supports -kludge linemode. -Note that the -.Op Fl k -option can be used to disable this. -.It "DO AUTHENTICATION" -Only sent if -.Nm telnetd -is compiled with support for authentication, and -indicates a willingness to receive authentication -information for automatic login. -.It "DO ENCRYPT" -Only sent if -.Nm telnetd -is compiled with support for data encryption, and -indicates a willingness to decrypt -the data stream. -.El -.Sh FILES -.Bl -tag -width /etc/services -compact -.It Pa /etc/services -.It Pa /etc/inittab -(UNICOS systems only) -.It Pa /etc/iptos -(if supported) -.El -.Sh "SEE ALSO" -.Xr telnet 1 , -.Xr login 1 -.Sh STANDARDS -.Bl -tag -compact -width RFC-1572 -.It Cm RFC-854 -.Tn TELNET -PROTOCOL SPECIFICATION -.It Cm RFC-855 -TELNET OPTION SPECIFICATIONS -.It Cm RFC-856 -TELNET BINARY TRANSMISSION -.It Cm RFC-857 -TELNET ECHO OPTION -.It Cm RFC-858 -TELNET SUPPRESS GO AHEAD OPTION -.It Cm RFC-859 -TELNET STATUS OPTION -.It Cm RFC-860 -TELNET TIMING MARK OPTION -.It Cm RFC-861 -TELNET EXTENDED OPTIONS - LIST OPTION -.It Cm RFC-885 -TELNET END OF RECORD OPTION -.It Cm RFC-1073 -Telnet Window Size Option -.It Cm RFC-1079 -Telnet Terminal Speed Option -.It Cm RFC-1091 -Telnet Terminal-Type Option -.It Cm RFC-1096 -Telnet X Display Location Option -.It Cm RFC-1123 -Requirements for Internet Hosts -- Application and Support -.It Cm RFC-1184 -Telnet Linemode Option -.It Cm RFC-1372 -Telnet Remote Flow Control Option -.It Cm RFC-1416 -Telnet Authentication Option -.It Cm RFC-1411 -Telnet Authentication: Kerberos Version 4 -.It Cm RFC-1412 -Telnet Authentication: SPX -.It Cm RFC-1571 -Telnet Environment Option Interoperability Issues -.It Cm RFC-1572 -Telnet Environment Option -.El -.Sh BUGS -Some -.Tn TELNET -commands are only partially implemented. -.Pp -Because of bugs in the original 4.2 BSD -.Xr telnet 1 , -.Nm telnetd -performs some dubious protocol exchanges to try to discover if the remote -client is, in fact, a 4.2 BSD -.Xr telnet 1 . -.Pp -Binary mode -has no common interpretation except between similar operating systems -(Unix in this case). -.Pp -The terminal type name received from the remote client is converted to -lower case. -.Pp -.Nm Telnetd -never sends -.Tn TELNET -.Dv IAC GA -(go ahead) commands. diff --git a/appl/telnet/telnetd/telnetd.c b/appl/telnet/telnetd/telnetd.c deleted file mode 100644 index 2d0bb24ce..000000000 --- a/appl/telnet/telnetd/telnetd.c +++ /dev/null @@ -1,1401 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "telnetd.h" - -RCSID("$Id$"); - -#ifdef _SC_CRAY_SECURE_SYS -#include -#include -#include -#include -int secflag; -char tty_dev[16]; -struct secdev dv; -struct sysv sysv; -struct socksec ss; -#endif /* _SC_CRAY_SECURE_SYS */ - -#ifdef AUTHENTICATION -int auth_level = 0; -#endif - -#ifdef KRB5 -#define Authenticator k5_Authenticator -#include -#undef Authenticator -#endif - -extern int utmp_len; -int registerd_host_only = 0; -#ifdef ENCRYPTION -int require_encryption = 0; -#endif - -#ifdef STREAMSPTY - -#ifdef _AIX -#include -#endif -# ifdef HAVE_SYS_STRTTY_H -# include -# endif -# ifdef HAVE_SYS_STR_TTY_H -# include -# endif -/* make sure we don't get the bsd version */ -/* what is this here for? solaris? /joda */ -# ifdef HAVE_SYS_TTY_H -# include "/usr/include/sys/tty.h" -# endif -# ifdef HAVE_SYS_PTYVAR_H -# include -# endif - -/* - * Because of the way ptyibuf is used with streams messages, we need - * ptyibuf+1 to be on a full-word boundary. The following wierdness - * is simply to make that happen. - */ -long ptyibufbuf[BUFSIZ/sizeof(long)+1]; -char *ptyibuf = ((char *)&ptyibufbuf[1])-1; -char *ptyip = ((char *)&ptyibufbuf[1])-1; -char ptyibuf2[BUFSIZ]; -unsigned char ctlbuf[BUFSIZ]; -struct strbuf strbufc, strbufd; - -int readstream(int, char*, int); - -#else /* ! STREAMPTY */ - -/* - * I/O data buffers, - * pointers, and counters. - */ -char ptyibuf[BUFSIZ], *ptyip = ptyibuf; -char ptyibuf2[BUFSIZ]; - -#endif /* ! STREAMPTY */ - -int hostinfo = 1; /* do we print login banner? */ - -#ifdef _CRAY -extern int newmap; /* nonzero if \n maps to ^M^J */ -int lowpty = 0, highpty; /* low, high pty numbers */ -#endif /* CRAY */ - -int debug = 0; -int keepalive = 1; -char *progname; - -static void usage (int error_code); - -/* - * The string to pass to getopt(). We do it this way so - * that only the actual options that we support will be - * passed off to getopt(). - */ -char valid_opts[] = "Bd:hklnS:u:UL:y" -#ifdef AUTHENTICATION - "a:X:z" -#endif -#ifdef ENCRYPTION - "e" -#endif -#ifdef DIAGNOSTICS - "D:" -#endif -#ifdef _CRAY - "r:" -#endif - ; - -static void doit(struct sockaddr*, int); - -int -main(int argc, char **argv) -{ - struct sockaddr_storage __ss; - struct sockaddr *sa = (struct sockaddr *)&__ss; - int on = 1; - socklen_t sa_size; - int ch; -#if defined(IPPROTO_IP) && defined(IP_TOS) - int tos = -1; -#endif - pfrontp = pbackp = ptyobuf; - netip = netibuf; - nfrontp = nbackp = netobuf; - - setprogname(argv[0]); - - progname = *argv; -#ifdef ENCRYPTION - nclearto = 0; -#endif - -#ifdef _CRAY - /* - * Get number of pty's before trying to process options, - * which may include changing pty range. - */ - highpty = getnpty(); -#endif /* CRAY */ - - if (argc == 2 && strcmp(argv[1], "--version") == 0) { - print_version(NULL); - exit(0); - } - if (argc == 2 && strcmp(argv[1], "--help") == 0) - usage(0); - - while ((ch = getopt(argc, argv, valid_opts)) != -1) { - switch(ch) { - -#ifdef AUTHENTICATION - case 'a': - /* - * Check for required authentication level - */ - if (strcmp(optarg, "debug") == 0) { - auth_debug_mode = 1; - } else if (strcasecmp(optarg, "none") == 0) { - auth_level = 0; - } else if (strcasecmp(optarg, "otp") == 0) { - auth_level = 0; - require_otp = 1; - } else if (strcasecmp(optarg, "other") == 0) { - auth_level = AUTH_OTHER; - } else if (strcasecmp(optarg, "user") == 0) { - auth_level = AUTH_USER; - } else if (strcasecmp(optarg, "valid") == 0) { - auth_level = AUTH_VALID; - } else if (strcasecmp(optarg, "off") == 0) { - /* - * This hack turns off authentication - */ - auth_level = -1; - } else { - fprintf(stderr, - "telnetd: unknown authorization level for -a\n"); - } - break; -#endif /* AUTHENTICATION */ - - case 'B': /* BFTP mode is not supported any more */ - break; - case 'd': - if (strcmp(optarg, "ebug") == 0) { - debug++; - break; - } - usage(1); - /* NOTREACHED */ - break; - -#ifdef DIAGNOSTICS - case 'D': - /* - * Check for desired diagnostics capabilities. - */ - if (!strcmp(optarg, "report")) { - diagnostic |= TD_REPORT|TD_OPTIONS; - } else if (!strcmp(optarg, "exercise")) { - diagnostic |= TD_EXERCISE; - } else if (!strcmp(optarg, "netdata")) { - diagnostic |= TD_NETDATA; - } else if (!strcmp(optarg, "ptydata")) { - diagnostic |= TD_PTYDATA; - } else if (!strcmp(optarg, "options")) { - diagnostic |= TD_OPTIONS; - } else { - usage(1); - /* NOT REACHED */ - } - break; -#endif /* DIAGNOSTICS */ - -#ifdef ENCRYPTION - case 'e': - require_encryption = 1; - break; -#endif - - case 'h': - hostinfo = 0; - break; - - case 'k': /* Linemode is not supported any more */ - case 'l': - break; - - case 'n': - keepalive = 0; - break; - -#ifdef _CRAY - case 'r': - { - char *strchr(); - char *c; - - /* - * Allow the specification of alterations - * to the pty search range. It is legal to - * specify only one, and not change the - * other from its default. - */ - c = strchr(optarg, '-'); - if (c) { - *c++ = '\0'; - highpty = atoi(c); - } - if (*optarg != '\0') - lowpty = atoi(optarg); - if ((lowpty > highpty) || (lowpty < 0) || - (highpty > 32767)) { - usage(1); - /* NOT REACHED */ - } - break; - } -#endif /* CRAY */ - - case 'S': -#ifdef HAVE_PARSETOS - if ((tos = parsetos(optarg, "tcp")) < 0) - fprintf(stderr, "%s%s%s\n", - "telnetd: Bad TOS argument '", optarg, - "'; will try to use default TOS"); -#else - fprintf(stderr, "%s%s\n", "TOS option unavailable; ", - "-S flag not supported\n"); -#endif - break; - - case 'u': { - char *eptr; - - utmp_len = strtol(optarg, &eptr, 0); - if (optarg == eptr) - fprintf(stderr, "telnetd: unknown utmp len (%s)\n", optarg); - break; - } - - case 'U': - registerd_host_only = 1; - break; - -#ifdef AUTHENTICATION - case 'X': - /* - * Check for invalid authentication types - */ - auth_disable_name(optarg); - break; -#endif - case 'y': - no_warn = 1; - break; -#ifdef AUTHENTICATION - case 'z': - log_unauth = 1; - break; - -#endif /* AUTHENTICATION */ - - case 'L': - new_login = optarg; - break; - - default: - fprintf(stderr, "telnetd: %c: unknown option\n", ch); - /* FALLTHROUGH */ - case '?': - usage(0); - /* NOTREACHED */ - } - } - - argc -= optind; - argv += optind; - - if (debug) { - int port = 0; - struct servent *sp; - - if (argc > 1) { - usage (1); - } else if (argc == 1) { - sp = roken_getservbyname (*argv, "tcp"); - if (sp) - port = sp->s_port; - else - port = htons(atoi(*argv)); - } else { -#ifdef KRB5 - port = krb5_getportbyname (NULL, "telnet", "tcp", 23); -#else - port = k_getportbyname("telnet", "tcp", htons(23)); -#endif - } - mini_inetd (port); - } else if (argc > 0) { - usage(1); - /* NOT REACHED */ - } - -#ifdef _SC_CRAY_SECURE_SYS - secflag = sysconf(_SC_CRAY_SECURE_SYS); - - /* - * Get socket's security label - */ - if (secflag) { - socklen_t szss = sizeof(ss); - int sock_multi; - socklen_t szi = sizeof(int); - - memset(&dv, 0, sizeof(dv)); - - if (getsysv(&sysv, sizeof(struct sysv)) != 0) - fatalperror(net, "getsysv"); - - /* - * Get socket security label and set device values - * {security label to be set on ttyp device} - */ -#ifdef SO_SEC_MULTI /* 8.0 code */ - if ((getsockopt(0, SOL_SOCKET, SO_SECURITY, - (void *)&ss, &szss) < 0) || - (getsockopt(0, SOL_SOCKET, SO_SEC_MULTI, - (void *)&sock_multi, &szi) < 0)) - fatalperror(net, "getsockopt"); - else { - dv.dv_actlvl = ss.ss_actlabel.lt_level; - dv.dv_actcmp = ss.ss_actlabel.lt_compart; - if (!sock_multi) { - dv.dv_minlvl = dv.dv_maxlvl = dv.dv_actlvl; - dv.dv_valcmp = dv.dv_actcmp; - } else { - dv.dv_minlvl = ss.ss_minlabel.lt_level; - dv.dv_maxlvl = ss.ss_maxlabel.lt_level; - dv.dv_valcmp = ss.ss_maxlabel.lt_compart; - } - dv.dv_devflg = 0; - } -#else /* SO_SEC_MULTI */ /* 7.0 code */ - if (getsockopt(0, SOL_SOCKET, SO_SECURITY, - (void *)&ss, &szss) >= 0) { - dv.dv_actlvl = ss.ss_slevel; - dv.dv_actcmp = ss.ss_compart; - dv.dv_minlvl = ss.ss_minlvl; - dv.dv_maxlvl = ss.ss_maxlvl; - dv.dv_valcmp = ss.ss_maxcmp; - } -#endif /* SO_SEC_MULTI */ - } -#endif /* _SC_CRAY_SECURE_SYS */ - - roken_openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON); - sa_size = sizeof (__ss); - if (getpeername(STDIN_FILENO, sa, &sa_size) < 0) { - fprintf(stderr, "%s: ", progname); - perror("getpeername"); - _exit(1); - } - if (keepalive && - setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, - (void *)&on, sizeof (on)) < 0) { - syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); - } - -#if defined(IPPROTO_IP) && defined(IP_TOS) && defined(HAVE_SETSOCKOPT) - { -# ifdef HAVE_GETTOSBYNAME - struct tosent *tp; - if (tos < 0 && (tp = gettosbyname("telnet", "tcp"))) - tos = tp->t_tos; -# endif - if (tos < 0) - tos = 020; /* Low Delay bit */ - if (tos - && sa->sa_family == AF_INET - && (setsockopt(STDIN_FILENO, IPPROTO_IP, IP_TOS, - (void *)&tos, sizeof(tos)) < 0) - && (errno != ENOPROTOOPT) ) - syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); - } -#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */ - net = STDIN_FILENO; - doit(sa, sa_size); - /* NOTREACHED */ - return 0; -} /* end of main */ - -static void -usage(int exit_code) -{ - fprintf(stderr, "Usage: telnetd"); - fprintf(stderr, " [--help]"); - fprintf(stderr, " [--version]"); -#ifdef AUTHENTICATION - fprintf(stderr, " [-a (debug|other|otp|user|valid|off|none)]\n\t"); -#endif - fprintf(stderr, " [-debug]"); -#ifdef DIAGNOSTICS - fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t"); -#endif -#ifdef AUTHENTICATION - fprintf(stderr, " [-edebug]"); -#endif - fprintf(stderr, " [-h]"); - fprintf(stderr, " [-L login]"); - fprintf(stderr, " [-n]"); -#ifdef _CRAY - fprintf(stderr, " [-r[lowpty]-[highpty]]"); -#endif - fprintf(stderr, "\n\t"); -#ifdef HAVE_GETTOSBYNAME - fprintf(stderr, " [-S tos]"); -#endif -#ifdef AUTHENTICATION - fprintf(stderr, " [-X auth-type] [-y] [-z]"); -#endif - fprintf(stderr, " [-u utmp_hostname_length] [-U]"); - fprintf(stderr, " [port]\n"); - exit(exit_code); -} - -/* - * getterminaltype - * - * Ask the other end to send along its terminal type and speed. - * Output is the variable terminaltype filled in. - */ -static unsigned char ttytype_sbbuf[] = { - IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE -}; - -int -getterminaltype(char *name, size_t name_sz) -{ - int retval = -1; - - settimer(baseline); -#ifdef AUTHENTICATION - /* - * Handle the Authentication option before we do anything else. - */ - send_do(TELOPT_AUTHENTICATION, 1); - while (his_will_wont_is_changing(TELOPT_AUTHENTICATION)) - ttloop(); - if (his_state_is_will(TELOPT_AUTHENTICATION)) { - retval = auth_wait(name, name_sz); - } -#endif - -#ifdef ENCRYPTION - send_will(TELOPT_ENCRYPT, 1); - send_do(TELOPT_ENCRYPT, 1); /* esc@magic.fi */ -#endif - send_do(TELOPT_TTYPE, 1); - send_do(TELOPT_TSPEED, 1); - send_do(TELOPT_XDISPLOC, 1); - send_do(TELOPT_NEW_ENVIRON, 1); - send_do(TELOPT_OLD_ENVIRON, 1); - while ( -#ifdef ENCRYPTION - his_do_dont_is_changing(TELOPT_ENCRYPT) || -#endif - his_will_wont_is_changing(TELOPT_TTYPE) || - his_will_wont_is_changing(TELOPT_TSPEED) || - his_will_wont_is_changing(TELOPT_XDISPLOC) || - his_will_wont_is_changing(TELOPT_NEW_ENVIRON) || - his_will_wont_is_changing(TELOPT_OLD_ENVIRON)) { - ttloop(); - } -#ifdef ENCRYPTION - /* - * Wait for the negotiation of what type of encryption we can - * send with. If autoencrypt is not set, this will just return. - */ - if (his_state_is_will(TELOPT_ENCRYPT)) { - encrypt_wait(); - } - if (require_encryption) { - - while (encrypt_delay()) - if (telnet_spin()) - fatal(net, "Failed while waiting for encryption"); - - if (!encrypt_is_encrypting()) - fatal(net, "Encryption required but not turned on by client"); - } -#endif - if (his_state_is_will(TELOPT_TSPEED)) { - static unsigned char sb[] = - { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE }; - - telnet_net_write (sb, sizeof sb); - DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2);); - } - if (his_state_is_will(TELOPT_XDISPLOC)) { - static unsigned char sb[] = - { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE }; - - telnet_net_write (sb, sizeof sb); - DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2);); - } - if (his_state_is_will(TELOPT_NEW_ENVIRON)) { - static unsigned char sb[] = - { IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_SEND, IAC, SE }; - - telnet_net_write (sb, sizeof sb); - DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2);); - } - else if (his_state_is_will(TELOPT_OLD_ENVIRON)) { - static unsigned char sb[] = - { IAC, SB, TELOPT_OLD_ENVIRON, TELQUAL_SEND, IAC, SE }; - - telnet_net_write (sb, sizeof sb); - DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2);); - } - if (his_state_is_will(TELOPT_TTYPE)) { - - telnet_net_write (ttytype_sbbuf, sizeof ttytype_sbbuf); - DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2, - sizeof ttytype_sbbuf - 2);); - } - if (his_state_is_will(TELOPT_TSPEED)) { - while (sequenceIs(tspeedsubopt, baseline)) - ttloop(); - } - if (his_state_is_will(TELOPT_XDISPLOC)) { - while (sequenceIs(xdisplocsubopt, baseline)) - ttloop(); - } - if (his_state_is_will(TELOPT_NEW_ENVIRON)) { - while (sequenceIs(environsubopt, baseline)) - ttloop(); - } - if (his_state_is_will(TELOPT_OLD_ENVIRON)) { - while (sequenceIs(oenvironsubopt, baseline)) - ttloop(); - } - if (his_state_is_will(TELOPT_TTYPE)) { - char first[256], last[256]; - - while (sequenceIs(ttypesubopt, baseline)) - ttloop(); - - /* - * If the other side has already disabled the option, then - * we have to just go with what we (might) have already gotten. - */ - if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) { - strlcpy(first, terminaltype, sizeof(first)); - for(;;) { - /* - * Save the unknown name, and request the next name. - */ - strlcpy(last, terminaltype, sizeof(last)); - _gettermname(); - if (terminaltypeok(terminaltype)) - break; - if ((strncmp(last, terminaltype, sizeof(last)) == 0) || - his_state_is_wont(TELOPT_TTYPE)) { - /* - * We've hit the end. If this is the same as - * the first name, just go with it. - */ - if (strncmp(first, terminaltype, sizeof(first)) == 0) - break; - /* - * Get the terminal name one more time, so that - * RFC1091 compliant telnets will cycle back to - * the start of the list. - */ - _gettermname(); - if (strncmp(first, terminaltype, sizeof(first)) != 0) - strlcpy(terminaltype, first, sizeof(terminaltype)); - break; - } - } - } - } - return(retval); -} /* end of getterminaltype */ - -void -_gettermname(void) -{ - /* - * If the client turned off the option, - * we can't send another request, so we - * just return. - */ - if (his_state_is_wont(TELOPT_TTYPE)) - return; - settimer(baseline); - telnet_net_write (ttytype_sbbuf, sizeof ttytype_sbbuf); - DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2, - sizeof ttytype_sbbuf - 2);); - while (sequenceIs(ttypesubopt, baseline)) - ttloop(); -} - -int -terminaltypeok(char *s) -{ - return 1; -} - - -char host_name[MaxHostNameLen]; -char remote_host_name[MaxHostNameLen]; -char remote_utmp_name[MaxHostNameLen]; - -/* - * Get a pty, scan input lines. - */ -static void -doit(struct sockaddr *who, int who_len) -{ - int level; - int ptynum; - char user_name[256]; - int error; - - /* - * Find an available pty to use. - */ - ourpty = getpty(&ptynum); - if (ourpty < 0) - fatal(net, "All network ports in use"); - -#ifdef _SC_CRAY_SECURE_SYS - /* - * set ttyp line security label - */ - if (secflag) { - char slave_dev[16]; - - snprintf(tty_dev, sizeof(tty_dev), "/dev/pty/%03d", ptynum); - if (setdevs(tty_dev, &dv) < 0) - fatal(net, "cannot set pty security"); - snprintf(slave_dev, sizeof(slave_dev), "/dev/ttyp%03d", ptynum); - if (setdevs(slave_dev, &dv) < 0) - fatal(net, "cannot set tty security"); - } -#endif /* _SC_CRAY_SECURE_SYS */ - - error = getnameinfo_verified (who, who_len, - remote_host_name, - sizeof(remote_host_name), - NULL, 0, - registerd_host_only ? NI_NAMEREQD : 0); - if (error) - fatal(net, "Couldn't resolve your address into a host name.\r\n\ -Please contact your net administrator"); - - gethostname(host_name, sizeof (host_name)); - - strlcpy (remote_utmp_name, remote_host_name, sizeof(remote_utmp_name)); - - /* Only trim if too long (and possible) */ - if (strlen(remote_utmp_name) > utmp_len) { - char *domain = strchr(host_name, '.'); - char *p = strchr(remote_utmp_name, '.'); - if (domain != NULL && p != NULL && (strcmp(p, domain) == 0)) - *p = '\0'; /* remove domain part */ - } - - /* - * If hostname still doesn't fit utmp, use ipaddr. - */ - if (strlen(remote_utmp_name) > utmp_len) { - error = getnameinfo (who, who_len, - remote_utmp_name, - sizeof(remote_utmp_name), - NULL, 0, - NI_NUMERICHOST); - if (error) - fatal(net, "Couldn't get numeric address\r\n"); - } - -#ifdef AUTHENTICATION - auth_encrypt_init(host_name, remote_host_name, "TELNETD", 1); -#endif - - init_env(); - - /* begin server processing */ - - /* - * Initialize the slc mapping table. - */ - - get_slc_defaults(); - - /* - * get terminal type. - */ - *user_name = 0; - level = getterminaltype(user_name, sizeof(user_name)); - esetenv("TERM", terminaltype[0] ? terminaltype : "network", 1); - -#ifdef _SC_CRAY_SECURE_SYS - if (secflag) { - if (setulvl(dv.dv_actlvl) < 0) - fatal(net,"cannot setulvl()"); - if (setucmp(dv.dv_actcmp) < 0) - fatal(net, "cannot setucmp()"); - } -#endif /* _SC_CRAY_SECURE_SYS */ - - my_telnet(net, ourpty, remote_host_name, remote_utmp_name, - level, user_name); - /*NOTREACHED*/ -} /* end of doit */ - -/* output contents of /etc/issue.net, or /etc/issue */ -static void -show_issue(void) -{ - FILE *f; - char buf[128]; - f = fopen(SYSCONFDIR "/issue.net", "r"); - if(f == NULL) - f = fopen(SYSCONFDIR "/issue", "r"); - if(f){ - while(fgets(buf, sizeof(buf), f) != NULL) { - size_t len = strcspn(buf, "\r\n"); - if(len == strlen(buf)) { - /* there's no newline */ - writenet(buf, len); - } else { - /* replace newline with \r\n */ - buf[len] = '\0'; - writenet(buf, len); - writenet("\r\n", 2); - } - } - fclose(f); - } -} - -/* - * Main loop. Select from pty and network, and - * hand data to telnet receiver finite state machine. - */ -void -my_telnet(int f, int p, const char *host, const char *utmp_host, - int level, char *autoname) -{ - int on = 1; - char *he; - char *IM; - int nfd; - int startslave_called = 0; - time_t timeout; - - /* - * Do some tests where it is desireable to wait for a response. - * Rather than doing them slowly, one at a time, do them all - * at once. - */ - if (my_state_is_wont(TELOPT_SGA)) - send_will(TELOPT_SGA, 1); - /* - * Is the client side a 4.2 (NOT 4.3) system? We need to know this - * because 4.2 clients are unable to deal with TCP urgent data. - * - * To find out, we send out a "DO ECHO". If the remote system - * answers "WILL ECHO" it is probably a 4.2 client, and we note - * that fact ("WILL ECHO" ==> that the client will echo what - * WE, the server, sends it; it does NOT mean that the client will - * echo the terminal input). - */ - send_do(TELOPT_ECHO, 1); - - /* - * Send along a couple of other options that we wish to negotiate. - */ - send_do(TELOPT_NAWS, 1); - send_will(TELOPT_STATUS, 1); - flowmode = 1; /* default flow control state */ - restartany = -1; /* uninitialized... */ - send_do(TELOPT_LFLOW, 1); - - /* - * Spin, waiting for a response from the DO ECHO. However, - * some REALLY DUMB telnets out there might not respond - * to the DO ECHO. So, we spin looking for NAWS, (most dumb - * telnets so far seem to respond with WONT for a DO that - * they don't understand...) because by the time we get the - * response, it will already have processed the DO ECHO. - * Kludge upon kludge. - */ - while (his_will_wont_is_changing(TELOPT_NAWS)) - ttloop(); - - /* - * But... - * The client might have sent a WILL NAWS as part of its - * startup code; if so, we'll be here before we get the - * response to the DO ECHO. We'll make the assumption - * that any implementation that understands about NAWS - * is a modern enough implementation that it will respond - * to our DO ECHO request; hence we'll do another spin - * waiting for the ECHO option to settle down, which is - * what we wanted to do in the first place... - */ - if (his_want_state_is_will(TELOPT_ECHO) && - his_state_is_will(TELOPT_NAWS)) { - while (his_will_wont_is_changing(TELOPT_ECHO)) - ttloop(); - } - /* - * On the off chance that the telnet client is broken and does not - * respond to the DO ECHO we sent, (after all, we did send the - * DO NAWS negotiation after the DO ECHO, and we won't get here - * until a response to the DO NAWS comes back) simulate the - * receipt of a will echo. This will also send a WONT ECHO - * to the client, since we assume that the client failed to - * respond because it believes that it is already in DO ECHO - * mode, which we do not want. - */ - if (his_want_state_is_will(TELOPT_ECHO)) { - DIAG(TD_OPTIONS, - {output_data("td: simulating recv\r\n"); - }); - willoption(TELOPT_ECHO); - } - - /* - * Finally, to clean things up, we turn on our echo. This - * will break stupid 4.2 telnets out of local terminal echo. - */ - - if (my_state_is_wont(TELOPT_ECHO)) - send_will(TELOPT_ECHO, 1); - -#ifdef TIOCPKT -#ifdef STREAMSPTY - if (!really_stream) -#endif - /* - * Turn on packet mode - */ - ioctl(p, TIOCPKT, (char *)&on); -#endif - - - /* - * Call telrcv() once to pick up anything received during - * terminal type negotiation, 4.2/4.3 determination, and - * linemode negotiation. - */ - telrcv(); - - ioctl(f, FIONBIO, (char *)&on); - ioctl(p, FIONBIO, (char *)&on); - -#if defined(SO_OOBINLINE) && defined(HAVE_SETSOCKOPT) - setsockopt(net, SOL_SOCKET, SO_OOBINLINE, - (void *)&on, sizeof on); -#endif /* defined(SO_OOBINLINE) */ - -#ifdef SIGTSTP - signal(SIGTSTP, SIG_IGN); -#endif -#ifdef SIGTTOU - /* - * Ignoring SIGTTOU keeps the kernel from blocking us - * in ttioct() in /sys/tty.c. - */ - signal(SIGTTOU, SIG_IGN); -#endif - - signal(SIGCHLD, cleanup); - -#ifdef TIOCNOTTY - { - int t; - t = open(_PATH_TTY, O_RDWR); - if (t >= 0) { - ioctl(t, TIOCNOTTY, (char *)0); - close(t); - } - } -#endif - - show_issue(); - /* - * Show banner that getty never gave. - * - * We put the banner in the pty input buffer. This way, it - * gets carriage return null processing, etc., just like all - * other pty --> client data. - */ - - if (getenv("USER")) - hostinfo = 0; - - IM = DEFAULT_IM; - he = 0; - edithost(he, host_name); - if (hostinfo && *IM) - putf(IM, ptyibuf2); - - if (pcc) - strncat(ptyibuf2, ptyip, pcc+1); - ptyip = ptyibuf2; - pcc = strlen(ptyip); - - DIAG(TD_REPORT, { - output_data("td: Entering processing loop\r\n"); - }); - - - nfd = ((f > p) ? f : p) + 1; - timeout = time(NULL) + 5; - for (;;) { - fd_set ibits, obits, xbits; - int c; - - /* wait for encryption to be turned on, but don't wait - indefinitely */ - if(!startslave_called && (!encrypt_delay() || timeout > time(NULL))){ - startslave_called = 1; - startslave(host, utmp_host, level, autoname); - } - - if (ncc < 0 && pcc < 0) - break; - - FD_ZERO(&ibits); - FD_ZERO(&obits); - FD_ZERO(&xbits); - - if (f >= FD_SETSIZE - || p >= FD_SETSIZE) - fatal(net, "fd too large"); - - /* - * Never look for input if there's still - * stuff in the corresponding output buffer - */ - if (nfrontp - nbackp || pcc > 0) { - FD_SET(f, &obits); - } else { - FD_SET(p, &ibits); - } - if (pfrontp - pbackp || ncc > 0) { - FD_SET(p, &obits); - } else { - FD_SET(f, &ibits); - } - if (!SYNCHing) { - FD_SET(f, &xbits); - } - if ((c = select(nfd, &ibits, &obits, &xbits, - (struct timeval *)0)) < 1) { - if (c == -1) { - if (errno == EINTR) { - continue; - } - } - sleep(5); - continue; - } - - /* - * Any urgent data? - */ - if (FD_ISSET(net, &xbits)) { - SYNCHing = 1; - } - - /* - * Something to read from the network... - */ - if (FD_ISSET(net, &ibits)) { -#ifndef SO_OOBINLINE - /* - * In 4.2 (and 4.3 beta) systems, the - * OOB indication and data handling in the kernel - * is such that if two separate TCP Urgent requests - * come in, one byte of TCP data will be overlaid. - * This is fatal for Telnet, but we try to live - * with it. - * - * In addition, in 4.2 (and...), a special protocol - * is needed to pick up the TCP Urgent data in - * the correct sequence. - * - * What we do is: if we think we are in urgent - * mode, we look to see if we are "at the mark". - * If we are, we do an OOB receive. If we run - * this twice, we will do the OOB receive twice, - * but the second will fail, since the second - * time we were "at the mark", but there wasn't - * any data there (the kernel doesn't reset - * "at the mark" until we do a normal read). - * Once we've read the OOB data, we go ahead - * and do normal reads. - * - * There is also another problem, which is that - * since the OOB byte we read doesn't put us - * out of OOB state, and since that byte is most - * likely the TELNET DM (data mark), we would - * stay in the TELNET SYNCH (SYNCHing) state. - * So, clocks to the rescue. If we've "just" - * received a DM, then we test for the - * presence of OOB data when the receive OOB - * fails (and AFTER we did the normal mode read - * to clear "at the mark"). - */ - if (SYNCHing) { - int atmark; - - ioctl(net, SIOCATMARK, (char *)&atmark); - if (atmark) { - ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB); - if ((ncc == -1) && (errno == EINVAL)) { - ncc = read(net, netibuf, sizeof (netibuf)); - if (sequenceIs(didnetreceive, gotDM)) { - SYNCHing = stilloob(net); - } - } - } else { - ncc = read(net, netibuf, sizeof (netibuf)); - } - } else { - ncc = read(net, netibuf, sizeof (netibuf)); - } - settimer(didnetreceive); -#else /* !defined(SO_OOBINLINE)) */ - ncc = read(net, netibuf, sizeof (netibuf)); -#endif /* !defined(SO_OOBINLINE)) */ - if (ncc < 0 && errno == EWOULDBLOCK) - ncc = 0; - else { - if (ncc <= 0) { - break; - } - netip = netibuf; - } - DIAG((TD_REPORT | TD_NETDATA), { - output_data("td: netread %d chars\r\n", ncc); - }); - DIAG(TD_NETDATA, printdata("nd", netip, ncc)); - } - - /* - * Something to read from the pty... - */ - if (FD_ISSET(p, &ibits)) { -#ifdef STREAMSPTY - if (really_stream) - pcc = readstream(p, ptyibuf, BUFSIZ); - else -#endif - pcc = read(p, ptyibuf, BUFSIZ); - - /* - * On some systems, if we try to read something - * off the master side before the slave side is - * opened, we get EIO. - */ - if (pcc < 0 && (errno == EWOULDBLOCK || -#ifdef EAGAIN - errno == EAGAIN || -#endif - errno == EIO)) { - pcc = 0; - } else { - if (pcc <= 0) - break; - if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) { - netclear(); /* clear buffer back */ -#ifndef NO_URGENT - /* - * There are client telnets on some - * operating systems get screwed up - * royally if we send them urgent - * mode data. - */ - output_data ("%c%c", IAC, DM); - - neturg = nfrontp-1; /* off by one XXX */ - DIAG(TD_OPTIONS, - printoption("td: send IAC", DM)); - -#endif - } - if (his_state_is_will(TELOPT_LFLOW) && - (ptyibuf[0] & - (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) { - int newflow = - ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0; - if (newflow != flowmode) { - flowmode = newflow; - output_data("%c%c%c%c%c%c", - IAC, SB, TELOPT_LFLOW, - flowmode ? LFLOW_ON - : LFLOW_OFF, - IAC, SE); - DIAG(TD_OPTIONS, printsub('>', - (unsigned char *)nfrontp-4, - 4);); - } - } - pcc--; - ptyip = ptyibuf+1; - } - } - - while (pcc > 0) { - if ((&netobuf[BUFSIZ] - nfrontp) < 3) - break; - c = *ptyip++ & 0377, pcc--; - if (c == IAC) - *nfrontp++ = c; - *nfrontp++ = c; - if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) { - if (pcc > 0 && ((*ptyip & 0377) == '\n')) { - *nfrontp++ = *ptyip++ & 0377; - pcc--; - } else - *nfrontp++ = '\0'; - } - } - - if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0) - netflush(); - if (ncc > 0) - telrcv(); - if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0) - ptyflush(); - } - cleanup(0); -} - -#ifndef TCSIG -# ifdef TIOCSIG -# define TCSIG TIOCSIG -# endif -#endif - -#ifdef STREAMSPTY - - int flowison = -1; /* current state of flow: -1 is unknown */ - -int -readstream(int p, char *ibuf, int bufsize) -{ - int flags = 0; - int ret = 0; - struct termios *tsp; -#if 0 - struct termio *tp; -#endif - struct iocblk *ip; - char vstop, vstart; - int ixon; - int newflow; - - strbufc.maxlen = BUFSIZ; - strbufc.buf = (char *)ctlbuf; - strbufd.maxlen = bufsize-1; - strbufd.len = 0; - strbufd.buf = ibuf+1; - ibuf[0] = 0; - - ret = getmsg(p, &strbufc, &strbufd, &flags); - if (ret < 0) /* error of some sort -- probably EAGAIN */ - return(-1); - - if (strbufc.len <= 0 || ctlbuf[0] == M_DATA) { - /* data message */ - if (strbufd.len > 0) { /* real data */ - return(strbufd.len + 1); /* count header char */ - } else { - /* nothing there */ - errno = EAGAIN; - return(-1); - } - } - - /* - * It's a control message. Return 1, to look at the flag we set - */ - - switch (ctlbuf[0]) { - case M_FLUSH: - if (ibuf[1] & FLUSHW) - ibuf[0] = TIOCPKT_FLUSHWRITE; - return(1); - - case M_IOCTL: - ip = (struct iocblk *) (ibuf+1); - - switch (ip->ioc_cmd) { -#ifdef TCSETS - case TCSETS: - case TCSETSW: - case TCSETSF: - tsp = (struct termios *) - (ibuf+1 + sizeof(struct iocblk)); - vstop = tsp->c_cc[VSTOP]; - vstart = tsp->c_cc[VSTART]; - ixon = tsp->c_iflag & IXON; - break; -#endif -#if 0 - case TCSETA: - case TCSETAW: - case TCSETAF: - tp = (struct termio *) (ibuf+1 + sizeof(struct iocblk)); - vstop = tp->c_cc[VSTOP]; - vstart = tp->c_cc[VSTART]; - ixon = tp->c_iflag & IXON; - break; -#endif - default: - errno = EAGAIN; - return(-1); - } - - newflow = (ixon && (vstart == 021) && (vstop == 023)) ? 1 : 0; - if (newflow != flowison) { /* it's a change */ - flowison = newflow; - ibuf[0] = newflow ? TIOCPKT_DOSTOP : TIOCPKT_NOSTOP; - return(1); - } - } - - /* nothing worth doing anything about */ - errno = EAGAIN; - return(-1); -} -#endif /* STREAMSPTY */ - -/* - * Send interrupt to process on other side of pty. - * If it is in raw mode, just write NULL; - * otherwise, write intr char. - */ -void -interrupt() -{ - ptyflush(); /* half-hearted */ - -#if defined(STREAMSPTY) && defined(TIOCSIGNAL) - /* Streams PTY style ioctl to post a signal */ - if (really_stream) - { - int sig = SIGINT; - ioctl(ourpty, TIOCSIGNAL, &sig); - ioctl(ourpty, I_FLUSH, FLUSHR); - } -#else -#ifdef TCSIG - ioctl(ourpty, TCSIG, (char *)SIGINT); -#else /* TCSIG */ - init_termbuf(); - *pfrontp++ = slctab[SLC_IP].sptr ? - (unsigned char)*slctab[SLC_IP].sptr : '\177'; -#endif /* TCSIG */ -#endif -} - -/* - * Send quit to process on other side of pty. - * If it is in raw mode, just write NULL; - * otherwise, write quit char. - */ -void -sendbrk() -{ - ptyflush(); /* half-hearted */ -#ifdef TCSIG - ioctl(ourpty, TCSIG, (char *)SIGQUIT); -#else /* TCSIG */ - init_termbuf(); - *pfrontp++ = slctab[SLC_ABORT].sptr ? - (unsigned char)*slctab[SLC_ABORT].sptr : '\034'; -#endif /* TCSIG */ -} - -void -sendsusp() -{ -#ifdef SIGTSTP - ptyflush(); /* half-hearted */ -# ifdef TCSIG - ioctl(ourpty, TCSIG, (char *)SIGTSTP); -# else /* TCSIG */ - *pfrontp++ = slctab[SLC_SUSP].sptr ? - (unsigned char)*slctab[SLC_SUSP].sptr : '\032'; -# endif /* TCSIG */ -#endif /* SIGTSTP */ -} - -/* - * When we get an AYT, if ^T is enabled, use that. Otherwise, - * just send back "[Yes]". - */ -void -recv_ayt() -{ -#if defined(SIGINFO) && defined(TCSIG) - if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) { - ioctl(ourpty, TCSIG, (char *)SIGINFO); - return; - } -#endif - output_data("\r\n[Yes]\r\n"); -} - -void -doeof() -{ - init_termbuf(); - - *pfrontp++ = slctab[SLC_EOF].sptr ? - (unsigned char)*slctab[SLC_EOF].sptr : '\004'; -} diff --git a/appl/telnet/telnetd/telnetd.h b/appl/telnet/telnetd/telnetd.h deleted file mode 100644 index 828bfb360..000000000 --- a/appl/telnet/telnetd/telnetd.h +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)telnetd.h 8.1 (Berkeley) 6/4/93 - */ - - -#include - -#include -#include -#include -#include - -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_PARAM_H -#include -#endif - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef TIME_WITH_SYS_TIME -#include -#include -#elif defined(HAVE_SYS_TIME_H) -#include -#else -#include -#endif - -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif /* HAVE_SYS_RESOURCE_H */ - -#ifdef HAVE_SYS_WAIT_H -#include -#endif - -#ifdef HAVE_FCNTL_H -#include -#endif -#ifdef HAVE_SYS_FILE_H -#include -#endif -#ifdef HAVE_SYS_STAT_H -#include -#endif - -/* including both and in SunOS 4 generates a - lot of warnings */ - -#if defined(HAVE_SYS_IOCTL_H) && SunOS != 40 -#include -#endif -#ifdef HAVE_SYS_FILIO_H -#include -#endif - -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETINET_IN6_H -#include -#endif -#ifdef HAVE_NETINET6_IN6_H -#include -#endif - -#ifdef HAVE_ARPA_INET_H -#include -#endif - -#include -#include -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_SYSLOG_H -#include -#endif -#include - -#ifdef HAVE_UNISTD_H -#include -#endif - -#include - -#ifdef HAVE_PTY_H -#include -#endif - -#ifdef STREAMSPTY -#ifdef HAVE_SAC_H -#include -#endif -#ifdef HAVE_SYS_STROPTS_H -#include -#endif - -# include - -#ifdef HAVE_SYS_UIO_H -#include -#ifdef __hpux -#undef SE -#endif -#endif -#ifdef HAVE_SYS_STREAM_H -#include -#endif - -#endif /* STREAMSPTY */ - -#undef NOERROR - -#include "defs.h" - -#ifndef _POSIX_VDISABLE -# ifdef VDISABLE -# define _POSIX_VDISABLE VDISABLE -# else -# define _POSIX_VDISABLE ((unsigned char)'\377') -# endif -#endif - - -#ifdef HAVE_SYS_PTY_H -#include -#endif -#ifdef HAVE_SYS_SELECT_H -#include -#endif - -#ifdef HAVE_SYS_PTYIO_H -#include -#endif - -#ifdef HAVE_SYS_UTSNAME_H -#include -#endif - -#ifdef HAVE_PATHS_H -#include -#endif - -#ifdef HAVE_ARPA_TELNET_H -#include -#endif - -#include "ext.h" - -#ifdef SOCKS -#include -/* This doesn't belong here. */ -struct tm *localtime(const time_t *); -struct hostent *gethostbyname(const char *); -#endif - -#ifdef AUTHENTICATION -#include -#include -#ifdef ENCRYPTION -#include -#endif -#endif - -#ifdef HAVE_LIBUTIL_H -#include -#endif - -#include - -/* Don't use the system login, use our version instead */ - -/* BINDIR should be defined somewhere else... */ - -#ifndef BINDIR -#define BINDIR "/usr/athena/bin" -#endif - -#undef _PATH_LOGIN -#define _PATH_LOGIN BINDIR "/login" - -/* fallbacks */ - -#ifndef _PATH_DEV -#define _PATH_DEV "/dev/" -#endif - -#ifndef _PATH_TTY -#define _PATH_TTY "/dev/tty" -#endif /* _PATH_TTY */ - -#ifdef DIAGNOSTICS -#define DIAG(a,b) if (diagnostic & (a)) b -#else -#define DIAG(a,b) -#endif - -/* other external variables */ -extern char **environ; - -/* prototypes */ - -/* appends data to nfrontp and advances */ -int output_data (const char *format, ...) -#ifdef __GNUC__ -__attribute__ ((format (printf, 1, 2))) -#endif -; - -#ifdef ENCRYPTION -extern int require_encryption; -#endif diff --git a/appl/telnet/telnetd/termstat.c b/appl/telnet/telnetd/termstat.c deleted file mode 100644 index 77d113525..000000000 --- a/appl/telnet/telnetd/termstat.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "telnetd.h" - -RCSID("$Id$"); - -/* - * local variables - */ -int def_tspeed = -1, def_rspeed = -1; -#ifdef TIOCSWINSZ -int def_row = 0, def_col = 0; -#endif - -/* - * flowstat - * - * Check for changes to flow control - */ -void -flowstat(void) -{ - if (his_state_is_will(TELOPT_LFLOW)) { - if (tty_flowmode() != flowmode) { - flowmode = tty_flowmode(); - output_data("%c%c%c%c%c%c", - IAC, SB, TELOPT_LFLOW, - flowmode ? LFLOW_ON : LFLOW_OFF, - IAC, SE); - } - if (tty_restartany() != restartany) { - restartany = tty_restartany(); - output_data("%c%c%c%c%c%c", - IAC, SB, TELOPT_LFLOW, - restartany ? LFLOW_RESTART_ANY - : LFLOW_RESTART_XON, - IAC, SE); - } - } -} - -/* - * clientstat - * - * Process linemode related requests from the client. - * Client can request a change to only one of linemode, editmode or slc's - * at a time, and if using kludge linemode, then only linemode may be - * affected. - */ -void -clientstat(int code, int parm1, int parm2) -{ - /* - * Get a copy of terminal characteristics. - */ - init_termbuf(); - - /* - * Process request from client. code tells what it is. - */ - switch (code) { - case TELOPT_NAWS: -#ifdef TIOCSWINSZ - { - struct winsize ws; - - def_col = parm1; - def_row = parm2; - - /* - * Change window size as requested by client. - */ - - ws.ws_col = parm1; - ws.ws_row = parm2; - ioctl(ourpty, TIOCSWINSZ, (char *)&ws); - } -#endif /* TIOCSWINSZ */ - - break; - - case TELOPT_TSPEED: - { - def_tspeed = parm1; - def_rspeed = parm2; - /* - * Change terminal speed as requested by client. - * We set the receive speed first, so that if we can't - * store seperate receive and transmit speeds, the transmit - * speed will take precedence. - */ - tty_rspeed(parm2); - tty_tspeed(parm1); - set_termbuf(); - - break; - - } /* end of case TELOPT_TSPEED */ - - default: - /* What? */ - break; - } /* end of switch */ - - netflush(); - -} diff --git a/appl/telnet/telnetd/utility.c b/appl/telnet/telnetd/utility.c deleted file mode 100644 index 066bcc293..000000000 --- a/appl/telnet/telnetd/utility.c +++ /dev/null @@ -1,1170 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#define PRINTOPTIONS -#include "telnetd.h" - -RCSID("$Id$"); - -/* - * utility functions performing io related tasks - */ - -/* - * ttloop - * - * A small subroutine to flush the network output buffer, get some - * data from the network, and pass it through the telnet state - * machine. We also flush the pty input buffer (by dropping its data) - * if it becomes too full. - * - * return 0 if OK or 1 if interrupted by a signal. - */ - -int -ttloop(void) -{ - DIAG(TD_REPORT, { - output_data("td: ttloop\r\n"); - }); - if (nfrontp-nbackp) - netflush(); - ncc = read(net, netibuf, sizeof netibuf); - if (ncc < 0) { - if (errno == EINTR) - return 1; - syslog(LOG_INFO, "ttloop: read: %m\n"); - exit(1); - } else if (ncc == 0) { - syslog(LOG_INFO, "ttloop: peer died\n"); - exit(1); - } - DIAG(TD_REPORT, { - output_data("td: ttloop read %d chars\r\n", ncc); - }); - netip = netibuf; - telrcv(); /* state machine */ - if (ncc > 0) { - pfrontp = pbackp = ptyobuf; - telrcv(); - } - return 0; -} /* end of ttloop */ - -/* - * Check a descriptor to see if out of band data exists on it. - */ -int -stilloob(int s) -{ - static struct timeval timeout = { 0 }; - fd_set excepts; - int value; - - if (s >= FD_SETSIZE) - fatal(ourpty, "fd too large"); - - do { - FD_ZERO(&excepts); - FD_SET(s, &excepts); - value = select(s+1, 0, 0, &excepts, &timeout); - } while ((value == -1) && (errno == EINTR)); - - if (value < 0) { - fatalperror(ourpty, "select"); - } - if (FD_ISSET(s, &excepts)) { - return 1; - } else { - return 0; - } -} - -void -ptyflush(void) -{ - int n; - - if ((n = pfrontp - pbackp) > 0) { - DIAG((TD_REPORT | TD_PTYDATA), { - output_data("td: ptyflush %d chars\r\n", n); - }); - DIAG(TD_PTYDATA, printdata("pd", pbackp, n)); - n = write(ourpty, pbackp, n); - } - if (n < 0) { - if (errno == EWOULDBLOCK || errno == EINTR) - return; - cleanup(0); - } - pbackp += n; - if (pbackp == pfrontp) - pbackp = pfrontp = ptyobuf; -} - -/* - * nextitem() - * - * Return the address of the next "item" in the TELNET data - * stream. This will be the address of the next character if - * the current address is a user data character, or it will - * be the address of the character following the TELNET command - * if the current address is a TELNET IAC ("I Am a Command") - * character. - */ -char * -nextitem(char *current) -{ - if ((*current&0xff) != IAC) { - return current+1; - } - switch (*(current+1)&0xff) { - case DO: - case DONT: - case WILL: - case WONT: - return current+3; - case SB:{ - /* loop forever looking for the SE */ - char *look = current+2; - - for (;;) { - if ((*look++&0xff) == IAC) { - if ((*look++&0xff) == SE) { - return look; - } - } - } - } - default: - return current+2; - } -} - - -/* - * netclear() - * - * We are about to do a TELNET SYNCH operation. Clear - * the path to the network. - * - * Things are a bit tricky since we may have sent the first - * byte or so of a previous TELNET command into the network. - * So, we have to scan the network buffer from the beginning - * until we are up to where we want to be. - * - * A side effect of what we do, just to keep things - * simple, is to clear the urgent data pointer. The principal - * caller should be setting the urgent data pointer AFTER calling - * us in any case. - */ -void -netclear(void) -{ - char *thisitem, *next; - char *good; -#define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ - ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) - -#ifdef ENCRYPTION - thisitem = nclearto > netobuf ? nclearto : netobuf; -#else - thisitem = netobuf; -#endif - - while ((next = nextitem(thisitem)) <= nbackp) { - thisitem = next; - } - - /* Now, thisitem is first before/at boundary. */ - -#ifdef ENCRYPTION - good = nclearto > netobuf ? nclearto : netobuf; -#else - good = netobuf; /* where the good bytes go */ -#endif - - while (nfrontp > thisitem) { - if (wewant(thisitem)) { - int length; - - next = thisitem; - do { - next = nextitem(next); - } while (wewant(next) && (nfrontp > next)); - length = next-thisitem; - memmove(good, thisitem, length); - good += length; - thisitem = next; - } else { - thisitem = nextitem(thisitem); - } - } - - nbackp = netobuf; - nfrontp = good; /* next byte to be sent */ - neturg = 0; -} /* end of netclear */ - -extern int not42; - -/* - * netflush - * Send as much data as possible to the network, - * handling requests for urgent data. - */ -void -netflush(void) -{ - int n; - - if ((n = nfrontp - nbackp) > 0) { - DIAG(TD_REPORT, - { n += output_data("td: netflush %d chars\r\n", n); - }); -#ifdef ENCRYPTION - if (encrypt_output) { - char *s = nclearto ? nclearto : nbackp; - if (nfrontp - s > 0) { - (*encrypt_output)((unsigned char *)s, nfrontp-s); - nclearto = nfrontp; - } - } -#endif - /* - * if no urgent data, or if the other side appears to be an - * old 4.2 client (and thus unable to survive TCP urgent data), - * write the entire buffer in non-OOB mode. - */ -#if 1 /* remove this to make it work between solaris 2.6 and linux */ - if ((neturg == 0) || (not42 == 0)) { -#endif - n = write(net, nbackp, n); /* normal write */ -#if 1 /* remove this to make it work between solaris 2.6 and linux */ - } else { - n = neturg - nbackp; - /* - * In 4.2 (and 4.3) systems, there is some question about - * what byte in a sendOOB operation is the "OOB" data. - * To make ourselves compatible, we only send ONE byte - * out of band, the one WE THINK should be OOB (though - * we really have more the TCP philosophy of urgent data - * rather than the Unix philosophy of OOB data). - */ - if (n > 1) { - n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ - } else { - n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ - } - } -#endif - } - if (n < 0) { - if (errno == EWOULDBLOCK || errno == EINTR) - return; - cleanup(0); - } - nbackp += n; -#ifdef ENCRYPTION - if (nbackp > nclearto) - nclearto = 0; -#endif - if (nbackp >= neturg) { - neturg = 0; - } - if (nbackp == nfrontp) { - nbackp = nfrontp = netobuf; -#ifdef ENCRYPTION - nclearto = 0; -#endif - } - return; -} - - -/* - * writenet - * - * Just a handy little function to write a bit of raw data to the net. - * It will force a transmit of the buffer if necessary - * - * arguments - * ptr - A pointer to a character string to write - * len - How many bytes to write - */ -void -writenet(const void *ptr, size_t len) -{ - /* flush buffer if no room for new data) */ - while ((&netobuf[BUFSIZ] - nfrontp) < len) { - /* if this fails, don't worry, buffer is a little big */ - netflush(); - } - if ((&netobuf[BUFSIZ] - nfrontp) < len) - abort(); - - memmove(nfrontp, ptr, len); - nfrontp += len; -} - - -/* - * miscellaneous functions doing a variety of little jobs follow ... - */ - - -void fatal(int f, char *msg) -{ - char buf[BUFSIZ]; - - snprintf(buf, sizeof(buf), "telnetd: %s.\r\n", msg); -#ifdef ENCRYPTION - if (encrypt_output) { - /* - * Better turn off encryption first.... - * Hope it flushes... - */ - encrypt_send_end(); - netflush(); - } -#endif - write(f, buf, (int)strlen(buf)); - sleep(1); /*XXX*/ - exit(1); -} - -void -fatalperror_errno(int f, const char *msg, int error) -{ - char buf[BUFSIZ]; - - snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(error)); - fatal(f, buf); -} - -void -fatalperror(int f, const char *msg) -{ - fatalperror_errno(f, msg, errno); -} - -char editedhost[32]; - -void edithost(char *pat, char *host) -{ - char *res = editedhost; - - if (!pat) - pat = ""; - while (*pat) { - switch (*pat) { - - case '#': - if (*host) - host++; - break; - - case '@': - if (*host) - *res++ = *host++; - break; - - default: - *res++ = *pat; - break; - } - if (res == &editedhost[sizeof editedhost - 1]) { - *res = '\0'; - return; - } - pat++; - } - if (*host) - strlcpy (res, host, - sizeof editedhost - (res - editedhost)); - else - *res = '\0'; - editedhost[sizeof editedhost - 1] = '\0'; -} - -static char *putlocation; - -void -putstr(char *s) -{ - - while (*s) - putchr(*s++); -} - -void -putchr(int cc) -{ - *putlocation++ = cc; -} - -static char fmtstr[] = { "%l:%M%P on %A, %d %B %Y" }; - -void putf(char *cp, char *where) -{ -#ifdef HAVE_UNAME - struct utsname name; -#endif - char *slash; - time_t t; - char db[100]; - - /* if we don't have uname, set these to sensible values */ - char *sysname = "Unix", - *machine = "", - *release = "", - *version = ""; - -#ifdef HAVE_UNAME - uname(&name); - sysname=name.sysname; - machine=name.machine; - release=name.release; - version=name.version; -#endif - - putlocation = where; - - while (*cp) { - if (*cp != '%') { - putchr(*cp++); - continue; - } - switch (*++cp) { - - case 't': - slash = strchr(line+1, '/'); - if (slash == (char *) 0) - putstr(line); - else - putstr(&slash[1]); - break; - - case 'h': - putstr(editedhost); - break; - - case 's': - putstr(sysname); - break; - - case 'm': - putstr(machine); - break; - - case 'r': - putstr(release); - break; - - case 'v': - putstr(version); - break; - - case 'd': - time(&t); - strftime(db, sizeof(db), fmtstr, localtime(&t)); - putstr(db); - break; - - case '%': - putchr('%'); - break; - } - cp++; - } -} - -#ifdef DIAGNOSTICS -/* - * Print telnet options and commands in plain text, if possible. - */ -void -printoption(char *fmt, int option) -{ - if (TELOPT_OK(option)) - output_data("%s %s\r\n", - fmt, - TELOPT(option)); - else if (TELCMD_OK(option)) - output_data("%s %s\r\n", - fmt, - TELCMD(option)); - else - output_data("%s %d\r\n", - fmt, - option); - return; -} - -void -printsub(int direction, unsigned char *pointer, size_t length) - /* '<' or '>' */ - /* where suboption data sits */ - /* length of suboption data */ -{ - int i = 0; - unsigned char buf[512]; - - if (!(diagnostic & TD_OPTIONS)) - return; - - if (direction) { - output_data("td: %s suboption ", - direction == '<' ? "recv" : "send"); - if (length >= 3) { - int j; - - i = pointer[length-2]; - j = pointer[length-1]; - - if (i != IAC || j != SE) { - output_data("(terminated by "); - if (TELOPT_OK(i)) - output_data("%s ", - TELOPT(i)); - else if (TELCMD_OK(i)) - output_data("%s ", - TELCMD(i)); - else - output_data("%d ", - i); - if (TELOPT_OK(j)) - output_data("%s", - TELOPT(j)); - else if (TELCMD_OK(j)) - output_data("%s", - TELCMD(j)); - else - output_data("%d", - j); - output_data(", not IAC SE!) "); - } - } - length -= 2; - } - if (length < 1) { - output_data("(Empty suboption??\?)"); - return; - } - switch (pointer[0]) { - case TELOPT_TTYPE: - output_data("TERMINAL-TYPE "); - switch (pointer[1]) { - case TELQUAL_IS: - output_data("IS \"%.*s\"", - (int)(length-2), - (char *)pointer+2); - break; - case TELQUAL_SEND: - output_data("SEND"); - break; - default: - output_data("- unknown qualifier %d (0x%x).", - pointer[1], pointer[1]); - } - break; - case TELOPT_TSPEED: - output_data("TERMINAL-SPEED"); - if (length < 2) { - output_data(" (empty suboption??\?)"); - break; - } - switch (pointer[1]) { - case TELQUAL_IS: - output_data(" IS %.*s", (int)(length-2), (char *)pointer+2); - break; - default: - if (pointer[1] == 1) - output_data(" SEND"); - else - output_data(" %d (unknown)", pointer[1]); - for (i = 2; i < length; i++) { - output_data(" ?%d?", pointer[i]); - } - break; - } - break; - - case TELOPT_LFLOW: - output_data("TOGGLE-FLOW-CONTROL"); - if (length < 2) { - output_data(" (empty suboption??\?)"); - break; - } - switch (pointer[1]) { - case LFLOW_OFF: - output_data(" OFF"); - break; - case LFLOW_ON: - output_data(" ON"); - break; - case LFLOW_RESTART_ANY: - output_data(" RESTART-ANY"); - break; - case LFLOW_RESTART_XON: - output_data(" RESTART-XON"); - break; - default: - output_data(" %d (unknown)", - pointer[1]); - } - for (i = 2; i < length; i++) { - output_data(" ?%d?", - pointer[i]); - } - break; - - case TELOPT_NAWS: - output_data("NAWS"); - if (length < 2) { - output_data(" (empty suboption??\?)"); - break; - } - if (length == 2) { - output_data(" ?%d?", - pointer[1]); - break; - } - output_data(" %u %u(%u)", - pointer[1], - pointer[2], - (((unsigned int)pointer[1])<<8) + pointer[2]); - if (length == 4) { - output_data(" ?%d?", - pointer[3]); - break; - } - output_data(" %u %u(%u)", - pointer[3], - pointer[4], - (((unsigned int)pointer[3])<<8) + pointer[4]); - for (i = 5; i < length; i++) { - output_data(" ?%d?", - pointer[i]); - } - break; - - case TELOPT_LINEMODE: - output_data("LINEMODE "); - if (length < 2) { - output_data(" (empty suboption??\?)"); - break; - } - switch (pointer[1]) { - case WILL: - output_data("WILL "); - goto common; - case WONT: - output_data("WONT "); - goto common; - case DO: - output_data("DO "); - goto common; - case DONT: - output_data("DONT "); - common: - if (length < 3) { - output_data("(no option??\?)"); - break; - } - switch (pointer[2]) { - case LM_FORWARDMASK: - output_data("Forward Mask"); - for (i = 3; i < length; i++) { - output_data(" %x", pointer[i]); - } - break; - default: - output_data("%d (unknown)", - pointer[2]); - for (i = 3; i < length; i++) { - output_data(" %d", - pointer[i]); - } - break; - } - break; - - case LM_SLC: - output_data("SLC"); - for (i = 2; i < length - 2; i += 3) { - if (SLC_NAME_OK(pointer[i+SLC_FUNC])) - output_data(" %s", - SLC_NAME(pointer[i+SLC_FUNC])); - else - output_data(" %d", - pointer[i+SLC_FUNC]); - switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { - case SLC_NOSUPPORT: - output_data(" NOSUPPORT"); - break; - case SLC_CANTCHANGE: - output_data(" CANTCHANGE"); - break; - case SLC_VARIABLE: - output_data(" VARIABLE"); - break; - case SLC_DEFAULT: - output_data(" DEFAULT"); - break; - } - output_data("%s%s%s", - pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", - pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", - pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); - if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN| - SLC_FLUSHOUT| SLC_LEVELBITS)) { - output_data("(0x%x)", - pointer[i+SLC_FLAGS]); - } - output_data(" %d;", - pointer[i+SLC_VALUE]); - if ((pointer[i+SLC_VALUE] == IAC) && - (pointer[i+SLC_VALUE+1] == IAC)) - i++; - } - for (; i < length; i++) { - output_data(" ?%d?", - pointer[i]); - } - break; - - case LM_MODE: - output_data("MODE "); - if (length < 3) { - output_data("(no mode??\?)"); - break; - } - { - char tbuf[32]; - snprintf(tbuf, - sizeof(tbuf), - "%s%s%s%s%s", - pointer[2]&MODE_EDIT ? "|EDIT" : "", - pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "", - pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "", - pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "", - pointer[2]&MODE_ACK ? "|ACK" : ""); - output_data("%s", - tbuf[1] ? &tbuf[1] : "0"); - } - if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) { - output_data(" (0x%x)", - pointer[2]); - } - for (i = 3; i < length; i++) { - output_data(" ?0x%x?", - pointer[i]); - } - break; - default: - output_data("%d (unknown)", - pointer[1]); - for (i = 2; i < length; i++) { - output_data(" %d", pointer[i]); - } - } - break; - - case TELOPT_STATUS: { - char *cp; - int j, k; - - output_data("STATUS"); - - switch (pointer[1]) { - default: - if (pointer[1] == TELQUAL_SEND) - output_data(" SEND"); - else - output_data(" %d (unknown)", - pointer[1]); - for (i = 2; i < length; i++) { - output_data(" ?%d?", - pointer[i]); - } - break; - case TELQUAL_IS: - output_data(" IS\r\n"); - - for (i = 2; i < length; i++) { - switch(pointer[i]) { - case DO: cp = "DO"; goto common2; - case DONT: cp = "DONT"; goto common2; - case WILL: cp = "WILL"; goto common2; - case WONT: cp = "WONT"; goto common2; - common2: - i++; - if (TELOPT_OK(pointer[i])) - output_data(" %s %s", - cp, - TELOPT(pointer[i])); - else - output_data(" %s %d", - cp, - pointer[i]); - - output_data("\r\n"); - break; - - case SB: - output_data(" SB "); - i++; - j = k = i; - while (j < length) { - if (pointer[j] == SE) { - if (j+1 == length) - break; - if (pointer[j+1] == SE) - j++; - else - break; - } - pointer[k++] = pointer[j++]; - } - printsub(0, &pointer[i], k - i); - if (i < length) { - output_data(" SE"); - i = j; - } else - i = j - 1; - - output_data("\r\n"); - - break; - - default: - output_data(" %d", - pointer[i]); - break; - } - } - break; - } - break; - } - - case TELOPT_XDISPLOC: - output_data("X-DISPLAY-LOCATION "); - switch (pointer[1]) { - case TELQUAL_IS: - output_data("IS \"%.*s\"", - (int)(length-2), - (char *)pointer+2); - break; - case TELQUAL_SEND: - output_data("SEND"); - break; - default: - output_data("- unknown qualifier %d (0x%x).", - pointer[1], pointer[1]); - } - break; - - case TELOPT_NEW_ENVIRON: - output_data("NEW-ENVIRON "); - goto env_common1; - case TELOPT_OLD_ENVIRON: - output_data("OLD-ENVIRON"); - env_common1: - switch (pointer[1]) { - case TELQUAL_IS: - output_data("IS "); - goto env_common; - case TELQUAL_SEND: - output_data("SEND "); - goto env_common; - case TELQUAL_INFO: - output_data("INFO "); - env_common: - { - int quote = 0; - for (i = 2; i < length; i++ ) { - switch (pointer[i]) { - case NEW_ENV_VAR: - if (quote) - output_data("\" "); - output_data("VAR "); - quote = 0; - break; - - case NEW_ENV_VALUE: - if (quote) - output_data("\" "); - output_data("VALUE "); - quote = 0; - break; - - case ENV_ESC: - if (quote) - output_data("\" "); - output_data("ESC "); - quote = 0; - break; - - case ENV_USERVAR: - if (quote) - output_data("\" "); - output_data("USERVAR "); - quote = 0; - break; - - default: - if (isprint(pointer[i]) && pointer[i] != '"') { - if (!quote) { - output_data("\""); - quote = 1; - } - output_data("%c", pointer[i]); - } else { - output_data("%03o ", pointer[i]); - quote = 0; - } - break; - } - } - if (quote) - output_data("\""); - break; - } - } - break; - -#ifdef AUTHENTICATION - case TELOPT_AUTHENTICATION: - output_data("AUTHENTICATION"); - - if (length < 2) { - output_data(" (empty suboption??\?)"); - break; - } - switch (pointer[1]) { - case TELQUAL_REPLY: - case TELQUAL_IS: - output_data(" %s ", - (pointer[1] == TELQUAL_IS) ? - "IS" : "REPLY"); - if (AUTHTYPE_NAME_OK(pointer[2])) - output_data("%s ", - AUTHTYPE_NAME(pointer[2])); - else - output_data("%d ", - pointer[2]); - if (length < 3) { - output_data("(partial suboption??\?)"); - break; - } - output_data("%s|%s", - ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? - "CLIENT" : "SERVER", - ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? - "MUTUAL" : "ONE-WAY"); - - auth_printsub(&pointer[1], length - 1, buf, sizeof(buf)); - output_data("%s", - buf); - break; - - case TELQUAL_SEND: - i = 2; - output_data(" SEND "); - while (i < length) { - if (AUTHTYPE_NAME_OK(pointer[i])) - output_data("%s ", - AUTHTYPE_NAME(pointer[i])); - else - output_data("%d ", - pointer[i]); - if (++i >= length) { - output_data("(partial suboption??\?)"); - break; - } - output_data("%s|%s ", - ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? - "CLIENT" : "SERVER", - ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? - "MUTUAL" : "ONE-WAY"); - ++i; - } - break; - - case TELQUAL_NAME: - i = 2; - output_data(" NAME \"%.*s\"", - (int)(length - 2), - pointer); - break; - - default: - for (i = 2; i < length; i++) { - output_data(" ?%d?", - pointer[i]); - } - break; - } - break; -#endif - -#ifdef ENCRYPTION - case TELOPT_ENCRYPT: - output_data("ENCRYPT"); - if (length < 2) { - output_data(" (empty suboption?)"); - break; - } - switch (pointer[1]) { - case ENCRYPT_START: - output_data(" START"); - break; - - case ENCRYPT_END: - output_data(" END"); - break; - - case ENCRYPT_REQSTART: - output_data(" REQUEST-START"); - break; - - case ENCRYPT_REQEND: - output_data(" REQUEST-END"); - break; - - case ENCRYPT_IS: - case ENCRYPT_REPLY: - output_data(" %s ", - (pointer[1] == ENCRYPT_IS) ? - "IS" : "REPLY"); - if (length < 3) { - output_data(" (partial suboption?)"); - break; - } - if (ENCTYPE_NAME_OK(pointer[2])) - output_data("%s ", - ENCTYPE_NAME(pointer[2])); - else - output_data(" %d (unknown)", - pointer[2]); - - encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf)); - output_data("%s", - buf); - break; - - case ENCRYPT_SUPPORT: - i = 2; - output_data(" SUPPORT "); - while (i < length) { - if (ENCTYPE_NAME_OK(pointer[i])) - output_data("%s ", - ENCTYPE_NAME(pointer[i])); - else - output_data("%d ", - pointer[i]); - i++; - } - break; - - case ENCRYPT_ENC_KEYID: - output_data(" ENC_KEYID %d", pointer[1]); - goto encommon; - - case ENCRYPT_DEC_KEYID: - output_data(" DEC_KEYID %d", pointer[1]); - goto encommon; - - default: - output_data(" %d (unknown)", pointer[1]); - encommon: - for (i = 2; i < length; i++) { - output_data(" %d", pointer[i]); - } - break; - } - break; -#endif - - default: - if (TELOPT_OK(pointer[0])) - output_data("%s (unknown)", - TELOPT(pointer[0])); - else - output_data("%d (unknown)", - pointer[i]); - for (i = 1; i < length; i++) { - output_data(" %d", pointer[i]); - } - break; - } - output_data("\r\n"); -} - -/* - * Dump a data buffer in hex and ascii to the output data stream. - */ -void -printdata(char *tag, char *ptr, size_t cnt) -{ - size_t i; - char xbuf[30]; - - while (cnt) { - /* flush net output buffer if no room for new data) */ - if ((&netobuf[BUFSIZ] - nfrontp) < 80) { - netflush(); - } - - /* add a line of output */ - output_data("%s: ", tag); - for (i = 0; i < 20 && cnt; i++) { - output_data("%02x", *ptr); - if (isprint((unsigned char)*ptr)) { - xbuf[i] = *ptr; - } else { - xbuf[i] = '.'; - } - if (i % 2) { - output_data(" "); - } - cnt--; - ptr++; - } - xbuf[i] = '\0'; - output_data(" %s\r\n", xbuf); - } -} -#endif /* DIAGNOSTICS */ diff --git a/appl/test/Makefile.am b/appl/test/Makefile.am index 67801c9e1..7bc9b6f41 100644 --- a/appl/test/Makefile.am +++ b/appl/test/Makefile.am @@ -2,8 +2,11 @@ include $(top_srcdir)/Makefile.am.common +WFLAGS += $(WFLAGS_LITE) + noinst_PROGRAMS = tcp_client tcp_server gssapi_server gssapi_client \ - uu_server uu_client nt_gss_server nt_gss_client http_client + uu_server uu_client nt_gss_server nt_gss_client http_client \ + kinit_auditdns tcp_client_SOURCES = tcp_client.c common.c test_locl.h @@ -36,7 +39,28 @@ nt_gss_client_LDADD = $(gssapi_server_LDADD) nt_gss_server_LDADD = $(nt_gss_client_LDADD) +kinit_auditdns_SOURCES = ../../kuser/kinit.c auditdns.c + +kinit_auditdns_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/../../lib/krb5 + +# sync with kinit_LDADD in kuser/Makefile.am +if !NO_AFS +afs_lib = $(LIB_kafs) +endif +kinit_auditdns_LDADD = \ + $(afs_lib) \ + $(top_builddir)/lib/krb5/libkrb5.la \ + $(top_builddir)/lib/gssapi/libgssapi.la \ + $(top_builddir)/lib/gss_preauth/libgss_preauth.la \ + $(top_builddir)/lib/ntlm/libheimntlm.la \ + $(LIB_hcrypto) \ + $(top_builddir)/lib/asn1/libasn1.la \ + $(LIB_libintl) \ + $(LIB_roken) + LDADD = $(top_builddir)/lib/krb5/libkrb5.la \ $(LIB_hcrypto) \ $(top_builddir)/lib/asn1/libasn1.la \ $(LIB_roken) + +EXTRA_DIST = NTMakefile jgssapi_server.java diff --git a/appl/test/NTMakefile b/appl/test/NTMakefile new file mode 100644 index 000000000..15bea96ee --- /dev/null +++ b/appl/test/NTMakefile @@ -0,0 +1,35 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=appl\test + +!include ../../windows/NTMakefile.w32 + diff --git a/appl/test/auditdns.c b/appl/test/auditdns.c new file mode 100644 index 000000000..3a79af45e --- /dev/null +++ b/appl/test/auditdns.c @@ -0,0 +1,510 @@ +/*- + * Copyright (c) 2024 Taylor R. Campbell + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "resolve.h" +#include "roken.h" + +#if (__STDC_VERSION__ - 0) < 199901L +# define restrict /* empty */ +#endif + +struct rk_dns_reply * +rk_dns_lookup(const char *domain, const char *type_name) +{ + + fprintf(stderr, "DNS leak: %s %s (%s)\n", __func__, domain, type_name); + abort(); +} + +struct hostent * +gethostbyname(const char *name) +{ + + fprintf(stderr, "DNS leak: %s %s\n", __func__, name); + abort(); +} + +#ifdef HAVE_GETHOSTBYNAME2 + +struct hostent * +gethostbyname2(const char *name, int af) +{ + + fprintf(stderr, "DNS leak: %s %s\n", __func__, name); + abort(); +} + +#endif /* HAVE_GETHOSTBYNAME2 */ + +struct hostent * +gethostbyaddr(const void *addr, socklen_t len, int af) +{ + const socklen_t maxlen[] = { + [AF_INET] = sizeof(struct in_addr), + [AF_INET6] = sizeof(struct in6_addr), + }; + char n[INET6_ADDRSTRLEN + 1]; + + if (af < 0 || af >= sizeof(maxlen)/sizeof(maxlen[0]) || + maxlen[af] == 0 || len < maxlen[af] || + inet_ntop(af, addr, n, sizeof n) == NULL) + fprintf(stderr, "Reverse DNS leak: %s\n", __func__); + else + fprintf(stderr, "Reverse DNS leak: %s %s\n", __func__, n); + abort(); +} + +#ifdef HAVE_GETADDRINFO + +void +freeaddrinfo(struct addrinfo *ai) +{ + + free(ai->ai_addr); + free(ai); +} + +int +getaddrinfo(const char *hostname, const char *servname, + const struct addrinfo *restrict hints, + struct addrinfo **restrict res) +{ + char *servend; + unsigned long port; + union { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } *addr = NULL; + int af[2] = {AF_INET, AF_INET6}; + socklen_t addrlen[2] = {sizeof(addr->sin), sizeof(addr->sin6)}; + int socktype[2] = {SOCK_DGRAM, SOCK_STREAM}; + int proto[2] = {IPPROTO_UDP, IPPROTO_TCP}; + size_t i, j, naddr, nproto; + struct addrinfo *ai = NULL; + int error; + + /* + * DNS audit: Abort unless the user specified hints with + * AI_NUMERICHOST, AI_NUMERICSERV, and no AI_CANONNAME. + */ + if (hints == NULL || + (hints->ai_flags & AI_NUMERICHOST) == 0 || + (hints->ai_flags & AI_NUMERICSERV) == 0 || + (hints->ai_flags & AI_CANONNAME) != 0) { + fprintf(stderr, "DNS leak: %s %s:%s\n", + __func__, hostname, servname); + abort(); + } + + /* + * Check hints for address family. If unspecified, use the default + * set of address families: {AF_INET, AF_INET6}. + */ + switch (hints->ai_family) { + case AF_UNSPEC: + naddr = 2; + break; + case AF_INET: + naddr = 1; + af[0] = AF_INET; + addrlen[0] = sizeof(addr->sin); + break; + case AF_INET6: + naddr = 1; + af[0] = AF_INET6; + addrlen[0] = sizeof(addr->sin6); + break; + default: + error = EAI_FAMILY; + goto out; + } + + /* + * Check hints for socket type and protocol. If both are zero, we + * use the default set of socktype/proto pairs. If one is + * specified but not the other, use the default. If both are + * specified, make sure they match. + */ + switch (hints->ai_socktype) { + case 0: + if (hints->ai_protocol == 0) + nproto = sizeof(proto)/sizeof(proto[0]); + else + nproto = 1; + break; + case SOCK_DGRAM: /* datagram <-> UDP */ + if (hints->ai_protocol != 0 && hints->ai_protocol != IPPROTO_UDP) { + error = EAI_SOCKTYPE; + goto out; + } + socktype[0] = SOCK_DGRAM; + proto[0] = IPPROTO_UDP; + nproto = 1; + break; + case SOCK_STREAM: /* stream <-> TCP */ + if (hints->ai_protocol != 0 && hints->ai_protocol != IPPROTO_TCP) { + error = EAI_SOCKTYPE; + goto out; + } + socktype[0] = SOCK_STREAM; + proto[0] = IPPROTO_TCP; + nproto = 1; + break; + default: + error = EAI_SOCKTYPE; + goto out; + } + + /* + * Check whether a service is specified at all. + */ + if (servname == NULL) { + /* + * No service specified. Use the wildcard port 0. + */ + port = 0; + } else { + /* + * Service specified. First verify it is at most 5 decimal + * digits; then parse it as a nonnegative integer in decimal, + * at most 65535. (This avoids pathological inputs like + * -18446744073709551493 for which strtoul will succeed and + * return 123 on LP64 platforms.) + */ + if (strlen(servname) > strlen("65535") || + strlen(servname) != strspn(servname, "0123456789")) { + error = EAI_NONAME; + goto out; + } + errno = 0; + port = strtoul(servname, &servend, 10); + if (servend == servname || + *servend != '\0' || + errno != 0 || + port > 65535) { + error = EAI_NONAME; + goto out; + } + } + + /* + * Check whether a hostname is specified at all. + */ + if (hostname == NULL) { + /* + * No hostname. This only makes sense if we're going to bind + * to a socket and receive incoming packets or listen and + * accept incoming connections, i.e., only if AI_PASSIVE is + * set. Otherwise, fail with EAI_NONAME. + */ + if ((hints->ai_flags & AI_PASSIVE) == 0) { + error = EAI_NONAME; + goto out; + } + + /* + * Allocate an array of as many addresses as the hints allow. + */ + if ((addr = calloc(naddr, sizeof(*addr))) == NULL) { + error = EAI_MEMORY; + goto out; + } + + /* + * Fill the addresses with the ANY wildcard address, IPv4 + * 0.0.0.0 or IPv6 `::' (i.e., 0000:0000:....:0000). + */ + switch (hints->ai_family) { + case AF_UNSPEC: + assert(naddr == 2); + addr[0].sin.sin_family = AF_INET; + addr[0].sin.sin_port = htons(port); + addr[0].sin.sin_addr.s_addr = htonl(INADDR_ANY); + addr[1].sin6.sin6_family = AF_INET6; + addr[1].sin6.sin6_port = htons(port); + addr[1].sin6.sin6_addr = in6addr_any; + break; + case AF_INET: + assert(naddr == 1); + addr[0].sin.sin_family = AF_INET; + addr[0].sin.sin_port = htons(port); + addr[0].sin.sin_addr.s_addr = htonl(INADDR_ANY); + break; + case AF_INET6: + assert(naddr == 1); + addr[0].sin6.sin6_family = AF_INET6; + addr[0].sin6.sin6_port = htons(port); + addr[0].sin6.sin6_addr = in6addr_any; + break; + default: + error = EAI_FAIL; /* XXX unreachable */ + goto out; + } + goto have_addr; + } else { + /* + * Allocate a single socket address record. Since we have + * AI_NUMERICHOST, the hostname can be parsed as only one + * address and won't be resolved to an array of possibly >1 + * addresses. + */ + naddr = 1; + if ((addr = calloc(naddr, sizeof(*addr))) == NULL) { + error = EAI_MEMORY; + goto out; + } + + /* + * If the hints specify AF_INET, or don't specify anything, try + * to parse it as an IPv4 address. If this fails, it will fall + * through. + */ + if (hints->ai_family == AF_UNSPEC || hints->ai_family == AF_INET) { + switch (inet_pton(AF_INET, hostname, &addr->sin.sin_addr)) { + case -1: /* system error */ + error = EAI_SYSTEM; + goto out; + case 0: /* failure */ + break; + case 1: /* success */ + addr->sin.sin_family = AF_INET; + addr->sin.sin_port = htons(port); + af[0] = AF_INET; + addrlen[0] = sizeof(addr->sin); + goto have_addr; + } + } + + /* + * If the hints specify AF_INET6, or don't specify anything, + * try to parse it as an IPv6 address. If this fails, it will + * fall through. + */ + if (hints->ai_family == AF_UNSPEC || hints->ai_family == AF_INET6) { + /* XXX scope id? */ + switch (inet_pton(AF_INET6, hostname, &addr->sin6.sin6_addr)) { + case -1: /* system error */ + error = EAI_SYSTEM; + goto out; + case 0: /* failure */ + break; + case 1: /* success */ + addr->sin6.sin6_family = AF_INET6; + addr->sin6.sin6_port = htons(port); + af[0] = AF_INET6; + addrlen[0] = sizeof(addr->sin6); + goto have_addr; + } + } + + /* + * Hostname can't be parsed. + */ + error = EAI_NONAME; + goto out; + } + +have_addr: + /* + * We have an address, or multiple possible addresses. Allocate an + * array of addrinfo records to store the result. + */ + if ((ai = calloc(naddr * nproto, sizeof(*ai))) == NULL) { + error = EAI_MEMORY; + goto out; + } + + /* + * Fill in the addrinfo records with the cartesian product of + * matching address families and matching socktype/protocol pairs. + * + * XXX Consider randomizing the output for fun! + */ + for (i = 0; i < naddr; i++) { + for (j = 0; j < nproto; j++) { + ai[i*nproto + j] = (struct addrinfo) { + .ai_flags = 0, /* input flags, unused on output */ + .ai_family = af[i], + .ai_addrlen = addrlen[i], + .ai_addr = &addr[i].sa, + .ai_socktype = socktype[j], + .ai_protocol = proto[j], + .ai_canonname = NULL, + .ai_next = &ai[i*nproto + j + 1], + }; + } + } + addr = NULL; /* reference consumed by ai[...].ai_addr */ + + /* + * Null out the last addrinfo's next pointer. + */ + ai[naddr*nproto - 1].ai_next = NULL; + + /* + * Success! + */ + error = 0; + +out: + /* + * In the event of error, free whatever we've allocated so far. + * Make sure to save and restore errno in case free touches it, + * because EAI_SYSTEM requires errno to report the system error. + */ + if (error) { + int errno_save = errno; + + if (addr) + free(addr); + addr = NULL; + if (ai) + freeaddrinfo(ai); + ai = NULL; + + errno = errno_save; + } + *res = ai; + return error; +} + +#endif /* HAVE_GETADDRINFO */ + +#ifdef HAVE_GETNAMEINFO + +int +getnameinfo(const struct sockaddr *restrict sa, socklen_t salen, + char *restrict node, socklen_t nodelen, + char *restrict service, socklen_t servicelen, + int flags) +{ + char n[INET6_ADDRSTRLEN + 1] = ""; + char s[5 + 1] = ""; /* ceil(log_10(2^16)) + 1 */ + + /* + * Call inet_ntop to format the appropriate member of the + * sockaddr_*. + */ + switch (sa->sa_family) { + case AF_INET: { + struct sockaddr_in sin; + + /* + * Verify the socket address length is at least enough for + * sockaddr_in, and make a copy to avoid strict aliasing + * violation. + */ + if (salen < sizeof sin) + return EAI_FAIL; + memcpy(&sin, sa, sizeof sin); + + /* + * Use inet_ntop to format sin_addr as x.y.z.w, and use + * snprintf to format the port number in decimal. + */ + if (inet_ntop(AF_INET, &sin.sin_addr, n, sizeof n) == NULL) + return EAI_FAIL; + snprintf(s, sizeof s, "%d", (int)sin.sin_port); + break; + } + case AF_INET6: { + struct sockaddr_in6 sin6; + + /* + * Verify the socket address length is at least enough for + * sockaddr_in6, and make a copy to avoid strict aliasing + * violation. + */ + if (salen < sizeof sin6) + return EAI_FAIL; + memcpy(&sin6, sa, sizeof sin6); + + /* + * Use inet_ntop to format sin6_addr as a:b:c:...:h, and use + * snprintf to format the port number in decimal. + */ + if (inet_ntop(AF_INET6, &sin6.sin6_addr, n, sizeof n) == NULL) + return EAI_FAIL; + /* XXX scope id? */ + snprintf(s, sizeof s, "%d", (int)sin6.sin6_port); + break; + } + default: + return EAI_FAMILY; + } + + /* + * DNS audit: Abort unless the user specified flags with + * NI_NUMERICHOST|NI_NUMERICSERV|NI_NUMERICSCOPE. We format the + * numeric syntax first so it can be included in the error message + * to give a clue about what might have DNS leaks. + * + * The NI_NUMERICSCOPE test is written in a funny way so that on + * platforms where it simply doesn't exist (like glibc and + * Windows), it doesn't spuriously fail -- scope ids naming is + * probably not a source of network leaks. + */ + if ((flags & NI_NUMERICHOST) == 0 || + (flags & NI_NUMERICSERV) == 0 || + (flags & NI_NUMERICSCOPE) != NI_NUMERICSCOPE) { + fprintf(stderr, "Reverse DNS leak: %s %s %s\n", __func__, n, s); + abort(); + } + + /* + * Verify the (numeric) `names' we determined fit in the buffers + * provided, if any. + */ + if ((node && nodelen > 0 && strlen(n) >= nodelen) || + (service && servicelen > 0 && strlen(s) >= servicelen)) + return EAI_OVERFLOW; + + /* + * Copy out the answers that were requested. + */ + if (node) + strlcpy(node, n, nodelen); + if (service) + strlcpy(service, s, servicelen); + + return 0; +} + +#endif /* HAVE_GETNAMEINFO */ diff --git a/appl/test/common.c b/appl/test/common.c index 9ac880550..3f0fc23f0 100644 --- a/appl/test/common.c +++ b/appl/test/common.c @@ -33,25 +33,25 @@ #include "test_locl.h" -RCSID("$Id$"); - static int help_flag; static int version_flag; static char *port_str; -static char *keytab_str; +char *keytab_str; krb5_keytab keytab; char *service = SERVICE; char *mech = "krb5"; int fork_flag; +char *password = NULL; static struct getargs args[] = { { "port", 'p', arg_string, &port_str, "port to listen to", "port" }, { "service", 's', arg_string, &service, "service to use", "service" }, { "keytab", 'k', arg_string, &keytab_str, "keytab to use", "keytab" }, { "mech", 'm', arg_string, &mech, "gssapi mech to use", "mech" }, - { "fork", 'f', arg_flag, &fork_flag, "do fork" }, - { "help", 'h', arg_flag, &help_flag }, - { "version", 0, arg_flag, &version_flag } + { "password", 'P', arg_string, &password, "password to use", "password" }, + { "fork", 'f', arg_flag, &fork_flag, "do fork", NULL }, + { "help", 'h', arg_flag, &help_flag, NULL, NULL }, + { "version", 0, arg_flag, &version_flag, NULL, NULL } }; static int num_args = sizeof(args) / sizeof(args[0]); @@ -113,12 +113,15 @@ server_setup(krb5_context *context, int argc, char **argv) if(argv[argc] != NULL) server_usage(1, args, num_args); - if (keytab_str != NULL) - ret = krb5_kt_resolve (*context, keytab_str, &keytab); - else - ret = krb5_kt_default (*context, &keytab); - if (ret) - krb5_err (*context, 1, ret, "krb5_kt_resolve/default"); + if (keytab_str != NULL) { + ret = krb5_kt_resolve (*context, keytab_str, &keytab); + if (ret) + krb5_err (*context, 1, ret, "krb5_kt_resolve"); + } else { + ret = krb5_kt_default (*context, &keytab); + if (ret) + krb5_err (*context, 1, ret, "krb5_kt_default"); + } return port; } @@ -160,6 +163,9 @@ client_doit (const char *hostname, int port, const char *service, s = socket (a->ai_family, a->ai_socktype, a->ai_protocol); if (s < 0) continue; + + socket_set_ipv6only(s, 1); + if (connect (s, a->ai_addr, a->ai_addrlen) < 0) { warn ("connect(%s)", hostname); close (s); diff --git a/appl/test/gssapi_client.c b/appl/test/gssapi_client.c index e7682195d..13049c800 100644 --- a/appl/test/gssapi_client.c +++ b/appl/test/gssapi_client.c @@ -45,6 +45,7 @@ do_trans (int sock, gss_ctx_id_t context_hdl) gss_buffer_desc real_input_token, real_output_token; gss_buffer_t input_token = &real_input_token, output_token = &real_output_token; + int conf_flag; /* get_mic */ @@ -62,6 +63,24 @@ do_trans (int sock, gss_ctx_id_t context_hdl) write_token (sock, input_token); write_token (sock, output_token); + gss_release_buffer(&min_stat, output_token); + + /* verify mic */ + + read_token (sock, input_token); + read_token (sock, output_token); + + maj_stat = gss_verify_mic(&min_stat, + context_hdl, + input_token, + output_token, + NULL); + if (GSS_ERROR(maj_stat)) + gss_err (1, min_stat, "gss_verify_mic"); + + gss_release_buffer (&min_stat, input_token); + gss_release_buffer (&min_stat, output_token); + /* wrap */ input_token->length = 7; @@ -91,26 +110,41 @@ do_trans (int sock, gss_ctx_id_t context_hdl) write_token (sock, output_token); + read_token (sock, input_token); + + maj_stat = gss_unwrap (&min_stat, + context_hdl, + input_token, + output_token, + &conf_flag, + NULL); + if(GSS_ERROR(maj_stat)) + gss_err (1, min_stat, "gss_unwrap"); + + write_token (sock, output_token); + + gss_release_buffer(&min_stat, output_token); + return 0; } +extern char *password; + static int proto (int sock, const char *hostname, const char *service) { - struct sockaddr_in remote, local; + struct sockaddr_storage remote, local; socklen_t addrlen; int context_established = 0; gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT; + gss_cred_id_t cred = GSS_C_NO_CREDENTIAL; gss_buffer_desc real_input_token, real_output_token; gss_buffer_t input_token = &real_input_token, output_token = &real_output_token; OM_uint32 maj_stat, min_stat; gss_name_t server; gss_buffer_desc name_token; - struct gss_channel_bindings_struct input_chan_bindings; - u_char init_buf[4]; - u_char acct_buf[4]; gss_OID mech_oid; char *str; @@ -121,7 +155,7 @@ proto (int sock, const char *hostname, const char *service) if (str == NULL) errx(1, "malloc - out of memory"); name_token.value = str; - + maj_stat = gss_import_name (&min_stat, &name_token, GSS_C_NT_HOSTBASED_SERVICE, @@ -130,19 +164,44 @@ proto (int sock, const char *hostname, const char *service) gss_err (1, min_stat, "Error importing name `%s@%s':\n", service, hostname); + if (password) { + gss_buffer_desc pw; + + pw.value = password; + pw.length = strlen(password); + + maj_stat = gss_acquire_cred_with_password(&min_stat, + GSS_C_NO_NAME, + &pw, + GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, + GSS_C_INITIATE, + &cred, + NULL, + NULL); + if (GSS_ERROR(maj_stat)) + gss_err (1, min_stat, + "Error acquiring default initiator credentials"); + } + addrlen = sizeof(local); if (getsockname (sock, (struct sockaddr *)&local, &addrlen) < 0 - || addrlen != sizeof(local)) + || addrlen > sizeof(local)) err (1, "getsockname(%s)", hostname); addrlen = sizeof(remote); if (getpeername (sock, (struct sockaddr *)&remote, &addrlen) < 0 - || addrlen != sizeof(remote)) + || addrlen > sizeof(remote)) err (1, "getpeername(%s)", hostname); input_token->length = 0; output_token->length = 0; +#if 0 + struct gss_channel_bindings_struct input_chan_bindings; + u_char init_buf[4]; + u_char acct_buf[4]; + input_chan_bindings.initiator_addrtype = GSS_C_AF_INET; input_chan_bindings.initiator_address.length = 4; init_buf[0] = (local.sin_addr.s_addr >> 24) & 0xFF; @@ -159,12 +218,11 @@ proto (int sock, const char *hostname, const char *service) acct_buf[3] = (remote.sin_addr.s_addr >> 0) & 0xFF; input_chan_bindings.acceptor_address.value = acct_buf; -#if 0 input_chan_bindings.application_data.value = emalloc(4); * (unsigned short*)input_chan_bindings.application_data.value = local.sin_port; * ((unsigned short *)input_chan_bindings.application_data.value + 1) = remote.sin_port; input_chan_bindings.application_data.length = 4; -#else + input_chan_bindings.application_data.length = 0; input_chan_bindings.application_data.value = NULL; #endif @@ -172,14 +230,13 @@ proto (int sock, const char *hostname, const char *service) while(!context_established) { maj_stat = gss_init_sec_context(&min_stat, - GSS_C_NO_CREDENTIAL, + cred, &context_hdl, server, mech_oid, - GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG - | GSS_C_DELEG_FLAG, + GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG, 0, - &input_chan_bindings, + NULL, input_token, NULL, output_token, diff --git a/appl/test/gssapi_server.c b/appl/test/gssapi_server.c index 0c622796e..74ceb3bee 100644 --- a/appl/test/gssapi_server.c +++ b/appl/test/gssapi_server.c @@ -31,12 +31,15 @@ * SUCH DAMAGE. */ +/* + * A sample server that uses the GSSAPI. + */ + #include "test_locl.h" #include #include #include #include "gss_common.h" -RCSID("$Id$"); static int process_it(int sock, @@ -90,6 +93,24 @@ process_it(int sock, gss_release_buffer (&min_stat, input_token); gss_release_buffer (&min_stat, output_token); + /* create mic */ + + input_token->length = 6; + input_token->value = strdup("hejsan"); + + maj_stat = gss_get_mic(&min_stat, + context_hdl, + GSS_C_QOP_DEFAULT, + input_token, + output_token); + if (GSS_ERROR(maj_stat)) + gss_err (1, min_stat, "gss_get_mic"); + + write_token (sock, input_token); + write_token (sock, output_token); + + gss_release_buffer (&min_stat, output_token); + /* gss_unwrap */ read_token (sock, input_token); @@ -128,6 +149,27 @@ process_it(int sock, gss_release_buffer (&min_stat, input_token); gss_release_buffer (&min_stat, output_token); + input_token->value = "hejhej"; + input_token->length = 6; + + maj_stat = gss_wrap (&min_stat, + context_hdl, + 1, + GSS_C_QOP_DEFAULT, + input_token, + NULL, + output_token); + if (GSS_ERROR(maj_stat)) + gss_err(1, min_stat, "gss_wrap"); + + write_token (sock, output_token); + gss_release_buffer (&min_stat, output_token); + + read_token (sock, input_token); + + if (input_token->length != 6 && memcmp(input_token->value, "hejhej", 6) != 0) + errx(1, "invalid reply"); + return 0; } @@ -144,12 +186,15 @@ proto (int sock, const char *service) gss_name_t client_name; struct gss_channel_bindings_struct input_chan_bindings; gss_cred_id_t delegated_cred_handle = NULL; - krb5_ccache ccache; + krb5_ccache ccache = NULL; u_char init_buf[4]; u_char acct_buf[4]; gss_OID mech_oid; char *mech, *p; + memset(&remote, 0, sizeof(remote)); + local = remote; + addrlen = sizeof(local); if (getsockname (sock, (struct sockaddr *)&local, &addrlen) < 0 || addrlen != sizeof(local)) @@ -230,15 +275,21 @@ proto (int sock, const char *service) printf("Using mech: %s\n", mech); if (delegated_cred_handle != GSS_C_NO_CREDENTIAL) { - krb5_context context; + krb5_context context = NULL; printf("Delegated cred found\n"); - maj_stat = krb5_init_context(&context); - maj_stat = krb5_cc_resolve(context, "FILE:/tmp/krb5cc_test", &ccache); - maj_stat = gss_krb5_copy_ccache(&min_stat, - delegated_cred_handle, - ccache); + min_stat = krb5_init_context(&context); + if (min_stat) + gss_err(1, min_stat, "krb5_init_context"); + if (min_stat == 0) + min_stat = krb5_cc_resolve(context, "FILE:/tmp/krb5cc_test", &ccache); + if (min_stat == 0) + maj_stat = gss_krb5_copy_ccache(&min_stat, + delegated_cred_handle, + ccache); + else + maj_stat = GSS_S_FAILURE; if (maj_stat == 0) { krb5_principal p; maj_stat = krb5_cc_get_principal(context, ccache, &p); @@ -253,6 +304,7 @@ proto (int sock, const char *service) } } krb5_cc_close(context, ccache); + krb5_free_context(context); gss_release_cred(&min_stat, &delegated_cred_handle); } @@ -294,13 +346,16 @@ proto (int sock, const char *service) } } -static int -doit (int port, const char *service) +static void +loop (int port, const char *service) { int sock, sock2; struct sockaddr_in my_addr; int one = 1; + if (keytab_str) + gsskrb5_register_acceptor_identity(keytab_str); + sock = socket (AF_INET, SOCK_STREAM, 0); if (sock < 0) err (1, "socket"); @@ -317,20 +372,33 @@ doit (int port, const char *service) if (bind (sock, (struct sockaddr *)&my_addr, sizeof(my_addr)) < 0) err (1, "bind"); - if (listen (sock, 1) < 0) - err (1, "listen"); + while (1) { + if (listen (sock, 1) < 0) + err (1, "listen"); - sock2 = accept (sock, NULL, NULL); - if (sock2 < 0) - err (1, "accept"); + sock2 = accept (sock, NULL, NULL); + if (sock2 < 0) + err (1, "accept"); - return proto (sock2, service); + proto (sock2, service); + } } +/* + * Iterative server; process one connection at a time. + */ int main(int argc, char **argv) { krb5_context context = NULL; /* XXX */ + krb5_error_code ret; int port = server_setup(&context, argc, argv); - return doit (port, service); + + ret = krb5_kt_have_content(context, keytab); + if (ret) + krb5_err (context, 1, ret, "krb5_kt_have_content"); + + loop (port, service); + return 0; } + diff --git a/appl/test/http_client.c b/appl/test/http_client.c index 1ebad8b1c..88a8fee35 100644 --- a/appl/test/http_client.c +++ b/appl/test/http_client.c @@ -117,15 +117,17 @@ static char *port_str = "http"; static char *gss_service = "HTTP"; static struct getargs http_args[] = { - { "verbose", 'v', arg_flag, &verbose_flag, "verbose logging", }, + { "verbose", 'v', arg_flag, &verbose_flag, "verbose logging", NULL }, { "port", 'p', arg_string, &port_str, "port to connect to", "port" }, - { "delegate", 0, arg_flag, &delegate_flag, "gssapi delegate credential" }, + { "delegate", 0, arg_flag, &delegate_flag, "gssapi delegate credential", + NULL }, { "gss-service", 's', arg_string, &gss_service, "gssapi service to use", "service" }, { "mech", 'm', arg_string, &mech, "gssapi mech to use", "mech" }, - { "mutual", 0, arg_negative_flag, &mutual_flag, "no gssapi mutual auth" }, - { "help", 'h', arg_flag, &help_flag }, - { "version", 0, arg_flag, &version_flag } + { "mutual", 0, arg_negative_flag, &mutual_flag, "no gssapi mutual auth", + NULL }, + { "help", 'h', arg_flag, &help_flag, NULL, NULL }, + { "version", 0, arg_flag, &version_flag, NULL, NULL } }; static int num_http_args = sizeof(http_args) / sizeof(http_args[0]); @@ -189,7 +191,7 @@ http_find_header(struct http_req *req, const char *header) static int http_query(const char *host, const char *page, - char **headers, int num_headers, struct http_req *req) + char **headers, struct http_req *req) { enum { RESPONSE, HEADER, BODY } state; ssize_t ret; @@ -204,7 +206,7 @@ http_query(const char *host, const char *page, errx(1, "connection failed"); fdprintf(s, "GET %s HTTP/1.0\r\n", page); - for (i = 0; i < num_headers; i++) + for (i = 0; headers[i]; i++) fdprintf(s, "%s\r\n", headers[i]); fdprintf(s, "Host: %s\r\n\r\n", host); @@ -216,7 +218,7 @@ http_query(const char *host, const char *page, break; else if (ret < 0) err (1, "read: %lu", (unsigned long)ret); - + in_buf[ret + in_len] = '\0'; if (state == HEADER || state == RESPONSE) { @@ -237,12 +239,16 @@ http_query(const char *host, const char *page, in_ptr -= 2; break; } else if (state == RESPONSE) { - req->response = strndup(in_buf, p - in_buf); + req->response = emalloc(p - in_buf + 1); + memcpy(req->response, in_buf, p - in_buf); + req->response[p - in_buf] = '\0'; state = HEADER; } else { req->headers = realloc(req->headers, (req->num_headers + 1) * sizeof(req->headers[0])); - req->headers[req->num_headers] = strndup(in_buf, p - in_buf); + req->headers[req->num_headers] = emalloc(p - in_buf + 1); + memcpy(req->headers[req->num_headers], in_buf, p - in_buf); + req->headers[req->num_headers][p - in_buf] = '\0'; if (req->headers[req->num_headers] == NULL) errx(1, "strdup"); req->num_headers++; @@ -286,8 +292,8 @@ main(int argc, char **argv) struct http_req req; const char *host, *page; int i, done, print_body, gssapi_done, gssapi_started; - char *headers[10]; /* XXX */ - int num_headers; + char *headers[10] = { 0 }; + int num_headers = 0; gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT; gss_name_t server = GSS_C_NO_NAME; int optind = 0; @@ -310,6 +316,7 @@ main(int argc, char **argv) argc -= optind; argv += optind; + memset(&req, 0, sizeof(req)); mech_oid = select_mech(mech); if (argc != 1 && argc != 2) @@ -333,11 +340,16 @@ main(int argc, char **argv) do { print_body = 0; - http_query(host, page, headers, num_headers, &req); - for (i = 0 ; i < num_headers; i++) + http_query(host, page, headers, &req); + for (i = 0 ; headers[i]; i++) { free(headers[i]); + headers[i] = NULL; + } num_headers = 0; + if (req.response == NULL) + errx(1, "Got no response"); + if (strstr(req.response, " 200 ") != NULL) { print_body = 1; done = 1; @@ -358,7 +370,7 @@ main(int argc, char **argv) if (verbose_flag) printf("Negotiate found\n"); - + if (server == GSS_C_NO_NAME) { char *name; asprintf(&name, "%s@%s", gss_service, host); @@ -384,7 +396,7 @@ main(int argc, char **argv) if (len == 0) errx(1, "invalid Negotiate token"); input_token.value = emalloc(len); - len = base64_decode(&h[i], input_token.value); + len = rk_base64_decode(&h[i], input_token.value); if (len < 0) errx(1, "invalid base64 Negotiate token %s", &h[i]); input_token.length = len; @@ -467,14 +479,13 @@ main(int argc, char **argv) if (output_token.length) { char *neg_token; - base64_encode(output_token.value, - output_token.length, - &neg_token); - - asprintf(&headers[0], "Authorization: Negotiate %s", + rk_base64_encode(output_token.value, + output_token.length, + &neg_token); + + asprintf(&headers[num_headers++], "Authorization: Negotiate %s", neg_token); - num_headers = 1; free(neg_token); gss_release_buffer(&min_stat, &output_token); } diff --git a/appl/test/jgssapi_server.java b/appl/test/jgssapi_server.java new file mode 100644 index 000000000..6a9e75e84 --- /dev/null +++ b/appl/test/jgssapi_server.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +import org.ietf.jgss.*; +import java.io.*; +import java.net.Socket; +import java.net.ServerSocket; + +public class jgssapi_server { + + static byte [] getMessage(DataInputStream inStream) + throws IOException + { + byte[] token; + token = new byte[inStream.readInt()]; + inStream.readFully(token); + return token; + } + + static void putMessage(DataOutputStream outStream, byte [] token) + throws IOException + { + outStream.writeInt(token.length); + outStream.write(token); + } + + + public static void main(String[] args) + throws IOException, GSSException { + + GSSManager manager = GSSManager.getInstance(); + + GSSContext context = manager.createContext((GSSCredential)null); + + byte[] token = null; + + int port = 4717; + + System.out.println("listen on port " + port); + + Socket s = new ServerSocket(port).accept(); + + DataInputStream inStream = new DataInputStream(s.getInputStream()); + DataOutputStream outStream = new DataOutputStream(s.getOutputStream()); + + System.out.println("negotiate context"); + while (!context.isEstablished()) { + token = getMessage(inStream); + + token = context.acceptSecContext(token, 0, token.length); + if (token != null) + putMessage(outStream, token); + } + + System.out.println("done"); + + /* + * mic + */ + System.out.println("mic test"); + + System.out.println(" verify mic"); + + byte[] intoken = getMessage(inStream); + byte[] outtoken = getMessage(inStream); + byte[] bytes = null; + + context.verifyMIC(outtoken, 0, outtoken.length, + intoken, 0, intoken.length, new MessageProp(0, false)); + + System.out.println(" create mic"); + + bytes = new byte[] { 0x66, 0x6f, 0x6f }; + + outtoken = context.getMIC(bytes, 0, bytes.length, new MessageProp(0, false)); + putMessage(outStream, bytes); + putMessage(outStream, outtoken); + + /* + * wrap int + */ + System.out.println("warp int"); + + outtoken = getMessage(inStream); + + bytes = context.unwrap(outtoken, 0, outtoken.length, new MessageProp(0, false)); + + if (bytes == null) + System.err.println("wrap int failed"); + + /* + * wrap conf + */ + System.out.println("warp conf"); + + outtoken = getMessage(inStream); + + bytes = context.unwrap(outtoken, 0, outtoken.length, new MessageProp(0, true)); + + if (bytes == null) + System.err.println("wrap conf failed"); + + + /* + * wrap conf + */ + System.out.println("warp conf"); + intoken = new byte[] { 0x66, 0x6f, 0x6f }; + outtoken = context.wrap(intoken, 0, intoken.length, new MessageProp(0, true)); + putMessage(outStream, outtoken); + outtoken = getMessage(inStream); + + context.dispose(); + + System.exit(0); + } +} + diff --git a/appl/test/nt_gss_common.c b/appl/test/nt_gss_common.c index ce8502fb8..617c18a37 100644 --- a/appl/test/nt_gss_common.c +++ b/appl/test/nt_gss_common.c @@ -86,6 +86,8 @@ nt_read_token (int sock, gss_buffer_t buf) | (net_len[2] << 16) | (net_len[3] << 24); + if (len > INT_MAX/16) + errx(1, "len too large"); buf->length = len; buf->value = malloc(len); if (read (sock, buf->value, len) != len) @@ -107,7 +109,7 @@ gss_print_errors (int min_stat) GSS_C_NO_OID, &msg_ctx, &status_string); - fprintf (stderr, "%.*s\n", + fprintf (stderr, "%.*s\n", (int)status_string.length, (char *)status_string.value); gss_release_buffer (&new_stat, &status_string); diff --git a/appl/test/nt_gss_server.c b/appl/test/nt_gss_server.c index cdfee1ea5..d6f7cc1be 100644 --- a/appl/test/nt_gss_server.c +++ b/appl/test/nt_gss_server.c @@ -58,8 +58,8 @@ static struct getargs args[] = { { "service", 's', arg_string, &service, "service to use", "service" }, { "dump-auth", 0, arg_string, &auth_file, "dump authorization data", "file" }, - { "help", 'h', arg_flag, &help_flag }, - { "version", 0, arg_flag, &version_flag } + { "help", 'h', arg_flag, &help_flag, NULL, NULL }, + { "version", 0, arg_flag, &version_flag, NULL, NULL } }; static int num_args = sizeof(args) / sizeof(args[0]); diff --git a/appl/test/tcp_server.c b/appl/test/tcp_server.c index f8df34fc9..50d1bf4d6 100644 --- a/appl/test/tcp_server.c +++ b/appl/test/tcp_server.c @@ -31,9 +31,17 @@ * SUCH DAMAGE. */ +/* + * A sample server that uses the Kerberos V5 API. + * + * See "Introduction to the Kerberos 5 API" in the Doxygen documentation + * for a walkthrough of this code. + */ + #include "test_locl.h" RCSID("$Id$"); +/* The API needs one Kerberos context per thread. */ krb5_context context; static int @@ -50,20 +58,22 @@ proto (int sock, const char *service) uint32_t len, net_len; ssize_t n; + /* Initialize the authentication context, to be used to authenticate the peer. */ status = krb5_auth_con_init (context, &auth_context); if (status) krb5_err (context, 1, status, "krb5_auth_con_init"); + /* Extract the local and remote address from the socket into auth_context. */ status = krb5_auth_con_setaddrs_from_fd (context, auth_context, &sock); - if (status) krb5_err (context, 1, status, "krb5_auth_con_setaddrs_from_fd"); - if(gethostname (hostname, sizeof(hostname)) < 0) + if (gethostname (hostname, sizeof(hostname)) < 0) krb5_err (context, 1, errno, "gethostname"); + /* Create principal "server" for "service" on "hostname" (this host). */ status = krb5_sname_to_principal (context, hostname, service, @@ -72,17 +82,22 @@ proto (int sock, const char *service) if (status) krb5_err (context, 1, status, "krb5_sname_to_principal"); + /* + * Perform the server side of the sendauth protocol. On success, "ticket" + * contains the authenticated credentials of the client. + */ status = krb5_recvauth (context, &auth_context, &sock, VERSION, server, - 0, + 0, /* flags */ keytab, &ticket); if (status) krb5_err (context, 1, status, "krb5_recvauth"); + /* Extract the client name as a string. */ status = krb5_unparse_name (context, ticket->client, &name); @@ -95,6 +110,9 @@ proto (int sock, const char *service) krb5_data_zero (&data); krb5_data_zero (&packet); + /* + * Read the payload (encoded as length, value). + */ n = krb5_net_read (context, &sock, &net_len, 4); if (n == 0) krb5_errx (context, 1, "EOF in krb5_net_read"); @@ -111,6 +129,9 @@ proto (int sock, const char *service) if (n < 0) krb5_err (context, 1, errno, "krb5_net_read"); + /* + * Expect a KRB_SAFE message (authenticated, not encrypted) + */ status = krb5_rd_safe (context, auth_context, &packet, @@ -122,6 +143,9 @@ proto (int sock, const char *service) fprintf (stderr, "safe packet: %.*s\n", (int)data.length, (char *)data.data); + /* + * Read the payload (encoded as length, value). + */ n = krb5_net_read (context, &sock, &net_len, 4); if (n == 0) krb5_errx (context, 1, "EOF in krb5_net_read"); @@ -138,6 +162,9 @@ proto (int sock, const char *service) if (n < 0) krb5_err (context, 1, errno, "krb5_net_read"); + /* + * Expect a KRB_PRIV message (authenticated and encrypted) + */ status = krb5_rd_priv (context, auth_context, &packet, @@ -155,14 +182,24 @@ proto (int sock, const char *service) static int doit (int port, const char *service) { - mini_inetd (port); + /* Block waiting for a connection. */ + mini_inetd (port, NULL); return proto (STDIN_FILENO, service); } +/* + * Process only one connection and then exit. + */ int main(int argc, char **argv) { int port = server_setup(&context, argc, argv); + krb5_error_code ret; + + ret = krb5_kt_have_content(context, keytab); + if (ret) + krb5_err (context, 1, ret, "krb5_kt_have_content"); + return doit (port, service); } diff --git a/appl/test/test_locl.h b/appl/test/test_locl.h index a2135c4fb..dba2bba1b 100644 --- a/appl/test/test_locl.h +++ b/appl/test/test_locl.h @@ -80,6 +80,7 @@ extern char *service; extern char *mech; +extern char *keytab_str; extern krb5_keytab keytab; extern int fork_flag; int server_setup(krb5_context*, int, char**); diff --git a/appl/test/uu_client.c b/appl/test/uu_client.c index 749f05583..15e789973 100644 --- a/appl/test/uu_client.c +++ b/appl/test/uu_client.c @@ -39,7 +39,7 @@ krb5_context context; static int proto (int sock, const char *hostname, const char *service) { - struct sockaddr_in remote, local; + struct sockaddr_storage remote, local; socklen_t addrlen; krb5_address remote_addr, local_addr; krb5_context context; @@ -54,12 +54,12 @@ proto (int sock, const char *hostname, const char *service) addrlen = sizeof(local); if (getsockname (sock, (struct sockaddr *)&local, &addrlen) < 0 - || addrlen != sizeof(local)) + || addrlen > sizeof(local)) err (1, "getsockname(%s)", hostname); addrlen = sizeof(remote); if (getpeername (sock, (struct sockaddr *)&remote, &addrlen) < 0 - || addrlen != sizeof(remote)) + || addrlen > sizeof(remote)) err (1, "getpeername(%s)", hostname); status = krb5_init_context(&context); @@ -74,13 +74,12 @@ proto (int sock, const char *hostname, const char *service) if (status) krb5_err(context, 1, status, "krb5_auth_con_init"); - local_addr.addr_type = AF_INET; - local_addr.address.length = sizeof(local.sin_addr); - local_addr.address.data = &local.sin_addr; - - remote_addr.addr_type = AF_INET; - remote_addr.address.length = sizeof(remote.sin_addr); - remote_addr.address.data = &remote.sin_addr; + status = krb5_sockaddr2address (context, (struct sockaddr *)&local, &local_addr); + if (status) + krb5_err(context, 1, status, "krb5_sockaddr2address(local)"); + status = krb5_sockaddr2address (context, (struct sockaddr *)&remote, &remote_addr); + if (status) + krb5_err(context, 1, status, "krb5_sockaddr2address(remote)"); status = krb5_auth_con_setaddrs (context, auth_context, diff --git a/appl/test/uu_server.c b/appl/test/uu_server.c index 85a893504..6e046990b 100644 --- a/appl/test/uu_server.c +++ b/appl/test/uu_server.c @@ -39,7 +39,7 @@ krb5_context context; static int proto (int sock, const char *service) { - struct sockaddr_in remote, local; + struct sockaddr_storage remote, local; socklen_t addrlen; krb5_address remote_addr, local_addr; krb5_ccache ccache; @@ -52,34 +52,31 @@ proto (int sock, const char *service) addrlen = sizeof(local); if (getsockname (sock, (struct sockaddr *)&local, &addrlen) < 0 - || addrlen != sizeof(local)) + || addrlen > sizeof(local)) err (1, "getsockname)"); addrlen = sizeof(remote); if (getpeername (sock, (struct sockaddr *)&remote, &addrlen) < 0 - || addrlen != sizeof(remote)) + || addrlen > sizeof(remote)) err (1, "getpeername"); status = krb5_auth_con_init (context, &auth_context); if (status) - errx (1, "krb5_auth_con_init: %s", - krb5_get_err_text(context, status)); + krb5_err(context, 1, status, "krb5_auth_con_init"); - local_addr.addr_type = AF_INET; - local_addr.address.length = sizeof(local.sin_addr); - local_addr.address.data = &local.sin_addr; - - remote_addr.addr_type = AF_INET; - remote_addr.address.length = sizeof(remote.sin_addr); - remote_addr.address.data = &remote.sin_addr; + status = krb5_sockaddr2address (context, (struct sockaddr *)&local, &local_addr); + if (status) + krb5_err(context, 1, status, "krb5_sockaddr2address(local)"); + status = krb5_sockaddr2address (context, (struct sockaddr *)&remote, &remote_addr); + if (status) + krb5_err(context, 1, status, "krb5_sockaddr2address(remote)"); status = krb5_auth_con_setaddrs (context, auth_context, &local_addr, &remote_addr); if (status) - errx (1, "krb5_auth_con_setaddr: %s", - krb5_get_err_text(context, status)); + krb5_err(context, 1, status, "krb5_auth_con_setaddr"); status = krb5_read_message(context, &sock, &client_name); if(status) @@ -105,6 +102,8 @@ proto (int sock, const char *service) &in_creds, &out_creds); if(status) krb5_err(context, 1, status, "krb5_get_credentials"); + krb5_cc_close(context, ccache); + ccache = NULL; status = krb5_cc_default(context, &ccache); if(status) @@ -123,7 +122,9 @@ proto (int sock, const char *service) NULL, NULL, NULL); - + krb5_cc_close(context, ccache); + ccache = NULL; + if (status) krb5_err(context, 1, status, "krb5_sendauth"); @@ -137,6 +138,9 @@ proto (int sock, const char *service) free(str); } + krb5_free_principal(context, in_creds.client); + krb5_free_principal(context, in_creds.server); + krb5_data_zero (&data); krb5_data_zero (&packet); @@ -150,8 +154,7 @@ proto (int sock, const char *service) &data, NULL); if (status) - errx (1, "krb5_rd_safe: %s", - krb5_get_err_text(context, status)); + krb5_err(context, 1, status, "krb5_rd_safe"); printf ("safe packet: %.*s\n", (int)data.length, (char *)data.data); @@ -166,8 +169,7 @@ proto (int sock, const char *service) &data, NULL); if (status) - errx (1, "krb5_rd_priv: %s", - krb5_get_err_text(context, status)); + krb5_err(context, 1, status, "krb5_rd_priv"); printf ("priv packet: %.*s\n", (int)data.length, (char *)data.data); @@ -178,34 +180,11 @@ proto (int sock, const char *service) static int doit (int port, const char *service) { - int sock, sock2; - struct sockaddr_in my_addr; - int one = 1; + rk_socket_t sock; - sock = socket (AF_INET, SOCK_STREAM, 0); - if (sock < 0) - err (1, "socket"); + mini_inetd(port, &sock); - memset (&my_addr, 0, sizeof(my_addr)); - my_addr.sin_family = AF_INET; - my_addr.sin_port = port; - my_addr.sin_addr.s_addr = INADDR_ANY; - - if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, - (void *)&one, sizeof(one)) < 0) - warn ("setsockopt SO_REUSEADDR"); - - if (bind (sock, (struct sockaddr *)&my_addr, sizeof(my_addr)) < 0) - err (1, "bind"); - - if (listen (sock, 1) < 0) - err (1, "listen"); - - sock2 = accept (sock, NULL, NULL); - if (sock2 < 0) - err (1, "accept"); - - return proto (sock2, service); + return proto(sock, service); } int diff --git a/appl/xnlock/ChangeLog b/appl/xnlock/ChangeLog deleted file mode 100644 index c1188ef08..000000000 --- a/appl/xnlock/ChangeLog +++ /dev/null @@ -1,159 +0,0 @@ -2007-07-28 Love Hörnquist Åstrand - - * xnlock.c: Add --help. - -2006-10-21 Love Hörnquist Åstrand - - * xnlock.c: Don't include , its x11's "roken.h" and we - do that just fine ourself thanks. - -2006-05-13 Love Hörnquist Åstrand - - * xnlock.c (main): argc_in_out argument to XtVaAppInitialize - should be an 'int *' accoring to manpage and headerfile, so remove - the cast added in 1996 - (rev 1.54) - -2005-10-22 Love Hörnquist Åstrand - - * xnlock.c: Check return value from asprintf instead of string != - NULL since it undefined behavior on Linux. From Björn Sandell - -2005-04-06 Love Hörnquist Åstrand - - * xnlock.c: use NULL as last argument to execl, not 0 - -2005-01-09 Love Hörnquist Åstrand - - * xnlock.c: get_v4_tgt only used when compileing with kerberos 4 - support - -2004-09-08 Johan Danielsson - - * xnlock.c: use krb5_appdefault_boolean instead of - krb5_config_get_bool - -2004-03-22 Johan Danielsson - - * xnlock.c: protect the world from des_encrypt in crypt.h - -2004-03-01 Love Hörnquist Åstrand - - * xnlock.c: include , From: Fredrik Ljungberg - - -2003-09-30 Love Hörnquist Åstrand - - * xnlock.c (verify_krb5): set mcred.client too - -2003-08-25 Johan Danielsson - - * Makefile.am: fix automake conditional foo - -2003-08-16 Love Hörnquist Åstrand - - * Makefile.am: Don't do local checks on xnlock, it only passes if - there is a working X11 socket, XXX should really be fixed in - xnlock - -2003-07-07 Love Hörnquist Åstrand - - * xnlock.c (verify_krb5): use krb5_cc_clear_mcred - -2003-05-06 Johan Danielsson - - * no checks here - -2003-04-29 Love Hörnquist Åstrand - - * xnlock.c: include kafs.h in the krb5 case - -2003-04-14 Love Hörnquist Åstrand - - * xnlock.c (GetPasswd): cast argument to isprint to unsigned char, - From Christian Biere via NetBSD - -2003-03-18 Love Hörnquist Åstrand - - * xnlock.c: do krb5_afslog when compling with afs support - -2003-02-10 Assar Westerlund - - * xnlock.c (verify): move ret to where it's used - -2002-08-23 Assar Westerlund - - * xnlock.c: add --version as a special case - -2001-06-24 Assar Westerlund - - * xnlock.c (verify_krb5): remove unused variable - -2001-03-15 Johan Danielsson - - * xnlock.c: don't explicitly set the krb4 ticket file - -2000-12-31 Assar Westerlund - - * xnlock.c (main): handle krb5_init_context failure consistently - -2000-07-17 Johan Danielsson - - * Makefile.am: use conditional for X - -2000-04-09 Assar Westerlund - - * xnlock.c (verfiy_krb5): get the v4-realm from the v5-ticket and - not from the default one. - * xnlock.c (verify_krb5): add obtainting of v4 tickets. - -1999-11-17 Assar Westerlund - - * Makefile.am: only build when we have X11. From: Simon Josefsson - - -Thu Mar 18 11:21:44 1999 Johan Danielsson - - * Makefile.am: include Makefile.am.common - -Wed Mar 17 23:35:51 1999 Assar Westerlund - - * xnlock.c (verify): use KRB_VERIFY_SECURE instead of 1 - -Tue Mar 16 22:29:14 1999 Assar Westerlund - - * xnlock.c: krb_verify_user_multiple -> krb_verify_user - -Thu Mar 11 14:59:20 1999 Johan Danielsson - - * xnlock.c: add some if-braces to keep gcc happy - -Sun Nov 22 10:36:45 1998 Assar Westerlund - - * Makefile.in (WFLAGS): set - -Wed Jul 8 01:37:37 1998 Assar Westerlund - - * xnlock.c (main): create place-holder ticket file with - open(O_EXCL | O_CREAT) instead of creat - -Sat Mar 28 12:53:46 1998 Assar Westerlund - - * Makefile.in (install, uninstall): transform the man page - -Tue Mar 24 05:20:34 1998 Assar Westerlund - - * xnlock.c: remove redundant preprocessor stuff - -Sat Mar 21 14:36:21 1998 Assar Westerlund - - * xnlock.c (init_words): recognize both `-p' and `-prog' - -Sat Feb 7 10:08:07 1998 Assar Westerlund - - * xnlock.c: Don't use REALM_SZ + 1, just REALM_SZ - -Sat Nov 29 04:58:19 1997 Johan Danielsson - - * xnlock.c: Make it build w/o krb4. - diff --git a/appl/xnlock/Makefile.am b/appl/xnlock/Makefile.am deleted file mode 100644 index f073d6810..000000000 --- a/appl/xnlock/Makefile.am +++ /dev/null @@ -1,31 +0,0 @@ -# $Id$ - -include $(top_srcdir)/Makefile.am.common - -AM_CPPFLAGS += $(X_CFLAGS) - -WFLAGS += $(WFLAGS_NOIMPLICITINT) - -if HAVE_X - -bin_PROGRAMS = xnlock - -else - -bin_PROGRAMS = - -endif - -CHECK_LOCAL = no-check-local - -man_MANS = xnlock.1 - -EXTRA_DIST = $(man_MANS) nose.0.left nose.0.right nose.1.left nose.1.right \ - nose.down nose.front nose.left.front nose.right.front - -LDADD = \ - $(LIB_kafs) \ - $(LIB_krb5) \ - $(LIB_hcrypto) \ - $(LIB_roken) \ - $(X_LIBS) -lXt $(X_PRE_LIBS) -lX11 $(X_EXTRA_LIBS) diff --git a/appl/xnlock/README b/appl/xnlock/README deleted file mode 100644 index 5b16c522f..000000000 --- a/appl/xnlock/README +++ /dev/null @@ -1,21 +0,0 @@ -xnlock -- Dan Heller, 1990 -"nlock" is a "new lockscreen" type program... something that prevents -screen burnout by making most of it "black" while providing something -of interest to be displayed in case anyone is watching. The program -also provides added security. - -"xnlock" is the X11 version of the program. - -Original sunview version written by Dan Heller 1985 (not included). - -For a real description of how this program works, read the -man page or just try running it. - -The one major outstanding bug with this program is that every -once in a while, two horizontal lines appear below the little -figure that runs around the screen. If someone can find and -fix this bug, *please* let me know -- I don't have time to -look and if I waited till I had time, you'd never see this -program... It has something to do with the "looking down" -position and then directly moving up and right or left... - diff --git a/appl/xnlock/nose.0.left b/appl/xnlock/nose.0.left deleted file mode 100644 index cb3d15286..000000000 --- a/appl/xnlock/nose.0.left +++ /dev/null @@ -1,38 +0,0 @@ -#define nose_0_left_width 64 -#define nose_0_left_height 64 -static unsigned char nose_0_left_bits[] = { - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x40,0x00, - 0x00,0x04,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x40, - 0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x04,0x00,0x00,0x00,0x00, - 0x40,0x00,0x00,0x04,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0x3f,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x20,0x00, - 0x00,0xf8,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0xf0,0x03,0x00,0x00,0x80,0x00, - 0x00,0x00,0x0e,0x0c,0x00,0x00,0x80,0x01,0x00,0x00,0x03,0x30,0x00,0x00,0x00, - 0x01,0x00,0x80,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x40,0x00,0xc0,0x00,0x00, - 0x00,0x02,0x00,0x20,0x00,0x80,0x00,0x00,0x00,0x04,0x00,0x10,0x00,0x00,0x00, - 0x00,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x08,0x00,0x00, - 0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x00, - 0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08, - 0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10, - 0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x01,0x00,0x00, - 0x18,0x00,0x20,0x00,0x00,0x01,0x00,0x00,0x08,0x00,0x40,0x00,0x80,0x00,0x00, - 0x00,0x08,0x00,0x80,0x00,0x40,0x00,0x00,0x00,0x0c,0x00,0x00,0x01,0x20,0x00, - 0x00,0x00,0x04,0x00,0x00,0x06,0x18,0x00,0x00,0x00,0x06,0x00,0x00,0xf8,0x07, - 0x00,0x00,0x00,0x02,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x0f,0x00,0x00,0x00, - 0x00,0xff,0x00,0x04,0x10,0x00,0x00,0x00,0xc0,0x00,0x03,0x03,0x10,0x00,0x00, - 0x00,0x30,0x00,0x0c,0x01,0x20,0x00,0x00,0x00,0x08,0x00,0x98,0x00,0x20,0x00, - 0x00,0x00,0x0c,0x03,0x60,0x00,0x20,0x00,0x00,0x00,0xc2,0x00,0xc0,0x00,0x20, - 0x00,0x00,0x00,0x42,0x00,0x80,0x00,0x20,0x00,0x00,0x00,0x21,0x00,0x00,0x01, - 0x20,0x00,0x00,0x00,0x21,0x00,0x00,0x01,0x20,0x00,0x00,0x00,0x21,0x00,0x00, - 0x00,0x20,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x01,0x00, - 0x00,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x02, - 0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x20,0x00,0x00,0x00, - 0x18,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x10,0x00,0x00, - 0x00,0xc0,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00}; diff --git a/appl/xnlock/nose.0.right b/appl/xnlock/nose.0.right deleted file mode 100644 index f387baa73..000000000 --- a/appl/xnlock/nose.0.right +++ /dev/null @@ -1,38 +0,0 @@ -#define nose_0_right_width 64 -#define nose_0_right_height 64 -static unsigned char nose_0_right_bits[] = { - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x20,0x00, - 0x00,0x02,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x20, - 0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x00, - 0x20,0x00,0x00,0x02,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0x1f,0x00,0x00, - 0x04,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x10,0x00, - 0x00,0xfc,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x01,0x00,0x00,0xc0,0x0f, - 0x00,0x00,0x80,0x01,0x00,0x00,0x30,0x70,0x00,0x00,0x80,0x00,0x00,0x00,0x0c, - 0xc0,0x00,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x01,0x00,0x40,0x00,0x00,0x00, - 0x03,0x00,0x02,0x00,0x20,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0x20,0x00,0x00, - 0x00,0x00,0x00,0x08,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x10,0x00, - 0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08, - 0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10, - 0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00, - 0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x18,0x00,0x00,0x80,0x00, - 0x00,0x08,0x00,0x10,0x00,0x00,0x80,0x00,0x00,0x04,0x00,0x10,0x00,0x00,0x00, - 0x01,0x00,0x02,0x00,0x30,0x00,0x00,0x00,0x02,0x00,0x01,0x00,0x20,0x00,0x00, - 0x00,0x04,0x80,0x00,0x00,0x60,0x00,0x00,0x00,0x18,0x60,0x00,0x00,0x40,0x00, - 0x00,0x00,0xe0,0x1f,0x00,0x00,0x80,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x1f,0x00,0x00,0x00,0x00,0x00, - 0x00,0x08,0x20,0x00,0xff,0x00,0x00,0x00,0x00,0x08,0xc0,0xc0,0x00,0x03,0x00, - 0x00,0x00,0x04,0x80,0x30,0x00,0x0c,0x00,0x00,0x00,0x04,0x00,0x19,0x00,0x10, - 0x00,0x00,0x00,0x04,0x00,0x06,0xc0,0x30,0x00,0x00,0x00,0x04,0x00,0x03,0x00, - 0x43,0x00,0x00,0x00,0x04,0x00,0x01,0x00,0x42,0x00,0x00,0x00,0x04,0x80,0x00, - 0x00,0x84,0x00,0x00,0x00,0x04,0x80,0x00,0x00,0x84,0x00,0x00,0x00,0x04,0x00, - 0x00,0x00,0x84,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x02, - 0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x40,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x20,0x00,0x00, - 0x00,0x04,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x0e,0x00, - 0x00,0x00,0xf0,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00}; diff --git a/appl/xnlock/nose.1.left b/appl/xnlock/nose.1.left deleted file mode 100644 index 8a6b82952..000000000 --- a/appl/xnlock/nose.1.left +++ /dev/null @@ -1,38 +0,0 @@ -#define nose_1_left_width 64 -#define nose_1_left_height 64 -static unsigned char nose_1_left_bits[] = { - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x40,0x00, - 0x00,0x04,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x40, - 0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x04,0x00,0x00,0x00,0x00, - 0x40,0x00,0x00,0x04,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0x3f,0x00,0x00, - 0x08,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x20,0x00, - 0x00,0xf8,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0xf0,0x03,0x00,0x00,0x80,0x00, - 0x00,0x00,0x0e,0x0c,0x00,0x00,0x80,0x01,0x00,0x00,0x03,0x30,0x00,0x00,0x00, - 0x01,0x00,0x80,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x40,0x00,0xc0,0x00,0x00, - 0x00,0x02,0x00,0x20,0x00,0x80,0x00,0x00,0x00,0x04,0x00,0x10,0x00,0x00,0x00, - 0x00,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x08,0x00,0x00, - 0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x00, - 0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08, - 0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10, - 0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x01,0x00,0x00, - 0x18,0x00,0x10,0x00,0x00,0x01,0x00,0x00,0x08,0x00,0x20,0x00,0x80,0x00,0x00, - 0x00,0x08,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x0c,0x00,0x80,0x00,0x20,0x00, - 0x00,0x00,0xe4,0x00,0x00,0x03,0x18,0x00,0x00,0x00,0x26,0x03,0x00,0xfc,0x07, - 0x00,0x00,0x00,0x12,0x0c,0x00,0x00,0xf8,0xff,0xff,0xff,0x11,0x10,0x80,0x1f, - 0x00,0x00,0x00,0x00,0x08,0x20,0x60,0x60,0xc0,0x07,0x00,0x00,0x04,0x40,0x10, - 0xc0,0x20,0x08,0x00,0x1f,0x02,0x40,0x08,0x00,0x21,0x10,0xc0,0x60,0x02,0x40, - 0x04,0x00,0x12,0x20,0x20,0x80,0x02,0x20,0xc2,0x00,0x14,0x40,0x18,0x00,0x03, - 0x20,0x22,0x00,0x0c,0x80,0x04,0x03,0x02,0x10,0x12,0x00,0x08,0x80,0x86,0x00, - 0x04,0x10,0x12,0x00,0x10,0x80,0x42,0x00,0x18,0x08,0x12,0x00,0x10,0x40,0x42, - 0x00,0x00,0x04,0x02,0x00,0x20,0x40,0x42,0x00,0x00,0x04,0x02,0x00,0x00,0x20, - 0x42,0x00,0x00,0x02,0x04,0x00,0x00,0x20,0x02,0x00,0x00,0x01,0x04,0x00,0x00, - 0x20,0x02,0x00,0x00,0x01,0x08,0x00,0x00,0x20,0x04,0x00,0x80,0x00,0x10,0x00, - 0x00,0x20,0x0c,0x00,0x80,0x00,0x60,0x00,0x00,0x10,0x08,0x00,0x40,0x00,0x80, - 0xff,0xff,0x0f,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0x0f,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00}; diff --git a/appl/xnlock/nose.1.right b/appl/xnlock/nose.1.right deleted file mode 100644 index f7c8962c0..000000000 --- a/appl/xnlock/nose.1.right +++ /dev/null @@ -1,38 +0,0 @@ -#define nose_1_right_width 64 -#define nose_1_right_height 64 -static unsigned char nose_1_right_bits[] = { - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x20,0x00, - 0x00,0x02,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x20, - 0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x00, - 0x20,0x00,0x00,0x02,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0x1f,0x00,0x00, - 0x04,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x10,0x00, - 0x00,0xfc,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x01,0x00,0x00,0xc0,0x0f, - 0x00,0x00,0x80,0x01,0x00,0x00,0x30,0x70,0x00,0x00,0x80,0x00,0x00,0x00,0x0c, - 0xc0,0x00,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x01,0x00,0x40,0x00,0x00,0x00, - 0x03,0x00,0x02,0x00,0x20,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0x20,0x00,0x00, - 0x00,0x00,0x00,0x08,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x10,0x00, - 0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08, - 0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00, - 0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10, - 0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00, - 0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x18,0x00,0x00,0x80,0x00, - 0x00,0x08,0x00,0x10,0x00,0x00,0x80,0x00,0x00,0x08,0x00,0x10,0x00,0x00,0x00, - 0x01,0x00,0x04,0x00,0x30,0x00,0x00,0x00,0x02,0x00,0x02,0x00,0x27,0x00,0x00, - 0x00,0x04,0x00,0x01,0xc0,0x64,0x00,0x00,0x00,0x18,0xc0,0x00,0x30,0x48,0x00, - 0x00,0x00,0xe0,0x3f,0x00,0x08,0x88,0xff,0xff,0xff,0x1f,0x00,0x00,0x04,0x10, - 0x00,0x00,0x00,0x00,0xf8,0x01,0x02,0x20,0x00,0x00,0xe0,0x03,0x06,0x06,0x02, - 0x40,0xf8,0x00,0x10,0x04,0x03,0x08,0x02,0x40,0x06,0x03,0x08,0x84,0x00,0x10, - 0x04,0x40,0x01,0x04,0x04,0x48,0x00,0x20,0x04,0xc0,0x00,0x18,0x02,0x28,0x00, - 0x43,0x08,0x40,0xc0,0x20,0x01,0x30,0x00,0x44,0x08,0x20,0x00,0x61,0x01,0x10, - 0x00,0x48,0x10,0x18,0x00,0x42,0x01,0x08,0x00,0x48,0x20,0x00,0x00,0x42,0x02, - 0x08,0x00,0x48,0x20,0x00,0x00,0x42,0x02,0x04,0x00,0x40,0x40,0x00,0x00,0x42, - 0x04,0x00,0x00,0x40,0x80,0x00,0x00,0x40,0x04,0x00,0x00,0x20,0x80,0x00,0x00, - 0x40,0x04,0x00,0x00,0x20,0x00,0x01,0x00,0x20,0x04,0x00,0x00,0x10,0x00,0x01, - 0x00,0x30,0x04,0x00,0x00,0x08,0x00,0x02,0x00,0x10,0x08,0x00,0x00,0x06,0x00, - 0x0c,0x00,0x0c,0xf0,0xff,0xff,0x01,0x00,0xf0,0xff,0x03,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00}; diff --git a/appl/xnlock/nose.down b/appl/xnlock/nose.down deleted file mode 100644 index e8bdba4f4..000000000 --- a/appl/xnlock/nose.down +++ /dev/null @@ -1,38 +0,0 @@ -#define nose_down_width 64 -#define nose_down_height 64 -static unsigned char nose_down_bits[] = { - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0xfc,0xff,0x01,0x00,0x00,0x00,0x00,0xc0,0x03,0x00,0x1e,0x00, - 0x00,0x00,0x00,0x38,0x00,0x00,0xe0,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00, - 0x03,0x00,0x00,0x80,0x01,0x00,0x00,0x00,0x04,0x00,0x00,0x40,0x00,0x00,0x00, - 0x00,0x08,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x10,0x00,0x80, - 0x1f,0x00,0x40,0x00,0x00,0x08,0x00,0x60,0x60,0x00,0x80,0x00,0x00,0x08,0x00, - 0x10,0x80,0x00,0x80,0x00,0x00,0x04,0x00,0x08,0x00,0x01,0x00,0x01,0x00,0x04, - 0x00,0x08,0x00,0x01,0x00,0x01,0x00,0x02,0x00,0x18,0x80,0x01,0x00,0x02,0x00, - 0x02,0x00,0x68,0x60,0x01,0x00,0x02,0x00,0x02,0x00,0x88,0x1f,0x01,0x00,0x02, - 0x00,0x02,0x00,0x08,0x00,0x01,0x00,0x02,0x00,0x02,0x00,0x10,0x80,0x00,0x00, - 0x03,0x00,0x06,0x00,0x60,0x60,0x00,0x80,0x02,0x00,0x0c,0x00,0x80,0x1f,0x00, - 0x40,0x01,0x00,0x14,0x00,0x00,0x00,0x00,0x20,0x01,0x00,0x28,0x00,0x00,0x00, - 0x00,0x90,0x00,0x00,0x50,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0xa0,0x01,0x00, - 0x00,0x00,0x26,0x00,0x00,0x40,0x1e,0x00,0x00,0xc0,0x11,0x00,0x00,0x80,0xe1, - 0x03,0x00,0x3c,0x0c,0x00,0x00,0x00,0x0e,0xfc,0xff,0x83,0x03,0x00,0x00,0x00, - 0xf0,0x01,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0x0f,0x00,0x00,0x00, - 0x00,0x80,0x03,0x00,0x0c,0x00,0x00,0x00,0x00,0x80,0x02,0x00,0x14,0x00,0x00, - 0x00,0x00,0x60,0x04,0x00,0x12,0x00,0x00,0xc0,0x7f,0x10,0x04,0x00,0x22,0xe0, - 0x01,0x70,0xc0,0x18,0x08,0x00,0x61,0x1c,0x06,0x10,0x00,0x0f,0x30,0xc0,0x80, - 0x07,0x08,0x08,0x00,0x06,0xc0,0x3f,0x80,0x01,0x08,0x08,0x00,0x18,0x00,0x02, - 0xc0,0x00,0x10,0x04,0x00,0x30,0x00,0x05,0x30,0x00,0x10,0x04,0x00,0x00,0x80, - 0x08,0x18,0x00,0x20,0x04,0x00,0x00,0x80,0x08,0x00,0x00,0x20,0x04,0x00,0x00, - 0x40,0x10,0x00,0x00,0x20,0x24,0x00,0x00,0x40,0x10,0x00,0x00,0x22,0x24,0x00, - 0x00,0x40,0x10,0x00,0x00,0x22,0x44,0x00,0x00,0x40,0x10,0x00,0x00,0x11,0x84, - 0x01,0x00,0xc0,0x18,0x00,0xc0,0x10,0x08,0x00,0x00,0x80,0x08,0x00,0x00,0x08, - 0x30,0x00,0x00,0x80,0x08,0x00,0x00,0x04,0xe0,0xff,0xff,0xff,0xf8,0xff,0xff, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00}; diff --git a/appl/xnlock/nose.front b/appl/xnlock/nose.front deleted file mode 100644 index 64b82015c..000000000 --- a/appl/xnlock/nose.front +++ /dev/null @@ -1,38 +0,0 @@ -#define nose_front_width 64 -#define nose_front_height 64 -static unsigned char nose_front_bits[] = { - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x40,0x00, - 0x00,0x04,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x40, - 0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x04,0x00,0x00,0x00,0x00, - 0x40,0x00,0x00,0x04,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0x3f,0x00,0x00, - 0x08,0x00,0xc0,0x1f,0x00,0x20,0x00,0x00,0x08,0x00,0x30,0x60,0x00,0x20,0x00, - 0x00,0xf8,0xff,0x0f,0x80,0xff,0x3f,0x00,0x00,0x00,0x02,0x02,0x00,0x82,0x00, - 0x00,0x00,0x00,0x03,0x01,0x00,0x84,0x01,0x00,0x00,0x00,0x81,0x00,0x00,0x08, - 0x01,0x00,0x00,0x80,0x80,0x00,0x00,0x08,0x02,0x00,0x00,0x80,0x40,0x00,0x00, - 0x10,0x02,0x00,0x00,0x40,0x40,0x00,0x00,0x10,0x04,0x00,0x00,0x40,0x20,0x00, - 0x00,0x20,0x04,0x00,0x00,0x60,0x20,0x00,0x00,0x20,0x0c,0x00,0x00,0x20,0x20, - 0x00,0x00,0x20,0x08,0x00,0x00,0x20,0x20,0x00,0x00,0x20,0x08,0x00,0x00,0x10, - 0x20,0x00,0x00,0x20,0x10,0x00,0x00,0x10,0x20,0x00,0x00,0x20,0x10,0x00,0x00, - 0x10,0x20,0x00,0x00,0x20,0x10,0x00,0x00,0x10,0x40,0x00,0x00,0x10,0x10,0x00, - 0x00,0x10,0x40,0x00,0x00,0x10,0x10,0x00,0x00,0x10,0x80,0x00,0x00,0x08,0x10, - 0x00,0x00,0x10,0x80,0x00,0x00,0x08,0x10,0x00,0x00,0x30,0x00,0x01,0x00,0x04, - 0x18,0x00,0x00,0x20,0x00,0x02,0x00,0x02,0x08,0x00,0x00,0x20,0x00,0x0c,0x80, - 0x01,0x08,0x00,0x00,0x60,0x00,0x30,0x60,0x00,0x0c,0x00,0x00,0x40,0x00,0xc0, - 0x1f,0x00,0x04,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x01, - 0x00,0x00,0x00,0x02,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x0f,0xc0,0x0f,0x00,0x00,0x00, - 0x00,0x40,0x10,0x20,0x10,0x00,0x00,0x00,0x00,0x20,0x60,0x30,0x20,0x00,0x00, - 0x00,0x00,0x20,0xc0,0x18,0x20,0x00,0x00,0xc0,0x7f,0x10,0x80,0x0d,0x40,0xe0, - 0x01,0x70,0xc0,0x18,0x00,0x05,0x40,0x1c,0x06,0x10,0x00,0x0f,0x00,0x05,0x80, - 0x07,0x08,0x08,0x00,0x06,0x00,0x05,0x80,0x01,0x08,0x08,0x00,0x18,0x00,0x05, - 0xc0,0x00,0x10,0x04,0x00,0x30,0x00,0x05,0x30,0x00,0x10,0x04,0x00,0x00,0x80, - 0x08,0x18,0x00,0x20,0x04,0x00,0x00,0x80,0x08,0x00,0x00,0x20,0x04,0x00,0x00, - 0x40,0x10,0x00,0x00,0x20,0x24,0x00,0x00,0x40,0x10,0x00,0x00,0x22,0x24,0x00, - 0x00,0x40,0x10,0x00,0x00,0x22,0x44,0x00,0x00,0x40,0x10,0x00,0x00,0x11,0x84, - 0x01,0x00,0xc0,0x18,0x00,0xc0,0x10,0x08,0x00,0x00,0x80,0x08,0x00,0x00,0x08, - 0x30,0x00,0x00,0x80,0x08,0x00,0x00,0x04,0xe0,0xff,0xff,0xff,0xf8,0xff,0xff, - 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00}; diff --git a/appl/xnlock/nose.left.front b/appl/xnlock/nose.left.front deleted file mode 100644 index 3a871eaaa..000000000 --- a/appl/xnlock/nose.left.front +++ /dev/null @@ -1,38 +0,0 @@ -#define nose_left_front_width 64 -#define nose_left_front_height 64 -static unsigned char nose_left_front_bits[] = { - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x40,0x00, - 0x00,0x04,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x40, - 0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x04,0x00,0x00,0x00,0x00, - 0x40,0x00,0x00,0x04,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0x3f,0x00,0x00, - 0x08,0x00,0xe0,0x0f,0x00,0x20,0x00,0x00,0x08,0x00,0x18,0x30,0x00,0x20,0x00, - 0x00,0xf8,0xff,0x07,0xc0,0xff,0x3f,0x00,0x00,0x00,0x02,0x01,0x00,0x81,0x00, - 0x00,0x00,0x00,0x83,0x00,0x00,0x82,0x01,0x00,0x00,0x00,0x41,0x00,0x00,0x04, - 0x01,0x00,0x00,0x80,0x40,0x00,0x00,0x04,0x02,0x00,0x00,0x80,0x20,0x00,0x00, - 0x08,0x02,0x00,0x00,0x40,0x20,0x00,0x00,0x08,0x04,0x00,0x00,0x40,0x10,0x00, - 0x00,0x10,0x04,0x00,0x00,0x60,0x10,0x00,0x00,0x10,0x0c,0x00,0x00,0x20,0x10, - 0x00,0x00,0x10,0x08,0x00,0x00,0x30,0x10,0x00,0x00,0x10,0x08,0x00,0x00,0x10, - 0x10,0x00,0x00,0x10,0x10,0x00,0x00,0x10,0x10,0x00,0x00,0x10,0x10,0x00,0x00, - 0x10,0x10,0x00,0x00,0x10,0x10,0x00,0x00,0x10,0x20,0x00,0x00,0x08,0x10,0x00, - 0x00,0x10,0x20,0x00,0x00,0x08,0x10,0x00,0x00,0x10,0x40,0x00,0x00,0x04,0x10, - 0x00,0x00,0x30,0x40,0x00,0x00,0x04,0x10,0x00,0x00,0x20,0x80,0x00,0x00,0x02, - 0x18,0x00,0x00,0x20,0x00,0x01,0x00,0x01,0x08,0x00,0x00,0x60,0x00,0x06,0xc0, - 0x00,0x08,0x00,0x00,0x80,0x00,0x18,0x30,0x00,0x0c,0x00,0x00,0x80,0x00,0xe0, - 0x0f,0x00,0x04,0x00,0x00,0x80,0x01,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x01, - 0x00,0x00,0x00,0x02,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x0f,0x00,0x00,0x00, - 0x00,0xff,0x00,0x04,0x10,0x00,0x00,0x00,0xe0,0x00,0x07,0x02,0x10,0x00,0x00, - 0x00,0x30,0x00,0x8c,0x01,0x20,0x00,0x00,0x00,0x0c,0x00,0x90,0x00,0x20,0x00, - 0x00,0x00,0x04,0x03,0x60,0x00,0x20,0x00,0x00,0x00,0xc2,0x00,0xc0,0x00,0x20, - 0x00,0x00,0x00,0x42,0x00,0x00,0x01,0x20,0x00,0x00,0x00,0x21,0x00,0x00,0x02, - 0x20,0x00,0x00,0x00,0x21,0x00,0x00,0x06,0x20,0x00,0x00,0x00,0x21,0x00,0x00, - 0x00,0x20,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x03,0x00, - 0x00,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x02, - 0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x20,0x00,0x00,0x00, - 0x18,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x10,0x00,0x00, - 0x00,0xc0,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00}; diff --git a/appl/xnlock/nose.right.front b/appl/xnlock/nose.right.front deleted file mode 100644 index f8214174e..000000000 --- a/appl/xnlock/nose.right.front +++ /dev/null @@ -1,38 +0,0 @@ -#define nose_right_front_width 64 -#define nose_right_front_height 64 -static unsigned char nose_right_front_bits[] = { - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x20,0x00, - 0x00,0x02,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x20, - 0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x00, - 0x20,0x00,0x00,0x02,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0x1f,0x00,0x00, - 0x04,0x00,0xf0,0x07,0x00,0x10,0x00,0x00,0x04,0x00,0x0c,0x18,0x00,0x10,0x00, - 0x00,0xfc,0xff,0x03,0xe0,0xff,0x1f,0x00,0x00,0x00,0x81,0x00,0x80,0x40,0x00, - 0x00,0x00,0x80,0x41,0x00,0x00,0xc1,0x00,0x00,0x00,0x80,0x20,0x00,0x00,0x82, - 0x00,0x00,0x00,0x40,0x20,0x00,0x00,0x02,0x01,0x00,0x00,0x40,0x10,0x00,0x00, - 0x04,0x01,0x00,0x00,0x20,0x10,0x00,0x00,0x04,0x02,0x00,0x00,0x20,0x08,0x00, - 0x00,0x08,0x02,0x00,0x00,0x30,0x08,0x00,0x00,0x08,0x06,0x00,0x00,0x10,0x08, - 0x00,0x00,0x08,0x04,0x00,0x00,0x10,0x08,0x00,0x00,0x08,0x0c,0x00,0x00,0x08, - 0x08,0x00,0x00,0x08,0x08,0x00,0x00,0x08,0x08,0x00,0x00,0x08,0x08,0x00,0x00, - 0x08,0x08,0x00,0x00,0x08,0x08,0x00,0x00,0x08,0x10,0x00,0x00,0x04,0x08,0x00, - 0x00,0x08,0x10,0x00,0x00,0x04,0x08,0x00,0x00,0x08,0x20,0x00,0x00,0x02,0x08, - 0x00,0x00,0x08,0x20,0x00,0x00,0x02,0x0c,0x00,0x00,0x18,0x40,0x00,0x00,0x01, - 0x04,0x00,0x00,0x10,0x80,0x00,0x80,0x00,0x04,0x00,0x00,0x10,0x00,0x03,0x60, - 0x00,0x06,0x00,0x00,0x30,0x00,0x0c,0x18,0x00,0x01,0x00,0x00,0x20,0x00,0xf0, - 0x07,0x00,0x01,0x00,0x00,0x60,0x00,0x00,0x00,0x80,0x01,0x00,0x00,0x40,0x00, - 0x00,0x00,0x80,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x1f,0x00,0x00,0x00,0x00,0x00, - 0x00,0x08,0x20,0x00,0xff,0x00,0x00,0x00,0x00,0x08,0x40,0xe0,0x00,0x07,0x00, - 0x00,0x00,0x04,0x80,0x31,0x00,0x0c,0x00,0x00,0x00,0x04,0x00,0x09,0x00,0x30, - 0x00,0x00,0x00,0x04,0x00,0x06,0xc0,0x20,0x00,0x00,0x00,0x04,0x00,0x03,0x00, - 0x43,0x00,0x00,0x00,0x04,0x80,0x00,0x00,0x42,0x00,0x00,0x00,0x04,0x40,0x00, - 0x00,0x84,0x00,0x00,0x00,0x04,0x60,0x00,0x00,0x84,0x00,0x00,0x00,0x04,0x00, - 0x00,0x00,0x84,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x02, - 0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x40,0x00,0x00,0x00, - 0x02,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x20,0x00,0x00, - 0x00,0x04,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x0e,0x00, - 0x00,0x00,0xf0,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00}; diff --git a/appl/xnlock/xnlock.1 b/appl/xnlock/xnlock.1 deleted file mode 100644 index 1adc9b577..000000000 --- a/appl/xnlock/xnlock.1 +++ /dev/null @@ -1,123 +0,0 @@ -.\" xnlock -- Dan Heller 1985 -.TH XNLOCK 1 "19 April 1990" -.SH NAME -xnlock \- amusing lock screen program with message for passers-by -.SH SYNOPSIS -.B xnlock -[ -\fIoptions\fP -] -[ -\fImessage\fP -] -.SH DESCRIPTION -.I xnlock -is a program that acts as a screen saver for workstations running X11. -It also "locks" the screen such that the workstation can be left -unattended without worry that someone else will walk up to it and -mess everything up. When \fIxnlock\fP is running, a little man with -a big nose and a hat runs around spewing out messages to the screen. -By default, the messages are "humorous", but that depends on your -sense of humor. -.LP -If a key or mouse button is pressed, a prompt is printed requesting the -user's password. If a RETURN is not typed within 30 seconds, -the little man resumes running around. -.LP -Text on the command line is used as the message. For example: -.br - % xnlock I\'m out to lunch for a couple of hours. -.br -Note the need to quote shell metacharacters. -.LP -In the absence of flags or text, \fIxnlock\fP displays random fortunes. -.SH OPTIONS -Command line options override all resource specifications. -All arguments that are not associated with a command line option -is taken to be message text that the little man will "say" every -once in a while. The resource \fBxnlock.text\fP may be set to -a string. -.TP -.BI \-fn " fontname" -The default font is the first 18 point font in the \fInew century schoolbook\fP -family. While larger fonts are recokmmended over smaller ones, any font -in the server's font list will work. The resource to use for this option -is \fBxnlock.font\fP. -.TP -.BI \-filename " filename" -Take the message to be displayed from the file \fIfilename\fP. -If \fIfilename\fP is not specified, \fI$HOME/.msgfile\fP is used. -If the contents of the file are changed during runtime, the most recent text -of the file is used (allowing the displayed message to be altered remotely). -Carriage returns within the text are allowed, but tabs or other control -characters are not translated and should not be used. -The resource available for this option is \fBxnlock.file\fP. -.TP -.BI \-ar -Accept root's password to unlock screen. This option is true by -default. The reason for this is so that someone's screen may be -unlocked by autorized users in case of emergency and the person -running the program is still out to lunch. The resource available -for specifying this option is \fBxnlock.acceptRootPasswd\fP. -.TP -.BI \-noar -Don't accept root's password. This option is for paranoids who -fear their peers might breakin using root's password and remove -their files anyway. Specifying this option on the command line -overrides the \fBxnlock.acceptRootPasswd\fP if set to True. -.TP -.BI \-ip -Ignore password prompt. -The resource available for this option is \fBxnlock.ignorePasswd\fP. -.TP -.BI \-noip -Don't ignore password prompt. This is available in order to -override the resource \fBignorePasswd\fP if set to True. -.TP -.BI -fg " color" -Specifies the foreground color. The resource available for this -is \fBxnlock.foreground\fP. -.TP -.BI -bg " color" -Specifies the background color. The resource available for this -is \fBxnlock.background\fP. -.TP -.BI \-rv -Reverse the foreground and background colors. -The resource for this is \fBxvnlock.reverseVideo\fP. -.TP -.BI \-norv -Don't use reverse video. This is available to override the reverseVideo -resource if set to True. -.TP -.BI \-prog " program" -Receive message text from the running program \fIprogram\fP. If there -are arguments to \fIprogram\fP, encase them with the name of the program in -quotes (e.g. xnlock -t "fortune -o"). -The resource for this is \fBxnlock.program\fP. -.SH RESOURCES -.br -xnlock.font: fontname -.br -xnlock.foreground: color -.br -xnlock.background: color -.br -xnlock.reverseVideo: True/False -.br -xnlock.text: Some random text string -.br -xnlock.program: program [args] -.br -xnlock.ignorePasswd: True/False -.br -xnlock.acceptRootPasswd: True/False -.SH FILES -\fIxnlock\fP executable file -.br -~/.msgfile default message file -.SH AUTHOR -Dan Heller Copyright (c) 1985, 1990. -.br -The original version of this program was written using pixrects on -a Sun 2 running SunOS 1.1. diff --git a/appl/xnlock/xnlock.c b/appl/xnlock/xnlock.c deleted file mode 100644 index 4bc727f14..000000000 --- a/appl/xnlock/xnlock.c +++ /dev/null @@ -1,1083 +0,0 @@ -/* - * xnlock -- Dan Heller, 1990 - * "nlock" is a "new lockscreen" type program... something that prevents - * screen burnout by making most of it "black" while providing something - * of interest to be displayed in case anyone is watching. - * "xnlock" is the X11 version of the program. - * Original sunview version written by Dan Heller 1985 (not included here). - */ -#ifdef HAVE_CONFIG_H -#include -RCSID("$Id$"); -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_PWD_H -#include -#endif -#ifdef HAVE_CRYPT_H -#undef des_encrypt -#define des_encrypt wingless_pigs_mostly_fail_to_fly -#include -#undef des_encrypt -#endif - -#ifdef KRB5 -#include -#include -#endif - -#include -#include - -static char login[16]; -static char userprompt[128]; -#ifdef KRB5 -static krb5_context context; -static krb5_principal client; -#endif - -#define font_height(font) (font->ascent + font->descent) - -static char *SPACE_STRING = " "; -static char STRING[] = "****************"; - -#define STRING_LENGTH (sizeof(STRING)) -#define MAX_PASSWD_LENGTH 256 -/* (sizeof(STRING)) */ - -#define PROMPT "Password: " -#define FAIL_MSG "Sorry, try again" -#define LEFT 001 -#define RIGHT 002 -#define DOWN 004 -#define UP 010 -#define FRONT 020 -#define X_INCR 3 -#define Y_INCR 2 -#define XNLOCK_CTRL 1 -#define XNLOCK_NOCTRL 0 - -static XtAppContext app; -static Display *dpy; -static unsigned short Width, Height; -static Widget widget; -static GC gc; -static XtIntervalId timeout_id; -static char *words; -static int x, y; -static Pixel Black, White; -static XFontStruct *font; -static char root_cpass[128]; -static char user_cpass[128]; -static int time_left, prompt_x, prompt_y, time_x, time_y; -static unsigned long interval; -static Pixmap left0, left1, right0, right1, left_front, - right_front, front, down; - -#define MAXLINES 40 - -#define IS_MOVING 1 -#define GET_PASSWD 2 -static int state; /* indicates states: walking or getting passwd */ - -static int ALLOW_LOGOUT = (60*10); /* Allow logout after nn seconds */ -#define LOGOUT_PASSWD "enuHDmTo5Lq4g" /* when given password "LOGOUT" */ -static time_t locked_at; - -struct appres_t { - Pixel bg; - Pixel fg; - XFontStruct *font; - Boolean ignore_passwd; - Boolean do_reverse; - Boolean accept_root; - char *text, *text_prog, *file, *logoutPasswd; - Boolean no_screensaver; - Boolean destroytickets; -} appres; - -static XtResource resources[] = { - { XtNbackground, XtCBackground, XtRPixel, sizeof(Pixel), - XtOffsetOf(struct appres_t, bg), XtRString, "black" }, - - { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), - XtOffsetOf(struct appres_t, fg), XtRString, "white" }, - - { XtNfont, XtCFont, XtRFontStruct, sizeof (XFontStruct *), - XtOffsetOf(struct appres_t, font), - XtRString, "-*-new century schoolbook-*-*-*-18-*" }, - - { "ignorePasswd", "IgnorePasswd", XtRBoolean, sizeof(Boolean), - XtOffsetOf(struct appres_t,ignore_passwd),XtRImmediate,(XtPointer)False }, - - { "acceptRootPasswd", "AcceptRootPasswd", XtRBoolean, sizeof(Boolean), - XtOffsetOf(struct appres_t, accept_root), XtRImmediate, (XtPointer)True }, - - { "text", "Text", XtRString, sizeof(String), - XtOffsetOf(struct appres_t, text), XtRString, "I'm out running around." }, - - { "program", "Program", XtRString, sizeof(String), - XtOffsetOf(struct appres_t, text_prog), XtRImmediate, NULL }, - - { "file", "File", XtRString, sizeof(String), - XtOffsetOf(struct appres_t,file), XtRImmediate, NULL }, - - { "logoutPasswd", "logoutPasswd", XtRString, sizeof(String), - XtOffsetOf(struct appres_t, logoutPasswd), XtRString, LOGOUT_PASSWD }, - - { "noScreenSaver", "NoScreenSaver", XtRBoolean, sizeof(Boolean), - XtOffsetOf(struct appres_t,no_screensaver), XtRImmediate, (XtPointer)True }, - - { "destroyTickets", "DestroyTickets", XtRBoolean, sizeof(Boolean), - XtOffsetOf(struct appres_t,destroytickets), XtRImmediate, (XtPointer)True }, -}; - -static XrmOptionDescRec options[] = { - { "-fg", ".foreground", XrmoptionSepArg, NULL }, - { "-foreground", ".foreground", XrmoptionSepArg, NULL }, - { "-fn", ".font", XrmoptionSepArg, NULL }, - { "-font", ".font", XrmoptionSepArg, NULL }, - { "-ip", ".ignorePasswd", XrmoptionNoArg, "True" }, - { "-noip", ".ignorePasswd", XrmoptionNoArg, "False" }, - { "-ar", ".acceptRootPasswd", XrmoptionNoArg, "True" }, - { "-noar", ".acceptRootPasswd", XrmoptionNoArg, "False" }, - { "-nonoscreensaver", ".noScreenSaver", XrmoptionNoArg, "False" }, - { "-nodestroytickets", ".destroyTickets", XrmoptionNoArg, "False" }, -}; - -static char* -get_words(void) -{ - FILE *pp = NULL; - static char buf[512]; - long n; - - if (appres.text_prog) { - pp = popen(appres.text_prog, "r"); - if (!pp) { - warn("popen %s", appres.text_prog); - return appres.text; - } - n = fread(buf, 1, sizeof(buf) - 1, pp); - buf[n] = 0; - pclose(pp); - return buf; - } - if (appres.file) { - pp = fopen(appres.file, "r"); - if (!pp) { - warn("fopen %s", appres.file); - return appres.text; - } - n = fread(buf, 1, sizeof(buf) - 1, pp); - buf[n] = 0; - fclose(pp); - return buf; - } - - return appres.text; -} - -static void -usage(int exit_code) -{ - fprintf(stderr, "usage: %s [options] [message]\n", getprogname()); - fprintf(stderr, "-fg color foreground color\n"); - fprintf(stderr, "-bg color background color\n"); - fprintf(stderr, "-rv reverse foreground/background colors\n"); - fprintf(stderr, "-nrv no reverse video\n"); - fprintf(stderr, "-ip ignore passwd\n"); - fprintf(stderr, "-nip don't ignore passwd\n"); - fprintf(stderr, "-ar accept root's passwd to unlock\n"); - fprintf(stderr, "-nar don't accept root's passwd\n"); - fprintf(stderr, "-f [file] message is read from file or ~/.msgfile\n"); - fprintf(stderr, "-prog program text is gotten from executing `program'\n"); - fprintf(stderr, "-nodestroytickets keep kerberos tickets\n"); - fprintf(stderr, "--version\n"); - fprintf(stderr, "--help\n"); - exit(exit_code); -} - -static void -init_words (int argc, char **argv) -{ - int i = 0; - - while(argv[i]) { - if(strcmp(argv[i], "-p") == 0 - || strcmp(argv[i], "-prog") == 0) { - i++; - if(argv[i]) { - appres.text_prog = argv[i]; - i++; - } else { - warnx ("-p requires an argument"); - usage(1); - } - } else if(strcmp(argv[i], "-f") == 0) { - i++; - if(argv[i]) { - appres.file = argv[i]; - i++; - } else { - int ret; - ret = asprintf (&appres.file, - "%s/.msgfile", getenv("HOME")); - if (ret == -1) - errx (1, "cannot allocate memory for message"); - } - } else if(strcmp(argv[i], "--version") == 0) { - print_version(NULL); - exit(0); - } else if(strcmp(argv[i], "--help") == 0) { - usage(0); - } else { - int j; - int len = 1; - for(j = i; argv[j]; j++) - len += strlen(argv[j]) + 1; - appres.text = malloc(len); - if (appres.text == NULL) - errx (1, "cannot allocate memory for message"); - appres.text[0] = 0; - for(; i < j; i++){ - strlcat(appres.text, argv[i], len); - strlcat(appres.text, " ", len); - } - } - } -} - -static void -ScreenSaver(int save) -{ - static int timeout, interval, prefer_blank, allow_exp; - if(!appres.no_screensaver){ - if (save) { - XGetScreenSaver(dpy, &timeout, &interval, - &prefer_blank, &allow_exp); - XSetScreenSaver(dpy, 0, interval, prefer_blank, allow_exp); - } else - /* restore state */ - XSetScreenSaver(dpy, timeout, interval, prefer_blank, allow_exp); - } -} - -/* Forward decls necessary */ -static void talk(int force_erase); -static unsigned long look(void); - -static int -zrefresh(void) -{ - switch (fork()) { - case -1: - warn ("zrefresh: fork"); - return -1; - case 0: - /* Child */ - execlp("zrefresh", "zrefresh", NULL); - execl(BINDIR "/zrefresh", "zrefresh", NULL); - return -1; - default: - /* Parent */ - break; - } - return 0; -} - -static void -leave(void) -{ - XUngrabPointer(dpy, CurrentTime); - XUngrabKeyboard(dpy, CurrentTime); - ScreenSaver(0); - XCloseDisplay(dpy); - zrefresh(); - exit(0); -} - -static void -walk(int dir) -{ - int incr = 0; - static int lastdir; - static int up = 1; - static Pixmap frame; - - XSetForeground(dpy, gc, White); - XSetBackground(dpy, gc, Black); - if (dir & (LEFT|RIGHT)) { /* left/right movement (mabye up/down too) */ - up = -up; /* bouncing effect (even if hit a wall) */ - if (dir & LEFT) { - incr = X_INCR; - frame = (up < 0) ? left0 : left1; - } else { - incr = -X_INCR; - frame = (up < 0) ? right0 : right1; - } - if ((lastdir == FRONT || lastdir == DOWN) && dir & UP) { - /* workaround silly bug that leaves screen dust when - * guy is facing forward or down and moves up-left/right. - */ - XCopyPlane(dpy, frame, XtWindow(widget), gc, 0, 0, 64,64, x, y, 1L); - XFlush(dpy); - } - /* note that maybe neither UP nor DOWN is set! */ - if (dir & UP && y > Y_INCR) - y -= Y_INCR; - else if (dir & DOWN && y < (int)Height - 64) - y += Y_INCR; - } - /* Explicit up/down movement only (no left/right) */ - else if (dir == UP) - XCopyPlane(dpy, front, XtWindow(widget), gc, - 0,0, 64,64, x, y -= Y_INCR, 1L); - else if (dir == DOWN) - XCopyPlane(dpy, down, XtWindow(widget), gc, - 0,0, 64,64, x, y += Y_INCR, 1L); - else if (dir == FRONT && frame != front) { - if (up > 0) - up = -up; - if (lastdir & LEFT) - frame = left_front; - else if (lastdir & RIGHT) - frame = right_front; - else - frame = front; - XCopyPlane(dpy, frame, XtWindow(widget), gc, 0, 0, 64,64, x, y, 1L); - } - if (dir & LEFT) - while(--incr >= 0) { - XCopyPlane(dpy, frame, XtWindow(widget), gc, - 0,0, 64,64, --x, y+up, 1L); - XFlush(dpy); - } - else if (dir & RIGHT) - while(++incr <= 0) { - XCopyPlane(dpy, frame, XtWindow(widget), gc, - 0,0, 64,64, ++x, y+up, 1L); - XFlush(dpy); - } - lastdir = dir; -} - -static long -my_random (void) -{ -#ifdef HAVE_RANDOM - return random(); -#else - return rand(); -#endif -} - -static int -think(void) -{ - if (my_random() & 1) - walk(FRONT); - if (my_random() & 1) { - words = get_words(); - return 1; - } - return 0; -} - -static void -move(XtPointer _p, XtIntervalId *_id) -{ - static int dir; - static unsigned int length; - - if (!length) { - int tries = 0; - dir = 0; - if ((my_random() & 1) && think()) { - talk(0); /* sets timeout to itself */ - return; - } - if (!(my_random() % 3) && (interval = look())) { - timeout_id = XtAppAddTimeOut(app, interval, move, NULL); - return; - } - interval = 20 + my_random() % 100; - do { - if (!tries) - length = Width/100 + my_random() % 90, tries = 8; - else - tries--; - switch (my_random() % 8) { - case 0: - if (x - X_INCR*length >= 5) - dir = LEFT; - case 1: - if (x + X_INCR*length <= (int)Width - 70) - dir = RIGHT; - case 2: - if (y - (Y_INCR*length) >= 5) - dir = UP, interval = 40; - case 3: - if (y + Y_INCR*length <= (int)Height - 70) - dir = DOWN, interval = 20; - case 4: - if (x - X_INCR*length >= 5 && y - (Y_INCR*length) >= 5) - dir = (LEFT|UP); - case 5: - if (x + X_INCR * length <= (int)Width - 70 && - y-Y_INCR * length >= 5) - dir = (RIGHT|UP); - case 6: - if (x - X_INCR * length >= 5 && - y + Y_INCR * length <= (int)Height - 70) - dir = (LEFT|DOWN); - case 7: - if (x + X_INCR*length <= (int)Width - 70 && - y + Y_INCR*length <= (int)Height - 70) - dir = (RIGHT|DOWN); - } - } while (!dir); - } - walk(dir); - --length; - timeout_id = XtAppAddTimeOut(app, interval, move, NULL); -} - -static void -post_prompt_box(Window window) -{ - int width = (Width / 3); - int height = font_height(font) * 6; - int box_x, box_y; - - /* make sure the entire nose icon fits in the box */ - if (height < 100) - height = 100; - - if(width < 105 + font->max_bounds.width*STRING_LENGTH) - width = 105 + font->max_bounds.width*STRING_LENGTH; - box_x = (Width - width) / 2; - time_x = prompt_x = box_x + 105; - - time_y = prompt_y = Height / 2; - box_y = prompt_y - 3 * font_height(font); - - /* erase current guy -- text message may still exist */ - XSetForeground(dpy, gc, Black); - XFillRectangle(dpy, window, gc, x, y, 64, 64); - talk(1); /* forcefully erase message if one is being displayed */ - /* Clear area in middle of screen for prompt box */ - XSetForeground(dpy, gc, White); - XFillRectangle(dpy, window, gc, box_x, box_y, width, height); - - /* make a box that's 5 pixels thick. Then add a thin box inside it */ - XSetForeground(dpy, gc, Black); - XSetLineAttributes(dpy, gc, 5, 0, 0, 0); - XDrawRectangle(dpy, window, gc, box_x+5, box_y+5, width-10, height-10); - XSetLineAttributes(dpy, gc, 0, 0, 0, 0); - XDrawRectangle(dpy, window, gc, box_x+12, box_y+12, width-23, height-23); - - XDrawString(dpy, window, gc, - prompt_x, prompt_y-font_height(font), - userprompt, strlen(userprompt)); - XDrawString(dpy, window, gc, prompt_x, prompt_y, PROMPT, strlen(PROMPT)); - /* set background for copyplane and DrawImageString; need reverse video */ - XSetBackground(dpy, gc, White); - XCopyPlane(dpy, right0, window, gc, 0,0, 64,64, - box_x + 20, box_y + (height - 64)/2, 1L); - prompt_x += XTextWidth(font, PROMPT, strlen(PROMPT)); - time_y += 2*font_height(font); -} - -static void -RaiseWindow(Widget w, XEvent *ev, String *s, Cardinal *n) -{ - Widget x; - if(!XtIsRealized(w)) - return; - x = XtParent(w); - XRaiseWindow(dpy, XtWindow(x)); -} - - -static void -ClearWindow(Widget w, XEvent *_event, String *_s, Cardinal *_n) -{ - XExposeEvent *event = (XExposeEvent *)_event; - if (!XtIsRealized(w)) - return; - XClearArea(dpy, XtWindow(w), event->x, event->y, - event->width, event->height, False); - if (state == GET_PASSWD) - post_prompt_box(XtWindow(w)); - if (timeout_id == 0 && event->count == 0) { - timeout_id = XtAppAddTimeOut(app, 1000L, move, NULL); - /* first grab the input focus */ - XSetInputFocus(dpy, XtWindow(w), RevertToPointerRoot, CurrentTime); - /* now grab the pointer and keyboard and contrain to this window */ - XGrabPointer(dpy, XtWindow(w), TRUE, 0, GrabModeAsync, - GrabModeAsync, XtWindow(w), None, CurrentTime); - } -} - -static void -countdown(XtPointer _t, XtIntervalId *_d) -{ - int *timeout = (int *)_t; - char buf[128]; - time_t seconds; - - if (--(*timeout) < 0) { - XExposeEvent event; - XtRemoveTimeOut(timeout_id); - state = IS_MOVING; - event.x = event.y = 0; - event.width = Width, event.height = Height; - ClearWindow(widget, (XEvent *)&event, 0, 0); - timeout_id = XtAppAddTimeOut(app, 200L, move, NULL); - return; - } - seconds = time(0) - locked_at; - if (seconds >= 3600) - snprintf(buf, sizeof(buf), - "Locked for %d:%02d:%02d ", - (int)seconds/3600, (int)seconds/60%60, (int)seconds%60); - else - snprintf(buf, sizeof(buf), - "Locked for %2d:%02d ", - (int)seconds/60, (int)seconds%60); - - XDrawImageString(dpy, XtWindow(widget), gc, - time_x, time_y, buf, strlen(buf)); - XtAppAddTimeOut(app, 1000L, countdown, timeout); - return; -} - -#ifdef KRB5 -static int -verify_krb5(const char *password) -{ - krb5_error_code ret; - krb5_ccache id; - - krb5_cc_default(context, &id); - ret = krb5_verify_user(context, - client, - id, - password, - 0, - NULL); - if (ret == 0){ - if (k_hasafs()) - krb5_afslog(context, id, NULL, NULL); - return 0; - } - if (ret != KRB5KRB_AP_ERR_MODIFIED) - krb5_warn(context, ret, "verify_krb5"); - - return -1; -} -#endif - -static int -verify(char *password) -{ - /* - * First try with root password, if allowed. - */ - if ( appres.accept_root - && strcmp(crypt(password, root_cpass), root_cpass) == 0) - return 0; - - /* - * Password that log out user - */ - if (getuid() != 0 && - geteuid() != 0 && - (time(0) - locked_at) > ALLOW_LOGOUT && - strcmp(crypt(password, appres.logoutPasswd), appres.logoutPasswd) == 0) - { - signal(SIGHUP, SIG_IGN); - kill(-1, SIGHUP); - sleep(5); - /* If the X-server shut down then so will we, else - * continue */ - signal(SIGHUP, SIG_DFL); - } - - /* - * Try copy of users password. - */ - if (strcmp(crypt(password, user_cpass), user_cpass) == 0) - return 0; - - /* - * Try to verify as user in case password change. - */ - if (unix_verify_user(login, password) == 0) - return 0; - -#ifdef KRB5 - /* - * Try to verify as user with kerberos 5. - */ - if(verify_krb5(password) == 0) - return 0; -#endif - - return -1; -} - - -static void -GetPasswd(Widget w, XEvent *_event, String *_s, Cardinal *_n) -{ - XKeyEvent *event = (XKeyEvent *)_event; - static char passwd[MAX_PASSWD_LENGTH]; - static unsigned int cnt; - static int is_ctrl = XNLOCK_NOCTRL; - char c; - KeySym keysym; - int echolen; - int old_state = state; - - if (event->type == ButtonPress) { - x = event->x, y = event->y; - return; - } - if (state == IS_MOVING) { - /* guy is running around--change to post prompt box. */ - XtRemoveTimeOut(timeout_id); - state = GET_PASSWD; - if (appres.ignore_passwd || !strlen(user_cpass)) - leave(); - post_prompt_box(XtWindow(w)); - cnt = 0; - time_left = 30; - countdown((XtPointer)&time_left, 0); - } - if (event->type == KeyRelease) { - keysym = XLookupKeysym(event, 0); - if (keysym == XK_Control_L || keysym == XK_Control_R) { - is_ctrl = XNLOCK_NOCTRL; - } - } - if (event->type != KeyPress) - return; - - time_left = 30; - - keysym = XLookupKeysym(event, 0); - if (keysym == XK_Control_L || keysym == XK_Control_R) { - is_ctrl = XNLOCK_CTRL; - return; - } - if (!XLookupString(event, &c, 1, &keysym, 0)) - return; - if (keysym == XK_Return || keysym == XK_Linefeed) { - passwd[cnt] = 0; - if(old_state == IS_MOVING) - return; - XtRemoveTimeOut(timeout_id); - - if(verify(passwd) == 0) - leave(); - - cnt = 0; - - XDrawImageString(dpy, XtWindow(widget), gc, - time_x, time_y, FAIL_MSG, strlen(FAIL_MSG)); - time_left = 0; - timeout_id = XtAppAddTimeOut(app, 2000L, countdown, &time_left); - return; - } - if (keysym == XK_BackSpace || keysym == XK_Delete || keysym == XK_Left) { - if (cnt) - passwd[cnt--] = ' '; - } else if (keysym == XK_u && is_ctrl == XNLOCK_CTRL) { - while (cnt) { - passwd[cnt--] = ' '; - echolen = min(cnt, STRING_LENGTH); - XDrawImageString(dpy, XtWindow(w), gc, - prompt_x, prompt_y, STRING, echolen); - XDrawImageString(dpy, XtWindow(w), gc, - prompt_x + XTextWidth(font, STRING, echolen), - prompt_y, SPACE_STRING, STRING_LENGTH - echolen + 1); - } - } else if (isprint((unsigned char)c)) { - if ((cnt + 1) >= MAX_PASSWD_LENGTH) - XBell(dpy, 50); - else - passwd[cnt++] = c; - } else - return; - echolen = min(cnt, STRING_LENGTH); - XDrawImageString(dpy, XtWindow(w), gc, - prompt_x, prompt_y, STRING, echolen); - XDrawImageString(dpy, XtWindow(w), gc, - prompt_x + XTextWidth(font, STRING, echolen), - prompt_y, SPACE_STRING, STRING_LENGTH - echolen +1); -} - -#include "nose.0.left" -#include "nose.1.left" -#include "nose.0.right" -#include "nose.1.right" -#include "nose.left.front" -#include "nose.right.front" -#include "nose.front" -#include "nose.down" - -static void -init_images(void) -{ - static Pixmap *images[] = { - &left0, &left1, &right0, &right1, - &left_front, &right_front, &front, &down - }; - static unsigned char *bits[] = { - nose_0_left_bits, nose_1_left_bits, nose_0_right_bits, - nose_1_right_bits, nose_left_front_bits, nose_right_front_bits, - nose_front_bits, nose_down_bits - }; - int i; - - for (i = 0; i < XtNumber(images); i++) - if (!(*images[i] = - XCreatePixmapFromBitmapData(dpy, DefaultRootWindow(dpy), - (char*)(bits[i]), 64, 64, 1, 0, 1))) - XtError("Can't load nose images"); -} - -static void -talk(int force_erase) -{ - unsigned int width = 0, height, Z, total = 0; - static unsigned int X, Y; - static int talking; - static struct { int x, y, width, height; } s_rect; - char *p, *p2; - char buf[BUFSIZ], args[MAXLINES][256]; - - /* clear what we've written */ - if (talking || force_erase) { - if (!talking) - return; - if (talking == 2) { - XSetForeground(dpy, gc, Black); - XDrawString(dpy, XtWindow(widget), gc, X, Y, words, strlen(words)); - } else if (talking == 1) { - XSetForeground(dpy, gc, Black); - XFillRectangle(dpy, XtWindow(widget), gc, s_rect.x-5, s_rect.y-5, - s_rect.width+10, s_rect.height+10); - } - talking = 0; - if (!force_erase) - timeout_id = XtAppAddTimeOut(app, 40L, - (XtTimerCallbackProc)move, - NULL); - return; - } - XSetForeground(dpy, gc, White); - talking = 1; - walk(FRONT); - strlcpy (buf, words, sizeof(buf)); - p = buf; - - /* possibly avoid a lot of work here - * if no CR or only one, then just print the line - */ - if (!(p2 = strchr(p, '\n')) || !p2[1]) { - int w; - - if (p2) - *p2 = 0; - w = XTextWidth(font, words, strlen(words)); - X = x + 32 - w/2; - Y = y - 5 - font_height(font); - /* give us a nice 5 pixel margin */ - if (X < 5) - X = 5; - else if (X + w + 15 > (int)Width + 5) - X = Width - w - 5; - if (Y < 5) - Y = y + 64 + 5 + font_height(font); - XDrawString(dpy, XtWindow(widget), gc, X, Y, words, strlen(words)); - timeout_id = XtAppAddTimeOut(app, 5000L, (XtTimerCallbackProc)talk, - NULL); - talking++; - return; - } - - /* p2 now points to the first '\n' */ - for (height = 0; p[0]; height++) { - int w; - *p2 = 0; - if ((w = XTextWidth(font, p, p2 - p)) > width) - width = w; - total += p2 - p; /* total chars; count to determine reading time */ - strlcpy(args[height], p, sizeof(args[height])); - if (height == MAXLINES - 1) { - puts("Message too long!"); - break; - } - p = p2+1; - if (!(p2 = strchr(p, '\n'))) - break; - } - height++; - - /* Figure out the height and width in pixels (height, width) extend - * the new box by 15 pixels on the sides (30 total) top and bottom. - */ - s_rect.width = width + 30; - s_rect.height = height * font_height(font) + 30; - if (x - s_rect.width - 10 < 5) - s_rect.x = 5; - else - if ((s_rect.x = x+32-(s_rect.width+15)/2) - + s_rect.width+15 > (int)Width-5) - s_rect.x = Width - 15 - s_rect.width; - if (y - s_rect.height - 10 < 5) - s_rect.y = y + 64 + 5; - else - s_rect.y = y - 5 - s_rect.height; - - XSetForeground(dpy, gc, White); - XFillRectangle(dpy, XtWindow(widget), gc, - s_rect.x-5, s_rect.y-5, s_rect.width+10, s_rect.height+10); - - /* make a box that's 5 pixels thick. Then add a thin box inside it */ - XSetForeground(dpy, gc, Black); - XSetLineAttributes(dpy, gc, 5, 0, 0, 0); - XDrawRectangle(dpy, XtWindow(widget), gc, - s_rect.x, s_rect.y, s_rect.width-1, s_rect.height-1); - XSetLineAttributes(dpy, gc, 0, 0, 0, 0); - XDrawRectangle(dpy, XtWindow(widget), gc, - s_rect.x + 7, s_rect.y + 7, s_rect.width - 15, - s_rect.height - 15); - - X = 15; - Y = 15 + font_height(font); - - /* now print each string in reverse order (start at bottom of box) */ - for (Z = 0; Z < height; Z++) { - XDrawString(dpy, XtWindow(widget), gc, s_rect.x+X, s_rect.y+Y, - args[Z], strlen(args[Z])); - Y += font_height(font); - } - timeout_id = XtAppAddTimeOut(app, (total/15) * 1000, - (XtTimerCallbackProc)talk, NULL); -} - -static unsigned long -look(void) -{ - XSetForeground(dpy, gc, White); - XSetBackground(dpy, gc, Black); - if (my_random() % 3) { - XCopyPlane(dpy, (my_random() & 1)? down : front, XtWindow(widget), gc, - 0, 0, 64,64, x, y, 1L); - return 1000L; - } - if (!(my_random() % 5)) - return 0; - if (my_random() % 3) { - XCopyPlane(dpy, (my_random() & 1)? left_front : right_front, - XtWindow(widget), gc, 0, 0, 64,64, x, y, 1L); - return 1000L; - } - if (!(my_random() % 5)) - return 0; - XCopyPlane(dpy, (my_random() & 1)? left0 : right0, XtWindow(widget), gc, - 0, 0, 64,64, x, y, 1L); - return 1000L; -} - -int -main (int argc, char **argv) -{ - int i; - Widget override; - XGCValues gcvalues; - - setprogname (argv[0]); - - /* - * Must be setuid root to read /etc/shadow, copy encrypted - * passwords here and then switch to sane uid. - */ - { - struct passwd *pw; - uid_t uid = getuid(); - if (!(pw = k_getpwuid(0))) - errx (1, "can't get root's passwd!"); - strlcpy(root_cpass, pw->pw_passwd, sizeof(root_cpass)); - - if (!(pw = k_getpwuid(uid))) - errx (1, "Can't get your password entry!"); - strlcpy(user_cpass, pw->pw_passwd, sizeof(user_cpass)); - setuid(uid); - if (uid != 0 && setuid(0) != -1) { - fprintf(stderr, "Failed to drop privileges!\n"); - exit(1); - } - /* Now we're no longer running setuid root. */ - strlcpy(login, pw->pw_name, sizeof(login)); - } - -#if defined(HAVE_SRANDOMDEV) - srandomdev(); -#elif defined(HAVE_RANDOM) - srandom(time(NULL)); -#else - srand (time(NULL)); -#endif - for (i = 0; i < STRING_LENGTH; i++) - STRING[i] = ((unsigned long)my_random() % ('~' - ' ')) + ' '; - - locked_at = time(0); - - snprintf(userprompt, sizeof(userprompt), "User: %s", login); -#ifdef KRB5 - { - krb5_error_code ret; - char *str; - - ret = krb5_init_context(&context); - if (ret) - errx (1, "krb5_init_context failed: %d", ret); - krb5_get_default_principal(context, &client); - krb5_unparse_name(context, client, &str); - snprintf(userprompt, sizeof(userprompt), "User: %s", str); - free(str); - } -#endif - - override = XtVaAppInitialize(&app, "XNlock", options, XtNumber(options), - &argc, argv, NULL, - XtNoverrideRedirect, True, - NULL); - - XtVaGetApplicationResources(override,(XtPointer)&appres, - resources,XtNumber(resources), - NULL); - /* the background is black and the little guy is white */ - Black = appres.bg; - White = appres.fg; - - if (appres.destroytickets) { -#ifdef KRB5 - /*XXX add krb4 code here */ -#endif - } - - dpy = XtDisplay(override); - - if (dpy == 0) - errx (1, "Error: Can't open display"); - - Width = DisplayWidth(dpy, DefaultScreen(dpy)) + 2; - Height = DisplayHeight(dpy, DefaultScreen(dpy)) + 2; - - for(i = 0; i < ScreenCount(dpy); i++){ - Widget shell, core; - - struct xxx{ - Pixel bg; - }res; - - XtResource Res[] = { - { XtNbackground, XtCBackground, XtRPixel, sizeof(Pixel), - XtOffsetOf(struct xxx, bg), XtRString, "black" } - }; - - if(i == DefaultScreen(dpy)) - continue; - - shell = XtVaAppCreateShell(NULL,NULL, applicationShellWidgetClass, dpy, - XtNscreen, ScreenOfDisplay(dpy, i), - XtNoverrideRedirect, True, - XtNx, -1, - XtNy, -1, - NULL); - - XtVaGetApplicationResources(shell, (XtPointer)&res, - Res, XtNumber(Res), - NULL); - - core = XtVaCreateManagedWidget("_foo", widgetClass, shell, - XtNwidth, DisplayWidth(dpy, i), - XtNheight, DisplayHeight(dpy, i), - XtNbackground, res.bg, - NULL); - XtRealizeWidget(shell); - } - - widget = XtVaCreateManagedWidget("_foo", widgetClass, override, - XtNwidth, Width, - XtNheight, Height, - XtNbackground, Black, - NULL); - - init_words(--argc, ++argv); - init_images(); - - gcvalues.foreground = Black; - gcvalues.background = White; - - - font = appres.font; - gcvalues.font = font->fid; - gcvalues.graphics_exposures = False; - gc = XCreateGC(dpy, DefaultRootWindow(dpy), - GCForeground | GCBackground | GCGraphicsExposures | GCFont, - &gcvalues); - - x = Width / 2; - y = Height / 2; - srand (time(0)); - state = IS_MOVING; - - { - static XtActionsRec actions[] = { - { "ClearWindow", ClearWindow }, - { "GetPasswd", GetPasswd }, - { "RaiseWindow", RaiseWindow }, - }; - XtAppAddActions(app, actions, XtNumber(actions)); - XtOverrideTranslations(widget, - XtParseTranslationTable( - ": ClearWindow() \n" - ": GetPasswd() \n" - ": RaiseWindow() \n" - ": GetPasswd() \n" - ": GetPasswd()")); - } - - XtRealizeWidget(override); - if((i = XGrabPointer(dpy, XtWindow(widget), True, 0, GrabModeAsync, - GrabModeAsync, XtWindow(widget), - None, CurrentTime)) != 0) - errx(1, "Failed to grab pointer (%d)", i); - - if((i = XGrabKeyboard(dpy, XtWindow(widget), True, GrabModeAsync, - GrabModeAsync, CurrentTime)) != 0) - errx(1, "Failed to grab keyboard (%d)", i); - ScreenSaver(1); - XtAppMainLoop(app); - exit(0); -} - diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 000000000..fa56c4c59 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,85 @@ +# +# This file tells appveyor.com how to build Heimdal on Windows. +# Appveyor is a continuous integration (CI) service for github and other +# users, and is free for public repositories. +# + +version: '1.0.{build}' + +image: + - Visual Studio 2019 + +install: + # HACK -- pacman installation in Appveyor seems broken + # Taken from https://github.com/johnkerl/miller/blob/master/appveyor.yml + # (which is gone) + #- ps: dir 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Microsoft SDKs\Windows' -Recurse + - set "PATH=C:\msys64\usr\bin;%PATH%" + - set "PATH=C:\%MSYS2_DIR%\%MSYSTEM%\bin;C:\%MSYS2_DIR%\usr\bin;%PATH%" + - bash -lc "mkdir -p /var/lib/pacman/sync/" + - bash -lc "pacman-key --init" + - bash -lc "pacman-key --populate msys2" + - bash -lc "curl -O http://repo.msys2.org/msys/x86_64/msys2-keyring-1~20211228-1-any.pkg.tar.zst" + - bash -lc "curl -O http://repo.msys2.org/msys/x86_64/msys2-keyring-1~20211228-1-any.pkg.tar.zst.sig" + - bash -lc "pacman --noconfirm -U --config <(echo) msys2-keyring-1~20211228-1-any.pkg.tar.zst" + - bash -lc "mkdir -p /var/lib/pacman/sync/" + - bash -lc "pacman-key --init" + - bash -lc "pacman-key --populate msys2" + - bash -lc "pacman -S --noconfirm --refresh pacman" + - bash -lc "pacman -S --needed --noconfirm pacman-mirrors" + - bash -lc "pacman -S --needed --noconfirm mingw-w64-x86_64-toolchain autoconf automake libtool make patch mingw-w64-x86_64-libtool" + - bash -lc "pacman -S --needed --noconfirm bison flex" + - bash -lc "pacman -S --needed --noconfirm perl perl-JSON" + +build_script: + # build using Windows 10 SDK + - set "WINSDKVER=10.0.22000.0" + - call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 %WINSDKVER% + - set "WIXDIR=c:\Program Files (x86)\Windows Installer XML v3.5" + # We're not doing any codesigning in the Appveyor build yet. + - SET "CODESIGN_PKT=0000000000000000" + - set "PATH=%PATH%;C:\Perl64\bin;C:\tools\cygwin\bin;C:\Program Files (x86)\HTML Help Workshop" + - set "PATH=%PATH%;C:/msys64/usr/bin" + - set "PATH=%PATH%;C:\program files (x86)\windows installer xml v3.5\bin;C:\cygwin\bin" + # double check this, should it be x86 or x64? + - set "PATH=%PATH%;%WindowsSdkVerBinPath%\x86" + - set "PATH=C:\Python310-x64;%PATH%" + - set dbg__type=Debug + - title Heimdal Build %CPU% %dbg__type% + - echo PATH=%PATH% + # target Windows 10 API + - set APPVER=10.0 + # Newer texinfo has no .exe's, so we have to invoke it as + # "perl ...\makeinfo ...". See doc/NTMakefile. + - nmake /f NTMakefile APPVEYOR=1 MAKEINFO=makeinfo NO_INSTALLERS=1 + - 7z a heimdal.zip C:\projects\heimdal + +test_script: + # Packages are not validated in the Appveyor build, FYI. + - nmake /f NTMakefile APPVEYOR=1 MAKEINFO=makeinfo NO_INSTALLERS=1 test + +artifacts: + - path: heimdal-out.zip + name: heimdal-out + - path: heimdal.zip + name: heimdal + +on_failure: + - 7z a heimdal-out.zip C:\projects\heimdal + - appveyor PushArtifact heimdal-out.zip + +# To get RDP access to an appveyor worker for debugging a build, just +# uncomment these next two lines and the last two lines too. +#init: +# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) + +# Uncomment this to allow the RDP session to continue after the build +# finishes. +# +# There's a delete-me file on the desktop that one should delete when +# one is done with the worker. RDP sessions are capped at 60 minutes as +# of this writing. +# +#on_finish: +# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) + diff --git a/autogen.sh b/autogen.sh old mode 100644 new mode 100755 index c3facbf5c..fc504dca2 --- a/autogen.sh +++ b/autogen.sh @@ -2,4 +2,8 @@ # to really generate all files you need to run "make distcheck" in a # object tree, but this will do if you have all parts of the required # tool-chain installed +set -e autoreconf -f -i || { echo "autoreconf failed: $?"; exit 1; } +find . \( -name '*-private.h' -o -name '*-protos.h' \) | xargs rm -f +perl -MJSON -e 'print foo;' || \ + { echo "you must install JSON perl module (cpan install JSON)"; exit 1; } diff --git a/cf/Makefile.am.common b/cf/Makefile.am.common index ce5538e1a..90921fe46 100644 --- a/cf/Makefile.am.common +++ b/cf/Makefile.am.common @@ -1,6 +1,6 @@ # $Id$ -SUFFIXES = .et .h +SUFFIXES = .et .h .pc.in .pc DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_srcdir)/include @@ -12,6 +12,8 @@ endif AM_CFLAGS = $(WFLAGS) +CLANG_FORMAT_STYLE = '{BasedOnStyle: Mozilla, AlwaysBreakAfterReturnType: TopLevelDefinitions, IndentWidth: 4, SortIncludes: false}' + CP = cp ## set build_HEADERZ to headers that should just be installed in build tree @@ -31,8 +33,6 @@ LIB_gethostbyname = @LIB_gethostbyname@ LIB_getpwent_r = @LIB_getpwent_r@ LIB_getpwnam_r = @LIB_getpwnam_r@ LIB_getsockopt = @LIB_getsockopt@ -LIB_logout = @LIB_logout@ -LIB_logwtmp = @LIB_logwtmp@ LIB_odm_initialize = @LIB_odm_initialize@ LIB_openpty = @LIB_openpty@ LIB_pidfile = @LIB_pidfile@ @@ -45,10 +45,8 @@ LIB_tgetent = @LIB_tgetent@ LIB_com_err = @LIB_com_err@ LIB_door_create = @LIB_door_create@ -HESIODLIB = @HESIODLIB@ -HESIODINCLUDE = @HESIODINCLUDE@ -INCLUDE_hesiod = @INCLUDE_hesiod@ -LIB_hesiod = @LIB_hesiod@ +LIB_openssl_crypto = @LIB_openssl_crypto@ +INCLUDE_openssl_crypto = @INCLUDE_openssl_crypto@ INCLUDE_krb4 = @INCLUDE_krb4@ LIB_krb4 = @LIB_krb4@ @@ -61,20 +59,36 @@ LIB_readline = @LIB_readline@ LEXLIB = @LEXLIB@ +libexec_heimdaldir = $(libexecdir)/heimdal + install-suid-programs: @foo='$(bin_SUIDS)'; \ for file in $$foo; do \ - x=$(DESTDIR)$(bindir)/$$file; \ - if chown 0:0 $$x && chmod u+s $$x; then :; else \ - echo "*"; \ - echo "* Failed to install $$x setuid root"; \ - echo "*"; \ - fi; done + x=$(DESTDIR)$(bindir)/$$file; \ + if chown 0:0 $$x && chmod u+s $$x; then :; else \ + echo "*"; \ + echo "* Failed to install $$x setuid root"; \ + echo "*"; \ + fi; \ + done -install-exec-hook: install-suid-programs +install-exec-local: install-suid-programs -install-build-headers:: $(include_HEADERS) $(dist_include_HEADERS) $(nodist_include_HEADERS) $(build_HEADERZ) $(nobase_include_HEADERS) - @foo='$(include_HEADERS) $(dist_include_HEADERS) $(nodist_include_HEADERS) $(build_HEADERZ)'; \ +codesign-all: + @if [ X"$$CODE_SIGN_IDENTITY" != X ] ; then \ + foo='$(bin_PROGRAMS) $(sbin_PROGRAMS) $(libexec_PROGRAMS)' ; \ + for file in $$foo ; do \ + echo "CODESIGN $$file" ; \ + codesign -f -s "$$CODE_SIGN_IDENTITY" $$file || exit 1 ; \ + done ; \ + fi + + + +all-local: codesign-all + +install-build-headers:: $(include_HEADERS) $(dist_include_HEADERS) $(nodist_include_HEADERS) $(build_HEADERZ) $(nobase_include_HEADERS) $(noinst_HEADERS) + @foo='$(include_HEADERS) $(dist_include_HEADERS) $(nodist_include_HEADERS) $(build_HEADERZ) $(noinst_HEADERS)'; \ for f in $$foo; do \ f=`basename $$f`; \ if test -f "$(srcdir)/$$f"; then file="$(srcdir)/$$f"; \ @@ -82,7 +96,7 @@ install-build-headers:: $(include_HEADERS) $(dist_include_HEADERS) $(nodist_incl if cmp -s $$file $(buildinclude)/$$f 2> /dev/null ; then \ : ; else \ echo " $(CP) $$file $(buildinclude)/$$f"; \ - $(CP) $$file $(buildinclude)/$$f; \ + $(CP) $$file $(buildinclude)/$$f || true; \ fi ; \ done ; \ foo='$(nobase_include_HEADERS)'; \ @@ -127,15 +141,9 @@ check-local:: test "$$failed" -eq 0 || exit 1; \ fi -SUFFIXES += .x .z .hx +SUFFIXES += .x .z -.x.c: - @cmp -s $< $@ 2> /dev/null || cp $< $@ - -.hx.h: - @cmp -s $< $@ 2> /dev/null || cp $< $@ - -SUFFIXES += .1 .3 .5 .8 .cat1 .cat3 .cat5 .cat8 +SUFFIXES += .1 .3 .5 .7 .8 .cat1 .cat3 .cat5 .cat7 .cat8 NROFF_MAN = groff -mandoc -Tascii #NROFF_MAN = nroff -man @@ -145,6 +153,8 @@ NROFF_MAN = groff -mandoc -Tascii $(NROFF_MAN) $< > $@ .5.cat5: $(NROFF_MAN) $< > $@ +.7.cat7: + $(NROFF_MAN) $< > $@ .8.cat8: $(NROFF_MAN) $< > $@ @@ -189,6 +199,19 @@ dist-cat5-mans: $(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x; \ done +dist-cat7-mans: + @foo='$(man7_MANS)'; \ + bar='$(man_MANS)'; \ + for i in $$bar; do \ + case $$i in \ + *.7) foo="$$foo $$i";; \ + esac; done ;\ + for i in $$foo; do \ + x=`echo $$i | sed 's/\.[^.]*$$/.cat7/'`; \ + echo "$(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x"; \ + $(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x; \ + done + dist-cat8-mans: @foo='$(man8_MANS)'; \ bar='$(man_MANS)'; \ @@ -202,13 +225,13 @@ dist-cat8-mans: $(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x; \ done -dist-hook: dist-cat1-mans dist-cat3-mans dist-cat5-mans dist-cat8-mans +dist-hook: dist-cat1-mans dist-cat3-mans dist-cat5-mans dist-cat7-mans dist-cat8-mans install-cat-mans: - $(SHELL) $(top_srcdir)/cf/install-catman.sh install "$(INSTALL_DATA)" "$(mkinstalldirs)" "$(srcdir)" "$(DESTDIR)$(mandir)" '$(CATMANEXT)' $(man_MANS) $(man1_MANS) $(man3_MANS) $(man5_MANS) $(man8_MANS) + $(SHELL) $(top_srcdir)/cf/install-catman.sh install "$(INSTALL_DATA)" "$(mkinstalldirs)" "$(srcdir)" "$(DESTDIR)$(mandir)" '$(CATMANEXT)' $(man_MANS) $(man1_MANS) $(man3_MANS) $(man5_MANS) $(man7_MANS) $(man8_MANS) uninstall-cat-mans: - $(SHELL) $(top_srcdir)/cf/install-catman.sh uninstall "$(INSTALL_DATA)" "$(mkinstalldirs)" "$(srcdir)" "$(DESTDIR)$(mandir)" '$(CATMANEXT)' $(man_MANS) $(man1_MANS) $(man3_MANS) $(man5_MANS) $(man8_MANS) + $(SHELL) $(top_srcdir)/cf/install-catman.sh uninstall "$(INSTALL_DATA)" "$(mkinstalldirs)" "$(srcdir)" "$(DESTDIR)$(mandir)" '$(CATMANEXT)' $(man_MANS) $(man1_MANS) $(man3_MANS) $(man5_MANS) $(man7_MANS) $(man8_MANS) install-data-hook: install-cat-mans uninstall-hook: uninstall-cat-mans @@ -219,15 +242,20 @@ uninstall-hook: uninstall-cat-mans .et.c: $(COMPILE_ET) $< +if NO_AFS +LIB_kafs = +else LIB_kafs = $(top_builddir)/lib/kafs/libkafs.la $(AIX_EXTRA_KAFS) +endif if KRB5 LIB_krb5 = $(top_builddir)/lib/krb5/libkrb5.la \ $(top_builddir)/lib/asn1/libasn1.la LIB_gssapi = $(top_builddir)/lib/gssapi/libgssapi.la -LIB_tsasl = $(top_builddir)/lib/tsasl/libtsasl.la endif +LIB_heimbase = $(top_builddir)/lib/base/libheimbase.la + if DCE LIB_kdfs = $(top_builddir)/lib/kdfs/libkdfs.la endif @@ -239,7 +267,7 @@ endif check-valgrind: tobjdir=`cd $(top_builddir) && pwd` ; \ tsrcdir=`cd $(top_srcdir) && pwd` ; \ - env TESTS_ENVIRONMENT="$${tobjdir}/libtool --mode execute valgrind --leak-check=full --trace-children=yes --quiet -q --num-callers=30 --suppressions=$${tsrcdir}/cf/valgrind-suppressions" make check + env TESTS_ENVIRONMENT="$${tsrcdir}/cf/maybe-valgrind.sh -s $${tsrcdir} -o $${tobjdir}" make check # # Target to please samba build farm, builds distfiles in-tree. @@ -252,3 +280,15 @@ distdir-in-tree: $(DISTFILES) $(INFO_DEPS) (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) distdir-in-tree) ; \ fi ; \ done + + +#silent-rules + +heim_verbose = $(heim_verbose_$(V)) +heim_verbose_ = $(heim_verbose_$(AM_DEFAULT_VERBOSITY)) +heim_verbose_0 = @echo " GEN "$@; + +if ENABLE_GCOV +AM_CFLAGS += --coverage --no-inline +AM_LDFLAGS = -lgcov +endif diff --git a/cf/aix.m4 b/cf/aix.m4 index 5d0be4f14..2c450fbb8 100644 --- a/cf/aix.m4 +++ b/cf/aix.m4 @@ -9,7 +9,7 @@ case "$host" in *-*-aix3*) aix=3 ;; -*-*-aix[4-9]*) +*-*-aix[[4-9]]*) aix=4 ;; esac @@ -17,12 +17,14 @@ esac AM_CONDITIONAL(AIX, test "$aix" != no)dnl AM_CONDITIONAL(AIX4, test "$aix" = 4)dnl - AC_ARG_ENABLE(dynamic-afs, AS_HELP_STRING([--disable-dynamic-afs], [do not use loaded AFS library with AIX])) if test "$aix" != no; then + + AC_DEFINE(NEED_QSORT, 1, [if your qsort is not a stable sort]) + if test "$enable_dynamic_afs" != no; then AC_REQUIRE([rk_DLOPEN]) if test "$ac_cv_func_dlopen" = no; then diff --git a/cf/autobuild.m4 b/cf/autobuild.m4 deleted file mode 100644 index bd1f4dc1b..000000000 --- a/cf/autobuild.m4 +++ /dev/null @@ -1,34 +0,0 @@ -# autobuild.m4 serial 2 (autobuild-3.3) -# Copyright (C) 2004 Simon Josefsson -# -# This file is free software, distributed under the terms of the GNU -# General Public License. As a special exception to the GNU General -# Public License, this file may be distributed as part of a program -# that contains a configuration script generated by Autoconf, under -# the same distribution terms as the rest of that program. -# -# This file can can be used in projects which are not available under -# the GNU General Public License or the GNU Library General Public -# License but which still want to provide support for Autobuild. - -# Usage: AB_INIT([MODE]). -AC_DEFUN([AB_INIT], -[ - AC_REQUIRE([AC_CANONICAL_BUILD]) - AC_REQUIRE([AC_CANONICAL_HOST]) - - AC_MSG_NOTICE([autobuild project... ${PACKAGE_NAME:-$PACKAGE}]) - AC_MSG_NOTICE([autobuild revision... ${PACKAGE_VERSION:-$VERSION}]) - hostname=`hostname` - if test "$hostname"; then - AC_MSG_NOTICE([autobuild hostname... $hostname]) - fi - ifelse([$1],[],,[AC_MSG_NOTICE([autobuild mode... $1])]) - date=`date +%Y%m%d-%H%M%S` - if test "$?" != 0; then - date=`date` - fi - if test "$date"; then - AC_MSG_NOTICE([autobuild timestamp... $date]) - fi -]) diff --git a/cf/ax_check_sign.m4 b/cf/ax_check_sign.m4 new file mode 100644 index 000000000..bc2c3f034 --- /dev/null +++ b/cf/ax_check_sign.m4 @@ -0,0 +1,54 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_check_sign.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_SIGN (TYPE, [ACTION-IF-SIGNED], [ACTION-IF-UNSIGNED], [INCLUDES]) +# +# DESCRIPTION +# +# Checks whether TYPE is signed or not. If no INCLUDES are specified, the +# default includes are used. If ACTION-IF-SIGNED is given, it is +# additional shell code to execute when the type is signed. If +# ACTION-IF-UNSIGNED is given, it is executed when the type is unsigned. +# +# This macro assumes that the type exists. Therefore the existence of the +# type should be checked before calling this macro. For example: +# +# AC_CHECK_HEADERS([wchar.h]) +# AC_CHECK_TYPE([wchar_t],,[ AC_MSG_ERROR([Type wchar_t not found.]) ]) +# AX_CHECK_SIGN([wchar_t], +# [ AC_DEFINE(WCHAR_T_SIGNED, 1, [Define if wchar_t is signed]) ], +# [ AC_DEFINE(WCHAR_T_UNSIGNED, 1, [Define if wchar_t is unsigned]) ], [ +# #ifdef HAVE_WCHAR_H +# #include +# #endif +# ]) +# +# LICENSE +# +# Copyright (c) 2008 Ville Laurikari +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 7 + +AU_ALIAS([VL_CHECK_SIGN], [AX_CHECK_SIGN]) +AC_DEFUN([AX_CHECK_SIGN], [ + typename=`echo $1 | sed "s/@<:@^a-zA-Z0-9_@:>@/_/g"` + AC_CACHE_CHECK([whether $1 is signed], ax_cv_decl_${typename}_signed, [ + AC_TRY_COMPILE([$4], + [ int foo @<:@ 1 - 2 * !((($1) -1) < 0) @:>@ ], + [ eval "ax_cv_decl_${typename}_signed=\"yes\"" ], + [ eval "ax_cv_decl_${typename}_signed=\"no\"" ])]) + symbolname=`echo $1 | sed "s/@<:@^a-zA-Z0-9_@:>@/_/g" | tr "a-z" "A-Z"` + if eval "test \"\${ax_cv_decl_${typename}_signed}\" = \"yes\""; then + $2 + elif eval "test \"\${ax_cv_decl_${typename}_signed}\" = \"no\""; then + $3 + fi +])dnl diff --git a/cf/broken-getaddrinfo.m4 b/cf/broken-getaddrinfo.m4 index 6d34f3b77..5daf416e3 100644 --- a/cf/broken-getaddrinfo.m4 +++ b/cf/broken-getaddrinfo.m4 @@ -23,4 +23,4 @@ main(int argc, char **argv) return 1; return 0; } -]])],[ac_cv_func_getaddrinfo_numserv=yes],[ac_cv_func_getaddrinfo_numserv=no]))]) +]])],[ac_cv_func_getaddrinfo_numserv=yes],[ac_cv_func_getaddrinfo_numserv=no],[ac_cv_func_getaddrinfo_numserv=yes]))]) diff --git a/cf/broken-glob.m4 b/cf/broken-glob.m4 deleted file mode 100644 index 0e77427d0..000000000 --- a/cf/broken-glob.m4 +++ /dev/null @@ -1,29 +0,0 @@ -dnl $Id$ -dnl -dnl check for glob(3) -dnl -AC_DEFUN([AC_BROKEN_GLOB],[ -AC_CACHE_CHECK(for working glob, ac_cv_func_glob_working, -ac_cv_func_glob_working=yes -AC_LINK_IFELSE([AC_LANG_PROGRAM([[ -#include -#include ]],[[ -glob(NULL, GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE| -#ifdef GLOB_MAXPATH -GLOB_MAXPATH -#else -GLOB_LIMIT -#endif -, -NULL, NULL); -]])],[:],[ac_cv_func_glob_working=no])) - -if test "$ac_cv_func_glob_working" = yes; then - AC_DEFINE(HAVE_GLOB, 1, [define if you have a glob() that groks - GLOB_BRACE, GLOB_NOCHECK, GLOB_QUOTE, GLOB_TILDE, and GLOB_LIMIT]) -fi -if test "$ac_cv_func_glob_working" = yes; then -AC_NEED_PROTO([#include -#include ],glob) -fi -]) diff --git a/cf/broken-realloc.m4 b/cf/broken-realloc.m4 index b6d962ace..a397e9688 100644 --- a/cf/broken-realloc.m4 +++ b/cf/broken-realloc.m4 @@ -19,7 +19,9 @@ int main(int argc, char **argv) if test "$ac_cv_func_realloc_broken" = yes ; then AC_DEFINE(BROKEN_REALLOC, 1, [Define if realloc(NULL) doesn't work.]) fi -AH_BOTTOM([#ifdef BROKEN_REALLOC -#define realloc(X, Y) rk_realloc((X), (Y)) -#endif]) +dnl AH_BOTTOM([#ifdef BROKEN_REALLOC +dnl #ifndef realloc +dnl #define realloc(X, Y) rk_realloc((X), (Y)) +dnl #endif +dnl #endif]) ]) diff --git a/cf/capabilities.m4 b/cf/capabilities.m4 deleted file mode 100644 index 4178b3c0a..000000000 --- a/cf/capabilities.m4 +++ /dev/null @@ -1,14 +0,0 @@ -dnl -dnl $Id$ -dnl - -dnl -dnl Test SGI capabilities -dnl - -AC_DEFUN([KRB_CAPABILITIES],[ - -AC_CHECK_HEADERS(capability.h sys/capability.h) - -AC_CHECK_FUNCS(sgi_getcapabilitybyname cap_set_proc) -]) diff --git a/cf/check-compile-et.m4 b/cf/check-compile-et.m4 index 9ea8320f3..e580cbb49 100644 --- a/cf/check-compile-et.m4 +++ b/cf/check-compile-et.m4 @@ -3,12 +3,12 @@ dnl dnl CHECK_COMPILE_ET AC_DEFUN([CHECK_COMPILE_ET], [ -AC_CHECK_PROG(COMPILE_ET, compile_et, [compile_et]) +AC_CHECK_PROG(COMPILE_ET, compile_et, [compile_et], [no]) krb_cv_compile_et="no" krb_cv_com_err_need_r="" krb_cv_compile_et_cross=no -if test "${COMPILE_ET}" = "compile_et"; then +if test "${COMPILE_ET}" != "no"; then dnl We have compile_et. Now let's see if it supports `prefix' and `index'. AC_MSG_CHECKING(whether compile_et has the features we need) @@ -28,7 +28,8 @@ if ${COMPILE_ET} conftest_et.et >/dev/null 2>&1; then CPPFLAGS="-I/usr/include/et ${CPPFLAGS}" fi dnl Check that the `prefix' and `index' directives were honored. - AC_RUN_IFELSE([ + AC_LANG(C) + AC_RUN_IFELSE([AC_LANG_SOURCE([ #include #include #include "conftest_et.h" @@ -37,7 +38,7 @@ int main(int argc, char **argv){ #error compile_et does not handle error_table N M #endif return (CONFTEST_CODE2 - CONFTEST_CODE1) != 127;} - ], [krb_cv_compile_et="yes"],[CPPFLAGS="${save_CPPFLAGS}"], + ])], [krb_cv_compile_et="yes"],[CPPFLAGS="${save_CPPFLAGS}"], [krb_cv_compile_et="yes" krb_cv_compile_et_cross=yes] ) fi AC_MSG_RESULT(${krb_cv_compile_et}) @@ -67,6 +68,7 @@ elif test "${krb_cv_compile_et}" = "yes"; then const char *p; p = error_message(0); initialize_error_table_r(0,0,0,0); + com_right_r(0, 0, 0, 0); ]])],[krb_cv_com_err="yes"],[krb_cv_com_err="no"; CPPFLAGS="${save_CPPFLAGS}"]) AC_MSG_RESULT(${krb_cv_com_err}) LIBS="${krb_cv_save_LIBS}" @@ -83,6 +85,7 @@ if test "${krb_cv_com_err}" = "yes"; then LIB_com_err_a="" LIB_com_err_so="" AC_MSG_NOTICE(Using the already-installed com_err) + COMPILE_ET="${ac_cv_prog_COMPILE_ET}" localcomerr=no elif test "${krb_cv_com_err}" = "cross"; then DIR_com_err="com_err" @@ -90,6 +93,7 @@ elif test "${krb_cv_com_err}" = "cross"; then LIB_com_err_a="\$(top_builddir)/lib/com_err/.libs/libcom_err.a" LIB_com_err_so="\$(top_builddir)/lib/com_err/.libs/libcom_err.so" AC_MSG_NOTICE(Using our own com_err with toolchain compile_et) + COMPILE_ET="${ac_cv_prog_COMPILE_ET}" localcomerr=yes else COMPILE_ET="\$(top_builddir)/lib/com_err/compile_et" @@ -101,6 +105,7 @@ else localcomerr=yes fi AM_CONDITIONAL(COM_ERR, test "$localcomerr" = yes)dnl +AC_SUBST(COMPILE_ET) AC_SUBST(DIR_com_err) AC_SUBST(LIB_com_err) AC_SUBST(LIB_com_err_a) diff --git a/cf/check-compile-flag.m4 b/cf/check-compile-flag.m4 new file mode 100644 index 000000000..bd753b34d --- /dev/null +++ b/cf/check-compile-flag.m4 @@ -0,0 +1,53 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the current language's compiler +# or gives an error. (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 6 + +AC_DEFUN([AX_CHECK_COMPILE_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl +AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ + ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" + AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_COMPILE_FLAGS diff --git a/cf/check-getpwnam_r-posix.m4 b/cf/check-getpwnam_r-posix.m4 index 69bc06e7c..0e9167f07 100644 --- a/cf/check-getpwnam_r-posix.m4 +++ b/cf/check-getpwnam_r-posix.m4 @@ -1,6 +1,6 @@ dnl $Id$ dnl -dnl check for getpwnam_r, and if it's posix or not +dnl check for getpwnam_r, and if it's posix or not; also check for getpwuid_r AC_DEFUN([AC_CHECK_GETPWNAM_R_POSIX],[ AC_FIND_FUNC_NO_LIBS(getpwnam_r,c_r) @@ -14,12 +14,61 @@ if test "$ac_cv_func_getpwnam_r" = yes; then int main(int argc, char **argv) { struct passwd pw, *pwd; - return getpwnam_r("", &pw, NULL, 0, &pwd) < 0; + return getpwnam_r("", &pw, 0, 0, &pwd) < 0; } ]])],[ac_cv_func_getpwnam_r_posix=yes],[ac_cv_func_getpwnam_r_posix=no],[:]) +LIBS="$ac_libs") + AC_CACHE_CHECK(if _POSIX_PTHREAD_SEMANTICS is needed,ac_cv_func_getpwnam_r_posix_def, + ac_libs="$LIBS" + LIBS="$LIBS $LIB_getpwnam_r" + AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include +int main(int argc, char **argv) +{ + struct passwd pw, *pwd; + return getpwnam_r("", &pw, 0, 0, &pwd) < 0; +} +]])],[ac_cv_func_getpwnam_r_posix_def=no],[ac_cv_func_getpwnam_r_posix_def=yes],[:]) LIBS="$ac_libs") if test "$ac_cv_func_getpwnam_r_posix" = yes; then AC_DEFINE(POSIX_GETPWNAM_R, 1, [Define if getpwnam_r has POSIX flavour.]) fi +if test "$ac_cv_func_getpwnam_r_posix" = yes -a "$ac_cv_func_getpwnam_r_posix_def" = yes; then + AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Define to get POSIX getpwnam_r in some systems.]) fi -]) \ No newline at end of file +fi +]) + +AC_DEFUN([AC_CHECK_GETPWUID_R_POSIX],[ +AC_FIND_FUNC_NO_LIBS(getpwuid_r,c_r) +if test "$ac_cv_func_getpwuid_r" = yes; then + AC_CACHE_CHECK(if getpwuid_r is posix,ac_cv_func_getpwuid_r_posix, + ac_libs="$LIBS" + LIBS="$LIBS $LIB_getpwuid_r" + AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#define _POSIX_PTHREAD_SEMANTICS +#include +int main(int argc, char **argv) +{ + struct passwd pw, *pwd; + return getpwuid_r(0, &pw, 0, 0, &pwd) < 0; +} +]])],[ac_cv_func_getpwuid_r_posix=yes],[ac_cv_func_getpwuid_r_posix=no],[:]) +LIBS="$ac_libs") + AC_CACHE_CHECK(if _POSIX_PTHREAD_SEMANTICS is needed,ac_cv_func_getpwuid_r_posix_def, + ac_libs="$LIBS" + LIBS="$LIBS $LIB_getpwuid_r" + AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include +int main(int argc, char **argv) +{ + struct passwd pw, *pwd; + return getpwuid_r("", &pw, 0, 0, &pwd) < 0; +} +]])],[ac_cv_func_getpwuid_r_posix_def=no],[ac_cv_func_getpwuid_r_posix_def=yes],[:]) +LIBS="$ac_libs") +if test "$ac_cv_func_getpwuid_r_posix" = yes; then + AC_DEFINE(POSIX_GETPWUID_R, 1, [Define if getpwuid_r has POSIX flavour.]) +fi +fi +]) diff --git a/cf/check-man.m4 b/cf/check-man.m4 index c0c05d737..ad013a4da 100644 --- a/cf/check-man.m4 +++ b/cf/check-man.m4 @@ -11,8 +11,7 @@ AC_CACHE_CHECK(how to format man pages,ac_cv_sys_man_format, .Dt CONFTEST 1 .Sh NAME .Nm conftest -.Nd -foobar +.Nd foobar END if test "$NROFF" ; then @@ -55,4 +54,4 @@ else CATMANEXT=0 fi AC_SUBST(CATMANEXT) -]) \ No newline at end of file +]) diff --git a/cf/check-var.m4 b/cf/check-var.m4 index f81f3524c..71d6f70ca 100644 --- a/cf/check-var.m4 +++ b/cf/check-var.m4 @@ -9,7 +9,8 @@ m4_ifval([$2],[ void * foo(void) { return &$1; }]],[[foo()]])], [ac_cv_var_$1=yes],[ac_cv_var_$1=no])]) if test "$ac_cv_var_$1" != yes ; then -AC_LINK_IFELSE([AC_LANG_PROGRAM([[extern int $1; +AC_LINK_IFELSE([AC_LANG_PROGRAM([[$2 +extern int $1; int foo(void) { return $1; }]],[[foo()]])], [ac_cv_var_$1=yes],[ac_cv_var_$1=no]) fi @@ -19,7 +20,7 @@ AC_MSG_RESULT($ac_foo) if test "$ac_foo" = yes; then AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_[]$1), 1, [Define if you have the `]$1[' variable.]) - m4_ifval([$2], AC_CHECK_DECLS([$1],[],[],[$2])) + m4_ifval([$2], [AC_CHECK_DECLS([$1],[],[],[$2])]) fi ]) diff --git a/cf/check-x.m4 b/cf/check-x.m4 deleted file mode 100644 index 5d8806c4b..000000000 --- a/cf/check-x.m4 +++ /dev/null @@ -1,53 +0,0 @@ -dnl -dnl See if there is any X11 present -dnl -dnl $Id$ - -AC_DEFUN([KRB_CHECK_X],[ -AC_PATH_XTRA - -# try to figure out if we need any additional ld flags, like -R -# and yes, the autoconf X test is utterly broken -if test "$no_x" != yes; then - AC_CACHE_CHECK(for special X linker flags,krb_cv_sys_x_libs_rpath,[ - ac_save_libs="$LIBS" - ac_save_cflags="$CFLAGS" - CFLAGS="$CFLAGS $X_CFLAGS" - krb_cv_sys_x_libs_rpath="" - krb_cv_sys_x_libs="" - for rflag in "" "-R" "-R " "-rpath "; do - if test "$rflag" = ""; then - foo="$X_LIBS" - else - foo="" - for flag in $X_LIBS; do - case $flag in - -L*) - foo="$foo $flag `echo $flag | sed \"s/-L/$rflag/\"`" - ;; - *) - foo="$foo $flag" - ;; - esac - done - fi - LIBS="$ac_save_libs $foo $X_PRE_LIBS -lX11 $X_EXTRA_LIBS" - AC_RUN_IFELSE([ - #include - foo(void) - { - XOpenDisplay(NULL); - } - main(int argc, char **argv) - { - return 0; - } - ],krb_cv_sys_x_libs_rpath="$rflag"; krb_cv_sys_x_libs="$foo"; break,:, - krb_cv_sys_x_libs_rpath="" ; krb_cv_sys_x_libs="" ; break) - done - LIBS="$ac_save_libs" - CFLAGS="$ac_save_cflags" - ]) - X_LIBS="$krb_cv_sys_x_libs" -fi -]) diff --git a/cf/check-xau.m4 b/cf/check-xau.m4 deleted file mode 100644 index f66e2d193..000000000 --- a/cf/check-xau.m4 +++ /dev/null @@ -1,64 +0,0 @@ -dnl $Id$ -dnl -dnl check for Xau{Read,Write}Auth and XauFileName -dnl -AC_DEFUN([AC_CHECK_XAU],[ -save_CFLAGS="$CFLAGS" -CFLAGS="$X_CFLAGS $CFLAGS" -save_LIBS="$LIBS" -dnl LIBS="$X_LIBS $X_PRE_LIBS $X_EXTRA_LIBS $LIBS" -LIBS="$X_PRE_LIBS $X_EXTRA_LIBS $LIBS" -save_LDFLAGS="$LDFLAGS" -LDFLAGS="$LDFLAGS $X_LIBS" - -## check for XauWriteAuth first, so we detect the case where -## XauReadAuth is in -lX11, but XauWriteAuth is only in -lXau this -## could be done by checking for XauReadAuth in -lXau first, but this -## breaks in IRIX 6.5 - -AC_FIND_FUNC_NO_LIBS(XauWriteAuth, X11 Xau,[#include ],[0,0]) -ac_xxx="$LIBS" -LIBS="$LIB_XauWriteAuth $LIBS" -AC_FIND_FUNC_NO_LIBS(XauReadAuth, X11 Xau,[#include ],[0]) -LIBS="$LIB_XauReadAauth $LIBS" -AC_FIND_FUNC_NO_LIBS(XauFileName, X11 Xau,[#include ]) -LIBS="$ac_xxx" - -## set LIB_XauReadAuth to union of these tests, since this is what the -## Makefiles are using -case "$ac_cv_funclib_XauWriteAuth" in -yes) ;; -no) ;; -*) if test "$ac_cv_funclib_XauReadAuth" = yes; then - if test "$ac_cv_funclib_XauFileName" = yes; then - LIB_XauReadAuth="$LIB_XauWriteAuth" - else - LIB_XauReadAuth="$LIB_XauWriteAuth $LIB_XauFileName" - fi - else - if test "$ac_cv_funclib_XauFileName" = yes; then - LIB_XauReadAuth="$LIB_XauReadAuth $LIB_XauWriteAuth" - else - LIB_XauReadAuth="$LIB_XauReadAuth $LIB_XauWriteAuth $LIB_XauFileName" - fi - fi - ;; -esac - -if test "$AUTOMAKE" != ""; then - AM_CONDITIONAL(NEED_WRITEAUTH, test "$ac_cv_func_XauWriteAuth" != "yes") -else - AC_SUBST(NEED_WRITEAUTH_TRUE) - AC_SUBST(NEED_WRITEAUTH_FALSE) - if test "$ac_cv_func_XauWriteAuth" != "yes"; then - NEED_WRITEAUTH_TRUE= - NEED_WRITEAUTH_FALSE='#' - else - NEED_WRITEAUTH_TRUE='#' - NEED_WRITEAUTH_FALSE= - fi -fi -CFLAGS=$save_CFLAGS -LIBS=$save_LIBS -LDFLAGS=$save_LDFLAGS -]) diff --git a/cf/crypto.m4 b/cf/crypto.m4 index 5d965cbfc..0f308ced8 100644 --- a/cf/crypto.m4 +++ b/cf/crypto.m4 @@ -6,17 +6,22 @@ dnl - own-built libhcrypto m4_define([test_headers], [ #undef KRB5 /* makes md4.h et al unhappy */ - #ifdef HAVE_OPENSSL + #ifdef HAVE_HCRYPTO_W_OPENSSL #ifdef HAVE_SYS_TYPES_H #include #endif #include + #include #include #include #include #include #include #include + #include + #include + #include + #include #include #include #include @@ -37,19 +42,20 @@ m4_define([test_headers], [ ]) m4_define([test_body], [ void *schedule = 0; - MD4_CTX md4; - MD5_CTX md5; - SHA_CTX sha1; - SHA256_CTX sha256; + EVP_MD_CTX mdctx; - MD4_Init(&md4); - MD5_Init(&md5); - SHA1_Init(&sha1); - SHA256_Init(&sha256); + EVP_md4(); + EVP_md5(); + EVP_sha1(); + EVP_sha256(); + + EVP_MD_CTX_init(&mdctx); + EVP_DigestInit_ex(&mdctx, EVP_sha1(), (ENGINE *)0); EVP_CIPHER_iv_length(((EVP_CIPHER*)0)); - #ifdef HAVE_OPENSSL - RAND_status(); UI_UTIL_read_pw_string(0,0,0,0); + RAND_status(); + #ifdef HAVE_HCRYPTO_W_OPENSSL + EC_KEY_new(); #endif OpenSSL_add_all_algorithms(); @@ -57,119 +63,118 @@ m4_define([test_body], [ DES_cbc_encrypt(0, 0, 0, schedule, 0, 0); RC4(0, 0, 0, 0);]) - AC_DEFUN([KRB_CRYPTO],[ -crypto_lib=unknown +AC_ARG_WITH([hcrypto-default-backend], + AS_HELP_STRING([--with-hcrypto-default-backend=cc|pkcs11_hcrypto|ossl|w32crypto|hcrypto], + [specify the default hcrypto backend]), + [ + CFLAGS="${CFLAGS} -DHCRYPTO_DEF_PROVIDER=${withval}" + case "$withval" in + cc) AC_DEFINE(HCRYPTO_DEF_PROVIDER, [cc], [Define to one of cc, pkcs11, ossl, w32crypto, or hcrypto to set a default hcrypto provider]);; + pkcs11_hcrypto) AC_DEFINE(HCRYPTO_DEF_PROVIDER, [pkcs11_hcrypto], [Define to one of cc, pkcs11, ossl, w32crypto, or hcrypto to set a default hcrypto provider]);; + ossl) AC_DEFINE(HCRYPTO_DEF_PROVIDER, [ossl], [Define to one of cc, pkcs11, ossl, w32crypto, or hcrypto to set a default hcrypto provider]);; + w32crypto) AC_DEFINE(HCRYPTO_DEF_PROVIDER, [w32crypto], [Define to one of cc, pkcs11, ossl, w32crypto, or hcrypto to set a default hcrypto provider]);; + hcrypto) AC_DEFINE(HCRYPTO_DEF_PROVIDER, [hcrypto], [Define to one of cc, pkcs11, ossl, w32crypto, or hcrypto to set a default hcrypto provider]);; + *) echo "Invalid hcrypto provider name ($withval)"; exit 5;; + esac + ], + []) +AC_ARG_WITH([hcrypto-fallback], + AS_HELP_STRING([--without-hcrypto-fallback], + [disable fallback on hcrypto for unavailable algorithms]), + [AC_DEFINE([HCRYPTO_FALLBACK],0,[Set to 1 to allow fallback to hcrypto for unavailable algorithms])], + [AC_DEFINE([HCRYPTO_FALLBACK],1,[Set to 1 to allow fallback to hcrypto for unavailable algorithms])]) AC_WITH_ALL([openssl]) -DIR_hcrypto= - AC_MSG_CHECKING([for crypto library]) openssl=no -if test "$crypto_lib" = "unknown" -a "$with_krb4" != "no"; then - save_CPPFLAGS="$CPPFLAGS" - save_LIBS="$LIBS" - - cdirs= clibs= - for i in $LIB_krb4; do - case "$i" in - -L*) cdirs="$cdirs $i";; - -l*) clibs="$clibs $i";; - esac - done - - ires= - for i in $INCLUDE_krb4; do - CFLAGS="-DHAVE_OPENSSL $i $save_CFLAGS" - for j in $cdirs; do - for k in $clibs; do - LIBS="$j $k $save_LIBS" - AC_LINK_IFELSE([AC_LANG_PROGRAM([test_headers], - [test_body])], - [openssl=yes ires="$i" lres="$j $k"; break 3]) - done - done - CFLAGS="$i $save_CFLAGS" - for j in $cdirs; do - for k in $clibs; do - LIBS="$j $k $save_LIBS" - AC_LINK_IFELSE([AC_LANG_PROGRAM([test_headers],[test_body])], - [openssl=no ires="$i" lres="$j $k"; break 3]) - done - done - done - - CFLAGS="$save_CFLAGS" - LIBS="$save_LIBS" - if test "$ires" -a "$lres"; then - INCLUDE_hcrypto="$ires" - LIB_hcrypto="$lres" - crypto_lib=krb4 - AC_MSG_RESULT([same as krb4]) - LIB_hcrypto_a='$(LIB_hcrypto)' - LIB_hcrypto_so='$(LIB_hcrypto)' - LIB_hcrypto_appl='$(LIB_hcrypto)' - fi +if test "$with_openssl" = "yes"; then + with_openssl=/usr fi - -if test "$crypto_lib" = "unknown" -a "$with_openssl" != "no"; then - save_CFLAGS="$CFLAGS" - save_LIBS="$LIBS" - INCLUDE_hcrypto= - LIB_hcrypto= +if test "$with_openssl" != "no"; then + saved_CFLAGS="${CFLAGS}" + saved_LDFLAGS="${LDFLAGS}" + INCLUDE_openssl_crypto= + LIB_openssl_crypto= if test "$with_openssl_include" != ""; then - INCLUDE_hcrypto="-I${with_openssl_include}" + INCLUDE_openssl_crypto="-I${with_openssl_include}" + else + INCLUDE_openssl_crypto="-I${with_openssl}/include" fi if test "$with_openssl_lib" != ""; then - LIB_hcrypto="-L${with_openssl_lib}" + LIB_openssl_crypto="-L${with_openssl_lib}" + elif test "${with_openssl}" != "/usr" -a -d "${with_openssl}/lib"; then + LIB_openssl_crypto="-L${with_openssl}/lib" fi - CFLAGS="-DHAVE_OPENSSL ${INCLUDE_hcrypto} ${CFLAGS}" - saved_LIB_hcrypto="$LIB_hcrypto" - for lres in "" "-ldl" "-lnsl -lsocket" "-lnsl -lsocket -ldl"; do - LIB_hcrypto="${saved_LIB_hcrypto} -lcrypto $lres" - LIB_hcrypto_a="$LIB_hcrypto" - LIB_hcrypto_so="$LIB_hcrypto" - LIB_hcrypto_appl="$LIB_hcrypto" - LIBS="${LIBS} ${LIB_hcrypto}" - AC_LINK_IFELSE([AC_LANG_PROGRAM([test_headers],[test_body])], [ - crypto_lib=libcrypto openssl=yes - AC_MSG_RESULT([libcrypto]) - ]) - if test "$crypto_lib" = libcrypto ; then - break; - fi - done - CFLAGS="$save_CFLAGS" - LIBS="$save_LIBS" + CFLAGS="-DHAVE_HCRYPTO_W_OPENSSL ${INCLUDE_openssl_crypto} ${CFLAGS}" + LDFLAGS="${LIB_openssl_crypto} ${LDFLAGS}" + AC_CHECK_LIB([crypto], [OPENSSL_init], + [LIB_openssl_crypto="${LIB_openssl_crypto} -lcrypto"; openssl=yes], [openssl=no], []) + if test "$openssl" = "yes"; then + AC_CHECK_LIB([crypto], + [OSSL_EC_curve_nid2name], + [AC_DEFINE_UNQUOTED([HAVE_OPENSSL_30], 1, + [whether OpenSSL is 3.0 or higher])] + ) + AC_CHECK_HEADERS([openssl/fips.h], + [AC_DEFINE_UNQUOTED([HAVE_OPENSSL_FIPS_H], 1, + [whether openssl/fips.h is available])] + ) + AC_CHECK_LIB([crypto], + [FIPS_mode_set], + [AC_DEFINE_UNQUOTED([HAVE_OPENSSL_FIPS_MODE_SET_API], 1, + [whether FIPS_mode_set API is available])] + ) + fi + # These cases are just for static linking on older OSes, + # presumably. + if test "$openssl" = "no"; then + AC_CHECK_LIB([crypto], [OPENSSL_init], + [LIB_openssl_crypto="${LIB_openssl_crypto} -lcrypto -ldl"; openssl=yes], [openssl=no], [-ldl]) + fi + if test "$openssl" = "no"; then + AC_CHECK_LIB([crypto], [OPENSSL_init], + [LIB_openssl_crypto="${LIB_openssl_crypto} -lcrypto -ldl -lnsl"; openssl=yes], [openssl=no], [-ldl -lnsl]) + fi + if test "$openssl" = "no"; then + AC_CHECK_LIB([crypto], [OPENSSL_init], + [LIB_openssl_crypto="${LIB_openssl_crypto} -lcrypto -ldl -lnsl -lsocket"; openssl=yes], [openssl=no], [-ldl -lnsl -lsocket]) + fi + if test "$openssl" = "no"; then + INCLUDE_openssl_crypto= + LIB_openssl_crypto= + fi + CFLAGS="${saved_CFLAGS}" + LDFLAGS="${saved_LDFLAGS}" fi -if test "$crypto_lib" = "unknown"; then +LIB_hcrypto='$(top_builddir)/lib/hcrypto/libhcrypto.la' +LIB_hcrypto_a='$(top_builddir)/lib/hcrypto/.libs/libhcrypto.a' +LIB_hcrypto_so='$(top_builddir)/lib/hcrypto/.libs/libhcrypto.so' +LIB_hcrypto_appl="-lhcrypto" - DIR_hcrypto='hcrypto' - LIB_hcrypto='$(top_builddir)/lib/hcrypto/libhcrypto.la' - LIB_hcrypto_a='$(top_builddir)/lib/hcrypto/.libs/libhcrypto.a' - LIB_hcrypto_so='$(top_builddir)/lib/hcrypto/.libs/libhcrypto.so' - LIB_hcrypto_appl="-lhcrypto" +AC_MSG_RESULT([included libhcrypto]) - AC_MSG_RESULT([included libhcrypto]) +AC_ARG_WITH(pkcs11-module, + AS_HELP_STRING([--with-pkcs11-module=path], + [use PKCS11 module in path]), + [pkcs11_module="$withval"], + []) -fi - -if test "$with_krb4" != no -a "$crypto_lib" != krb4; then - AC_MSG_ERROR([the crypto library used by krb4 lacks features -required by Kerberos 5; to continue, you need to install a newer -Kerberos 4 or configure --without-krb4]) +if test "$pkcs11_module" != ""; then + AC_DEFINE_UNQUOTED(PKCS11_MODULE_PATH, "$pkcs11_module", [path to PKCS11 module]) + openssl=no fi if test "$openssl" = "yes"; then - AC_DEFINE([HAVE_OPENSSL], 1, [define to use openssl's libcrypto]) + AC_DEFINE([HAVE_HCRYPTO_W_OPENSSL], 1, [define to use openssl's libcrypto as the default backend for libhcrypto]) fi -AM_CONDITIONAL(HAVE_OPENSSL, test "$openssl" = yes)dnl +AM_CONDITIONAL(HAVE_HCRYPTO_W_OPENSSL, test "$openssl" = yes)dnl -AC_SUBST(DIR_hcrypto) -AC_SUBST(INCLUDE_hcrypto) +AC_SUBST(INCLUDE_openssl_crypto) +AC_SUBST(LIB_openssl_crypto) AC_SUBST(LIB_hcrypto) AC_SUBST(LIB_hcrypto_a) AC_SUBST(LIB_hcrypto_so) diff --git a/cf/db.m4 b/cf/db.m4 index 8a6c632eb..c0b4510b6 100644 --- a/cf/db.m4 +++ b/cf/db.m4 @@ -2,34 +2,72 @@ dnl $Id$ dnl dnl tests for various db libraries dnl + AC_DEFUN([rk_DB],[ -AC_ARG_ENABLE(berkeley-db, - AS_HELP_STRING([--disable-berkeley-db], - [if you don't want berkeley db]),[ -]) +AC_ARG_WITH(db-type-preference, + AS_HELP_STRING([--with-db-type-preference=list], + [specify HDB backend DB type preference as whitespace-separated list of db1, db3, lmdb, and/or sqlite]), + [db_type_preference="$withval"], + [db_type_preference="lmdb db3 db1 sqlite"]) +AC_ARG_WITH(berkeley-db, + AS_HELP_STRING([--with-berkeley-db], + [enable support for berkeley db @<:@default=check@:>@]), + [], + [with_berkeley_db=check]) + +dbheader="" +AC_ARG_WITH(berkeley-db-include, + AS_HELP_STRING([--with-berkeley-db-include=dir], + [use berkeley-db headers in dir]), + [dbheader=$withval], + [with_berkeley_db_include=check]) AC_ARG_ENABLE(ndbm-db, AS_HELP_STRING([--disable-ndbm-db], [if you don't want ndbm db]),[ ]) -have_ndbm=no +AC_ARG_ENABLE(mdb-db, + AS_HELP_STRING([--disable-mdb-db], + [if you don't want LMDB]),[ +]) + +have_db1=no +have_db3=no +have_lmdb=no db_type=unknown -if test "$enable_berkeley_db" != no; then +AS_IF([test "x$with_berkeley_db" != xno], + [AS_IF([test "x$with_berkeley_db_include" != xcheck], + [AC_CHECK_HEADERS(["$dbheader/db.h"], + [AC_SUBST([DBHEADER], [$dbheader]) + AC_DEFINE([HAVE_DBHEADER], [1], + [Define if you have user supplied header location]) + ], + [if test "x$with_berkeley_db_include" != xcheck; then + AC_MSG_FAILURE( + [--with-berkeley-db-include was given but include test failed]) + fi + ])], + [AC_CHECK_HEADERS([ \ + db6/db.h \ + db5/db.h \ + db4/db.h \ + db3/db.h \ + db.h \ + ])]) - AC_CHECK_HEADERS([ \ - db4/db.h \ - db3/db.h \ - db.h \ - db_185.h \ - ]) +dnl db_create is used by db3 and db4 and db5 and db6 -dnl db_create is used by db3 and db4 - - AC_FIND_FUNC_NO_LIBS(db_create, db4 db3 db, [ + AC_FIND_FUNC_NO_LIBS(db_create, [$dbheader] db-6 db-5 db4 db3 db, [ #include - #ifdef HAVE_DB4_DB_H + #ifdef HAVE_DBHEADER + #include <$dbheader/db.h> + #elif HAVE_DB6_DB_H + #include + #elif HAVE_DB5_DB_H + #include + #elif HAVE_DB4_DB_H #include #elif defined(HAVE_DB3_DB_H) #include @@ -39,39 +77,36 @@ dnl db_create is used by db3 and db4 ],[NULL, NULL, 0]) if test "$ac_cv_func_db_create" = "yes"; then - db_type=db3 + have_db3=yes if test "$ac_cv_funclib_db_create" != "yes"; then - DBLIB="$ac_cv_funclib_db_create" + DB3LIB="$ac_cv_funclib_db_create" else - DBLIB="" + DB3LIB="" fi - AC_DEFINE(HAVE_DB3, 1, [define if you have a berkeley db3/4 library]) - else + AC_DEFINE(HAVE_DB3, 1, [define if you have a berkeley db3/4/5/6 library]) + fi dnl dbopen is used by db1/db2 - AC_FIND_FUNC_NO_LIBS(dbopen, db2 db, [ - #include - #if defined(HAVE_DB2_DB_H) - #include - #elif defined(HAVE_DB_185_H) - #include - #elif defined(HAVE_DB_H) - #include - #else - #error no db.h - #endif - ],[NULL, 0, 0, 0, NULL]) + AC_FIND_FUNC_NO_LIBS(dbopen, db2 db, [ + #include + #if defined(HAVE_DB2_DB_H) + #include + #elif defined(HAVE_DB_H) + #include + #else + #error no db.h + #endif + ],[NULL, 0, 0, 0, NULL]) - if test "$ac_cv_func_dbopen" = "yes"; then - db_type=db1 - if test "$ac_cv_funclib_dbopen" != "yes"; then - DBLIB="$ac_cv_funclib_dbopen" - else - DBLIB="" - fi - AC_DEFINE(HAVE_DB1, 1, [define if you have a berkeley db1/2 library]) + if test "$ac_cv_func_dbopen" = "yes"; then + have_db1=yes + if test "$ac_cv_funclib_dbopen" != "yes"; then + DB1LIB="$ac_cv_funclib_dbopen" + else + DB1LIB="" fi + AC_DEFINE(HAVE_DB1, 1, [define if you have a berkeley db1/2 library]) fi dnl test for ndbm compatability @@ -86,9 +121,9 @@ dnl test for ndbm compatability if test "$ac_cv_func_dbm_firstkey" = "yes"; then if test "$ac_cv_funclib_dbm_firstkey" != "yes"; then - LIB_NDBM="$ac_cv_funclib_dbm_firstkey" + NDBMLIB="$ac_cv_funclib_dbm_firstkey" else - LIB_NDBM="" + NDBMLIB="" fi AC_DEFINE(HAVE_DB_NDBM, 1, [define if you have ndbm compat in db]) AC_DEFINE(HAVE_NEW_DB, 1, [Define if NDBM really is DB (creates files *.db)]) @@ -98,7 +133,24 @@ dnl test for ndbm compatability fi fi -fi # berkeley db +]) # fi berkeley db + + +AS_IF([test "x$enable_mdb_db" != xno], + [AC_CHECK_HEADER(lmdb.h, [ + AC_CHECK_LIB(lmdb, mdb_env_create, have_lmdb=yes; LMDBLIB="-llmdb" + AC_DEFINE(HAVE_LMDB, 1, [define if you have the LMDB library]))])]) + +for db_type in unknown $db_type_preference; do + if eval test \"x\$have_${db_type}\" = xyes -o ${db_type} = sqlite; then + break + fi + db_type=unknown +done + +AS_IF([test "x$have_db3" = xyes -a "$db_type" = unknown], db_type=db3, db_type="$db_type") +AS_IF([test "x$have_db1" = xyes -a "$db_type" = unknown], db_type=db1, db_type="$db_type") +AS_IF([test "x$have_lmdb" = xyes -a "$db_type" = unknown], db_type=lmdb, db_type="$db_type") if test "$enable_ndbm_db" != "no"; then @@ -121,16 +173,12 @@ if test "$enable_ndbm_db" != "no"; then if test "$ac_cv_func_dbm_firstkey" = "yes"; then if test "$ac_cv_funclib_dbm_firstkey" != "yes"; then - LIB_NDBM="$ac_cv_funclib_dbm_firstkey" + NDBMLIB="$ac_cv_funclib_dbm_firstkey" else - LIB_NDBM="" + NDBMLIB="" fi AC_DEFINE(HAVE_NDBM, 1, [define if you have a ndbm library])dnl have_ndbm=yes - if test "$db_type" = "unknown"; then - db_type=ndbm - DBLIB="$LIB_NDBM" - fi else $as_unset ac_cv_func_dbm_firstkey @@ -148,15 +196,14 @@ if test "$enable_ndbm_db" != "no"; then if test "$ac_cv_func_dbm_firstkey" = "yes"; then if test "$ac_cv_funclib_dbm_firstkey" != "yes"; then - LIB_NDBM="$ac_cv_funclib_dbm_firstkey" + NDBMLIB="$ac_cv_funclib_dbm_firstkey" else - LIB_NDBM="" + NDBMLIB="" fi AC_DEFINE(HAVE_NDBM, 1, [define if you have a ndbm library])dnl have_ndbm=yes if test "$db_type" = "unknown"; then db_type=ndbm - DBLIB="$LIB_NDBM" fi fi fi @@ -190,12 +237,14 @@ int main(int argc, char **argv) AC_DEFINE(HAVE_NEW_DB, 1, [Define if NDBM really is DB (creates files *.db)]) else AC_MSG_RESULT([no]) - fi],[AC_MSG_RESULT([no])]) + fi],[AC_MSG_RESULT([no])],[AC_MSG_RESULT([no-cross])]) fi -AM_CONDITIONAL(HAVE_DB1, test "$db_type" = db1)dnl -AM_CONDITIONAL(HAVE_DB3, test "$db_type" = db3)dnl -AM_CONDITIONAL(HAVE_NDBM, test "$db_type" = ndbm)dnl +AM_CONDITIONAL(HAVE_DB1, test "$have_db1" = yes)dnl +AM_CONDITIONAL(HAVE_DB3, test "$have_db3" = yes)dnl +AM_CONDITIONAL(HAVE_LMDB, test "$have_lmdb" = yes)dnl +AM_CONDITIONAL(HAVE_NDBM, test "$have_ndbm" = yes)dnl +AM_CONDITIONAL(HAVE_DBHEADER, test "$dbheader" != "")dnl ## it's probably not correct to include LDFLAGS here, but we might ## need it, for now just add any possible -L @@ -205,7 +254,15 @@ for i in $LDFLAGS; do -L*) z="$z $i";; esac done -DBLIB="$z $DBLIB" -AC_SUBST(DBLIB)dnl -AC_SUBST(LIB_NDBM)dnl +DB3LIB="$z $DB3LIB" +DB1LIB="$z $DB1LIB" +LMDBLIB="$z $LMDBLIB" +NDMBLIB="$z $NDBMLIB" +AC_SUBST(DB3LIB)dnl +AC_SUBST(DB1LIB)dnl +AC_SUBST(LMDBLIB)dnl +AC_SUBST(NDBMLIB)dnl +AC_SUBST(NDBMLIB)dnl +AC_SUBST(db_type)dnl +AC_SUBST(db_type_preference)dnl ]) diff --git a/cf/dispatch.m4 b/cf/dispatch.m4 new file mode 100644 index 000000000..76c5f47ee --- /dev/null +++ b/cf/dispatch.m4 @@ -0,0 +1,23 @@ + +AC_DEFUN([rk_LIBDISPATCH],[ + +AC_CHECK_PROGS(GCD_MIG, mig, no) + +if test "$GCD_MIG" != no; then + AC_CHECK_HEADERS([dispatch/dispatch.h]) + AC_FIND_FUNC_NO_LIBS(dispatch_async_f, dispatch, + [#ifdef HAVE_DISPATCH_DISPATCH_H + #include + #endif],[0,0,0]) + + if test "$ac_cv_func_dispatch_async_f" = yes -a "$GCD_MIG" != no; then + AC_DEFINE([HAVE_GCD], 1, [Define if os support gcd.]) + libdispatch=yes + else + libdispatch=no + fi + +fi +AM_CONDITIONAL(have_gcd, test "$libdispatch" = yes -a "$GCD_MIG" != no) + +]) diff --git a/cf/dlopen.m4 b/cf/dlopen.m4 index 17e3c6203..1756843fc 100644 --- a/cf/dlopen.m4 +++ b/cf/dlopen.m4 @@ -9,3 +9,11 @@ AC_DEFUN([rk_DLOPEN], [ #endif],[0,0]) AM_CONDITIONAL(HAVE_DLOPEN, test "$ac_cv_funclib_dlopen" != no) ]) + +AC_DEFUN([rk_DLADDR], [ + AC_FIND_FUNC_NO_LIBS(dladdr, dl,[ +#ifdef HAVE_DLFCN_H +#include +#endif],[0,0]) + AM_CONDITIONAL(HAVE_DLADDR, test "$ac_cv_funclib_dladdr" != no) +]) diff --git a/cf/find-func-no-libs2.m4 b/cf/find-func-no-libs2.m4 index 692001c10..a6b3ad6d3 100644 --- a/cf/find-func-no-libs2.m4 +++ b/cf/find-func-no-libs2.m4 @@ -21,7 +21,7 @@ if eval "test \"\$ac_cv_func_$1\" != yes" ; then *) ac_lib="-l$ac_lib" ;; esac LIBS="$6 $ac_lib $5 $ac_save_LIBS" - AC_LINK_IFELSE([AC_LANG_PROGRAM([[$3]],[[$1($4)]])],[eval "if test -n \"$ac_lib\";then ac_cv_funclib_$1=$ac_lib; else ac_cv_funclib_$1=yes; fi";break]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[char $1 (void);]],[[$1()]])],[eval "if test -n \"$ac_lib\";then ac_cv_funclib_$1=$ac_lib; else ac_cv_funclib_$1=yes; fi";break]) done eval "ac_cv_funclib_$1=\${ac_cv_funclib_$1-no}" LIBS="$ac_save_LIBS" @@ -53,7 +53,6 @@ case "$ac_res" in ;; *) eval "ac_cv_func_$1=yes" - eval "ac_cv_lib_`echo "$ac_res" | sed 's/-l//'`=yes" AC_DEFINE_UNQUOTED($ac_tr_func) AC_DEFINE_UNQUOTED($ac_tr_lib) AC_MSG_RESULT([yes, in $ac_res]) diff --git a/cf/framework-corefoundation.m4 b/cf/framework-corefoundation.m4 new file mode 100644 index 000000000..a23c4c748 --- /dev/null +++ b/cf/framework-corefoundation.m4 @@ -0,0 +1,28 @@ +AC_DEFUN([rk_FRAMEWORK_COREFOUNDATION], [ + +AC_MSG_CHECKING([for framework CoreFoundation]) +AC_CACHE_VAL(rk_cv_framework_corefoundation, +[ +if test "$rk_cv_framework_corefoundation" != yes; then + ac_save_LIBS="$LIBS" + LIBS="$ac_save_LIBS -framework CoreFoundation" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include +]], +[[CFURLRef url; +char path[] = "/"; +url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8 *) +path, strlen(path), FALSE); +CFRelease(url); +]])],[rk_cv_framework_corefoundation=yes]) + LIBS="$ac_save_LIBS" +fi +]) + +if test "$rk_cv_framework_corefoundation" = yes; then + AC_DEFINE(HAVE_FRAMEWORK_COREFOUNDATION, 1, [Have -framework CoreFoundation]) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi +AM_CONDITIONAL(FRAMEWORK_COREFOUNDATION, test "$rk_cv_framework_corefoundation" = yes) +]) diff --git a/cf/have-struct-field.m4 b/cf/have-struct-field.m4 index bb7bcefbc..3962d8506 100644 --- a/cf/have-struct-field.m4 +++ b/cf/have-struct-field.m4 @@ -7,7 +7,8 @@ dnl AC_HAVE_STRUCT_FIELD(struct, field, headers) AC_DEFUN([AC_HAVE_STRUCT_FIELD], [ define(cache_val, translit(ac_cv_type_$1_$2, [A-Z ], [a-z_])) AC_CACHE_CHECK([for $2 in $1], cache_val,[ -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[$3]], +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include +$3]], [[$1 x; memset(&x, 0, sizeof(x)); x.$2]])], [cache_val=yes], [cache_val=no]) diff --git a/cf/install-catman.sh b/cf/install-catman.sh index 4f63cb406..f1a258185 100644 --- a/cf/install-catman.sh +++ b/cf/install-catman.sh @@ -14,8 +14,8 @@ catinstall="${INSTALL_CATPAGES-yes}" for f in "$@"; do echo $f - base=`echo "$f" | sed 's/\([^/]*\/\)*\(.*\)\.\([^.]*\)$/\2/'` - section=`echo "$f" | sed 's/\([^/]*\/\)*\(.*\)\.\([^.]*\)$/\3/'` + base=`echo "$f" | sed 's~\.[^.]*$~~; s~.*/~~'` + section=`echo "$f" | sed 's/^[^.]*\.//'` mandir="$manbase/man$section" catdir="$manbase/cat$section" c="$base.cat$section" @@ -48,10 +48,11 @@ for f in "$@"; do fi done if test "$catinstall" = yes -a -f "$srcdir/$c"; then - target="$catdir/$link.$suffix" - for lncmd in "ln -f $catdir/$base.$suffix $target" \ - "ln -fs $base.$suffix $target" \ - "cp -f $catdir/$base.$suffix $target" + eval target="$catdir/$link.$suffix" + eval source="$catdir/$base.$suffix" + for lncmd in "ln -f $source $target" \ + "ln -fs $source $target" \ + "cp -f $catdir/$source $target" do if eval "$lncmd"; then eval echo "$lncmd" diff --git a/cf/irix.m4 b/cf/irix.m4 index 3ffdfbffe..d2b0009a0 100644 --- a/cf/irix.m4 +++ b/cf/irix.m4 @@ -6,21 +6,10 @@ AC_DEFUN([rk_IRIX], [ irix=no case "$host" in -*-*-irix4*) - AC_DEFINE([IRIX4], 1, - [Define if you are running IRIX 4.]) - irix=yes - ;; *-*-irix*) irix=yes ;; esac AM_CONDITIONAL(IRIX, test "$irix" != no)dnl -AH_BOTTOM([ -/* IRIX 4 braindamage */ -#if IRIX == 4 && !defined(__STDC__) -#define __STDC__ 0 -#endif -]) ]) diff --git a/cf/krb-bigendian.m4 b/cf/krb-bigendian.m4 index 62af3ffdf..e8037503f 100644 --- a/cf/krb-bigendian.m4 +++ b/cf/krb-bigendian.m4 @@ -51,7 +51,7 @@ if test "$krb_cv_c_bigendian_compile" = "yes"; then AC_DEFINE(ENDIANESS_IN_SYS_PARAM_H, 1, [define if sys/param.h defines the endiness])dnl fi AH_BOTTOM([ -#if ENDIANESS_IN_SYS_PARAM_H +#ifdef ENDIANESS_IN_SYS_PARAM_H # include # include # if BYTE_ORDER == BIG_ENDIAN diff --git a/cf/krb-func-getcwd-broken.m4 b/cf/krb-func-getcwd-broken.m4 deleted file mode 100644 index 08b079351..000000000 --- a/cf/krb-func-getcwd-broken.m4 +++ /dev/null @@ -1,41 +0,0 @@ -dnl $Id$ -dnl -dnl -dnl test for broken getcwd in (SunOS braindamage) -dnl - -AC_DEFUN([AC_KRB_FUNC_GETCWD_BROKEN], [ -if test "$ac_cv_func_getcwd" = yes; then -AC_MSG_CHECKING(if getcwd is broken) -AC_CACHE_VAL(ac_cv_func_getcwd_broken, [ -ac_cv_func_getcwd_broken=no - -AC_RUN_IFELSE([AC_LANG_SOURCE([[ -#include -char *getcwd(char*, int); - -void *popen(char *cmd, char *mode) -{ - errno = ENOTTY; - return 0; -} - -int main(int argc, char **argv) -{ - char *ret; - ret = getcwd(0, 1024); - if(ret == 0 && errno == ENOTTY) - return 0; - return 1; -} -]])], [ac_cv_func_getcwd_broken=yes],[:],[:]) -]) -if test "$ac_cv_func_getcwd_broken" = yes; then - AC_DEFINE(BROKEN_GETCWD, 1, [Define if getcwd is broken (like in SunOS 4).])dnl - AC_LIBOBJ(getcwd) - AC_MSG_RESULT($ac_cv_func_getcwd_broken) -else - AC_MSG_RESULT([seems ok]) -fi -fi -]) diff --git a/cf/krb-func-getlogin.m4 b/cf/krb-func-getlogin.m4 index 6218e6b1f..8adfddb4a 100644 --- a/cf/krb-func-getlogin.m4 +++ b/cf/krb-func-getlogin.m4 @@ -6,7 +6,7 @@ dnl AC_DEFUN([AC_FUNC_GETLOGIN], [ -AC_CHECK_FUNCS(getlogin setlogin) +AC_CHECK_FUNCS(getlogin getlogin_r setlogin) if test "$ac_cv_func_getlogin" = yes; then AC_CACHE_CHECK(if getlogin is posix, ac_cv_func_getlogin_posix, [ if test "$ac_cv_func_getlogin" = yes -a "$ac_cv_func_setlogin" = yes; then @@ -15,8 +15,18 @@ else ac_cv_func_getlogin_posix=yes fi ]) +AC_CACHE_CHECK(if getlogin_r is posix, ac_cv_func_getlogin_r_posix, [ +if test "$ac_cv_func_getlogin_r" = yes -a "$ac_cv_func_setlogin" = yes; then + ac_cv_func_getlogin_r_posix=no +else + ac_cv_func_getlogin_r_posix=yes +fi +]) if test "$ac_cv_func_getlogin_posix" = yes; then AC_DEFINE(POSIX_GETLOGIN, 1, [Define if getlogin has POSIX flavour (and not BSD).]) fi +if test "$ac_cv_func_getlogin_r_posix" = yes; then + AC_DEFINE(POSIX_GETLOGIN_R, 1, [Define if getlogin_r has POSIX flavour (and not BSD).]) +fi fi ]) diff --git a/cf/krb-prog-perl.m4 b/cf/krb-prog-perl.m4 new file mode 100644 index 000000000..b359111fc --- /dev/null +++ b/cf/krb-prog-perl.m4 @@ -0,0 +1,21 @@ +dnl +dnl perl and some of its module are required to build some headers +dnl + +AC_DEFUN([AC_KRB_PROG_PERL], +[AC_CHECK_PROGS(PERL, perl, perl) +if test "$PERL" = ""; then + AC_MSG_ERROR([perl not found - Cannot build Heimdal without perl]) +fi +]) + +AC_DEFUN([AC_KRB_PERL_MOD], +[ +AC_MSG_CHECKING([for Perl5 module $1]) +if ! $PERL -M$1 -e 'exit(0);' >/dev/null 2>&1; then + AC_MSG_RESULT([no]) + AC_MSG_ERROR([perl module $1 not found - Cannot build Heimdal without perl module $1]) +else + AC_MSG_RESULT([yes]) +fi +]) diff --git a/cf/krb-prog-yacc.m4 b/cf/krb-prog-yacc.m4 index 380412ec7..4c0afd9b7 100644 --- a/cf/krb-prog-yacc.m4 +++ b/cf/krb-prog-yacc.m4 @@ -1,12 +1,18 @@ dnl $Id$ dnl dnl -dnl We prefer byacc or yacc because they do not use `alloca' +dnl OLD: We prefer byacc or yacc because they do not use `alloca' +dnl +dnl CURRENT: We don't mind `alloca', but we do mind `bison -y' because +dnl newer versions of `bison', with `-y' complain about %expect and +dnl anything that yacc didn't document. Because `bison' typically +dnl also installs a `yacc' link that acts like `bison y', we put +dnl `yacc' last in this list. dnl AC_DEFUN([AC_KRB_PROG_YACC], -[AC_CHECK_PROGS(YACC, byacc yacc 'bison -y') +[AC_CHECK_PROGS(YACC, 'bison -d' 'byacc -d' yacc) if test "$YACC" = ""; then - AC_MSG_WARN([yacc not found - some stuff will not build]) + AC_MSG_WARN([byacc and bison not found - some stuff will not build]) fi ]) diff --git a/cf/krb-readline.m4 b/cf/krb-readline.m4 index b5b32feeb..ddb94bf0d 100644 --- a/cf/krb-readline.m4 +++ b/cf/krb-readline.m4 @@ -6,18 +6,6 @@ dnl dnl el_init AC_DEFUN([KRB_READLINE],[ -AC_FIND_FUNC_NO_LIBS(el_init, edit, [], [], [$LIB_tgetent]) -if test "$ac_cv_func_el_init" = yes ; then - AC_CACHE_CHECK(for four argument el_init, ac_cv_func_el_init_four,[ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include - #include ]], - [[el_init("", NULL, NULL, NULL);]])], - [ac_cv_func_el_init_four=yes], - [ac_cv_func_el_init_four=no])]) - if test "$ac_cv_func_el_init_four" = yes; then - AC_DEFINE(HAVE_FOUR_VALUED_EL_INIT, 1, [Define if el_init takes four arguments.]) - fi -fi dnl readline @@ -25,18 +13,15 @@ ac_foo=no build_editline=no if test "$with_readline" = yes; then : +elif test "$with_libedit" = yes; then + LIB_readline="${LIB_libedit}" elif test "$ac_cv_func_readline" = yes; then : -elif test "$ac_cv_func_el_init" = yes; then - ac_foo=yes - build_editline=yes - LIB_readline="\$(top_builddir)/lib/editline/libel_compat.la \$(LIB_el_init) \$(LIB_tgetent)" else - build_editline=yes - LIB_readline="\$(top_builddir)/lib/editline/libeditline.la \$(LIB_tgetent)" + build_libedit=yes + LIB_readline="\$(top_builddir)/lib/libedit/src/libheimedit.la \$(LIB_tgetent)" fi -AM_CONDITIONAL(EDITLINE, test "$build_editline" = yes) -AM_CONDITIONAL(el_compat, test "$ac_foo" = yes) +AM_CONDITIONAL(LIBEDIT, test "$build_libedit" = yes) AC_DEFINE(HAVE_READLINE, 1, [Define if you have a readline compatible library.])dnl diff --git a/cf/krb-version.m4 b/cf/krb-version.m4 deleted file mode 100644 index e196d993d..000000000 --- a/cf/krb-version.m4 +++ /dev/null @@ -1,24 +0,0 @@ -dnl $Id$ -dnl -dnl -dnl output a C header-file with some version strings -dnl - -AC_DEFUN([AC_KRB_VERSION],[ -cat > include/newversion.h.in </dev/null | sed 1q` - Date=`date` - mv -f include/newversion.h.in include/version.h.in - sed -e "s/@USER@/$User/" -e "s/@HOST@/$Host/" -e "s/@DATE@/$Date/" include/version.h.in > include/version.h -fi -]) diff --git a/cf/largefile.m4 b/cf/largefile.m4 index 5c54897be..cdbbc5543 100644 --- a/cf/largefile.m4 +++ b/cf/largefile.m4 @@ -10,7 +10,7 @@ dnl with generated code, such as lex if test "$enable_largefile" != no -a "$ac_cv_sys_large_files" != no; then CPPFLAGS="$CPPFLAGS -D_LARGE_FILES=$ac_cv_sys_large_files" fi -if test "$enable_largefile" != no -a "$ac_cv_sys_file_offset_bits" != no; then +if test "$enable_largefile" != no -a "$ac_cv_sys_file_offset_bits" != no && test -n "$ac_cv_sys_file_offset_bits"; then CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=$ac_cv_sys_file_offset_bits" fi ]) diff --git a/cf/make-proto.pl b/cf/make-proto.pl index 04733e128..21f341c0f 100644 --- a/cf/make-proto.pl +++ b/cf/make-proto.pl @@ -1,18 +1,32 @@ # Make prototypes from .c files # $Id$ -##use Getopt::Std; -require 'getopts.pl'; +use Getopt::Std; +use File::Compare; my $comment = 0; +my $doxygen = 0; +my $funcdoc = 0; my $if_0 = 0; my $brace = 0; my $line = ""; my $debug = 0; my $oproto = 1; my $private_func_re = "^_"; +my %depfunction; +my %exported; +my %deprecated; +my $apple = 0; +my %documentation; -do Getopts('x:m:o:p:dqE:R:P:') || die "foo"; +getopts('x:m:o:p:dqE:R:P:') || die "foo"; +if($opt_a) { + $apple = 1; +} + +if($opt_a) { + $apple = 1; +} if($opt_d) { $debug = 1; @@ -25,7 +39,7 @@ if($opt_q) { if($opt_R) { $private_func_re = $opt_R; } -%flags = ( +my %flags = ( 'multiline-proto' => 1, 'header' => 1, 'function-blocking' => 0, @@ -51,18 +65,22 @@ if($opt_m) { } if($opt_x) { - open(EXP, $opt_x); - while() { - chomp; - s/\#.*//g; - s/\s+/ /g; - if(/^([a-zA-Z0-9_]+)\s?(.*)$/) { - $exported{$1} = $2; - } else { - print $_, "\n"; + require JSON::PP; + + my $EXP; + local $/; + open(EXP, '<', $opt_x) || die "open ${opt_x}"; + my $obj = JSON::PP->new->utf8->decode(); + close $EXP; + + foreach my $x (keys %$obj) { + if (defined $obj->{$x}->{"export"}) { + $exported{$x} = $obj->{$x}; + } + if (defined $obj->{$x}->{"deprecated"}) { + $deprecated{$x} = $obj->{$x}->{"deprecated"}; } } - close EXP; } while(<>) { @@ -71,10 +89,19 @@ while(<>) { # Handle C comments s@/\*.*\*/@@; s@//.*/@@; - if ( s@/\*.*@@) { $comment = 1; - } elsif ($comment && s@.*\*/@@) { $comment = 0; + if ( s@/\*\*(.*)@@) { $comment = 1; $doxygen = 1; $funcdoc = $1; + } elsif ( s@/\*.*@@) { $comment = 1; + } elsif ($comment && s@.*\*/@@) { $comment = 0; $doxygen = 0; + } elsif ($doxygen) { $funcdoc .= $_; next; } elsif ($comment) { next; } + # Handle CPP #define's + $define = 1 if /^\s*\#\s*define/; + if ($define) { + $define = 0 if ! /\\$/; + next; + } + if(/^\#if 0/) { $if_0 = 1; } @@ -100,16 +127,25 @@ while(<>) { s/^\s*//; s/\s*$//; s/\s+/ /g; - if($_ =~ /\)$/ or $_ =~ /DEPRECATED$/){ + if($_ =~ /\)$/){ if(!/^static/ && !/^PRIVATE/){ $attr = ""; if(m/(.*)(__attribute__\s?\(.*\))/) { $attr .= " $2"; $_ = $1; } - if(m/(.*)\s(\w+DEPRECATED)/) { + if(m/(.*)\s(\w+DEPRECATED_FUNCTION)\s?(\(.*\))(.*)/) { + $depfunction{$2} = 1; + $attr .= " $2$3"; + $_ = "$1 $4"; + } + if(m/(.*)\s(\w+DEPRECATED)(.*)/) { $attr .= " $2"; - $_ = $1; + $_ = "$1 $3"; + } + if(m/(.*)\s(HEIMDAL_\w+_ATTRIBUTE)\s?(\(.*\))?(.*)/) { + $attr .= " $2$3"; + $_ = "$1 $4"; } # remove outer () s/\s*\(/) { if($attr ne "") { $_ .= "\n $attr"; } + if ($funcdoc) { + $documentation{$f} = $funcdoc; + } + $funcdoc = undef; + if ($apple && exists $exported{$f}) { + $ios = $exported{$f}{ios}; + $ios = "NA" if (!defined $ios); + $mac = $exported{$f}{macos}; + $mac = "NA" if (!defined $mac); + die "$f neither" if ($mac eq "NA" and $ios eq "NA"); + $_ = $_ . " __OSX_AVAILABLE_STARTING(__MAC_${mac}, __IPHONE_${ios})"; + } + if (exists $deprecated{$f}) { + $_ = $_ . " GSSAPI_DEPRECATED_FUNCTION(\"$deprecated{$f}\")"; + $depfunction{GSSAPI_DEPRECATED_FUNCTION} = 1; + } $_ = $_ . ";"; $funcs{$f} = $_; } @@ -176,23 +228,27 @@ while(<>) { } } +die "reached end of code and still in doxygen comment" if ($doxygen); +die "reached end of code and still in comment" if ($comment); + sub foo { local ($arg) = @_; $_ = $arg; s/.*\/([^\/]*)/$1/; + s/.*\\([^\\]*)/$1/; s/[^a-zA-Z0-9]/_/g; "__" . $_ . "__"; } if($opt_o) { - open(OUT, ">$opt_o"); + open(OUT, ">${opt_o}.new"); $block = &foo($opt_o); } else { $block = "__public_h__"; } if($opt_p) { - open(PRIV, ">$opt_p"); + open(PRIV, ">${opt_p}.new"); $private = &foo($opt_p); } else { $private = "__private_h__"; @@ -204,6 +260,7 @@ $private_h = ""; $public_h_header .= "/* This is a generated file */ #ifndef $block #define $block +#ifndef DOXY "; if ($oproto) { @@ -251,14 +308,32 @@ if($oproto) { } $private_h_trailer = ""; + foreach(sort keys %funcs){ - if(/^(main)$/) { next } - if(!defined($exported{$_}) && /$private_func_re/) { - $private_h .= $funcs{$_} . "\n\n"; + if(/^(DllMain|main)$/) { next } + if ($funcs{$_} =~ /\^/) { + $beginblock = "#ifdef __BLOCKS__\n"; + $endblock = "#endif /* __BLOCKS__ */\n"; + } else { + $beginblock = $endblock = ""; + } + # if we have an export table and doesn't have content, or matches private RE + if((scalar(keys(%exported)) ne 0 && !exists $exported{$_} ) || /$private_func_re/) { + $private_h .= $beginblock; +# if ($apple and not /$private_func_re/) { +# $private_h .= "#define $_ __ApplePrivate_${_}\n"; +# } + $private_h .= $funcs{$_} . "\n" ; + $private_h .= $endblock . "\n"; if($funcs{$_} =~ /__attribute__/) { $private_attribute_seen = 1; } } else { + if($documentation{$_}) { + $public_h .= "/**\n"; + $public_h .= "$documentation{$_}"; + $public_h .= " */\n\n"; + } if($flags{"function-blocking"}) { $fupper = uc $_; if($exported{$_} =~ /proto/) { @@ -267,7 +342,7 @@ foreach(sort keys %funcs){ $public_h .= "#ifndef HAVE_$fupper\n"; } } - $public_h .= $funcs{$_} . "\n"; + $public_h .= $beginblock . $funcs{$_} . "\n" . $endblock; if($funcs{$_} =~ /__attribute__/) { $public_attribute_seen = 1; } @@ -295,48 +370,128 @@ if($flags{"gnuc-attribute"}) { "; } } + +my $depstr = ""; +my $undepstr = ""; +foreach (keys %depfunction) { + $depstr .= "#ifndef $_ +#ifndef __has_extension +#define __has_extension(x) 0 +#define ${_}has_extension 1 +#endif +#if __has_extension(attribute_deprecated_with_message) +#define $_(x) __attribute__((__deprecated__(x))) +#elif defined(__GNUC__) && ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1 ))) +#define $_(X) __attribute__((__deprecated__)) +#else +#define $_(X) +#endif +#ifdef ${_}has_extension +#undef __has_extension +#undef ${_}has_extension +#endif +#endif /* $_ */ + + +"; + $public_h_trailer .= "#undef $_ + +"; + $private_h_trailer .= "#undef $_ +#define $_(X) + +"; +} + +$public_h_header .= $depstr; +$private_h_header .= $depstr; + + if($flags{"cxx"}) { $public_h_header .= "#ifdef __cplusplus extern \"C\" { #endif "; - $public_h_trailer .= "#ifdef __cplusplus + $public_h_trailer = "#ifdef __cplusplus } #endif -"; +" . $public_h_trailer; } if ($opt_E) { $public_h_header .= "#ifndef $opt_E -#if defined(_WIN32) -#define ${opt_E}_FUNCTION __stdcall __declspec(dllimport) -#define ${opt_E}_VARIABLE __declspec(dllimport) -#else -#define ${opt_E}_FUNCTION -#define ${opt_E}_VARIABLE + #ifndef ${opt_E}_FUNCTION + #if defined(_WIN32) + #define ${opt_E}_FUNCTION __declspec(dllimport) + #else + #define ${opt_E}_FUNCTION + #endif + #endif + #ifndef ${opt_E}_NORETURN_FUNCTION + #if defined(_WIN32) + #define ${opt_E}_NORETURN_FUNCTION __declspec(dllimport noreturn) + #else + #define ${opt_E}_NORETURN_FUNCTION + #endif + #endif + #ifndef ${opt_E}_CALL + #if defined(_WIN32) + #define ${opt_E}_CALL __stdcall + #else + #define ${opt_E}_CALL + #endif + #endif + #ifndef ${opt_E}_VARIABLE + #if defined(_WIN32) + #define ${opt_E}_VARIABLE __declspec(dllimport) + #else + #define ${opt_E}_VARIABLE + #endif + #endif #endif -#endif - "; $private_h_header .= "#ifndef $opt_E -#if defined(_WIN32) -#define ${opt_E}_FUNCTION __stdcall __declspec(dllimport) -#define ${opt_E}_VARIABLE __declspec(dllimport) -#else -#define ${opt_E}_FUNCTION -#define ${opt_E}_VARIABLE + #ifndef ${opt_E}_FUNCTION + #if defined(_WIN32) + #define ${opt_E}_FUNCTION __declspec(dllimport) + #else + #define ${opt_E}_FUNCTION + #endif + #endif + #ifndef ${opt_E}_NORETURN_FUNCTION + #if defined(_WIN32) + #define ${opt_E}_NORETURN_FUNCTION __declspec(dllimport noreturn) + #else + #define ${opt_E}_NORETURN_FUNCTION + #endif + #endif + #ifndef ${opt_E}_CALL + #if defined(_WIN32) + #define ${opt_E}_CALL __stdcall + #else + #define ${opt_E}_CALL + #endif + #endif + #ifndef ${opt_E}_VARIABLE + #if defined(_WIN32) + #define ${opt_E}_VARIABLE __declspec(dllimport) + #else + #define ${opt_E}_VARIABLE + #endif + #endif #endif -#endif - "; } +$public_h_trailer .= $undepstr; +$private_h_trailer .= $undepstr; + if ($public_h ne "" && $flags{"header"}) { $public_h = $public_h_header . $public_h . - $public_h_trailer . "#endif /* $block */\n"; + $public_h_trailer . "#endif /* DOXY */\n#endif /* $block */\n"; } if ($private_h ne "" && $flags{"header"}) { $private_h = $private_h_header . $private_h . @@ -352,3 +507,22 @@ if($opt_p) { close OUT; close PRIV; + +if ($opt_o) { + + if (compare("${opt_o}.new", ${opt_o}) != 0) { + printf("updating ${opt_o}\n"); + rename("${opt_o}.new", ${opt_o}); + } else { + unlink("${opt_o}.new"); + } +} + +if ($opt_p) { + if (compare("${opt_p}.new", ${opt_p}) != 0) { + printf("updating ${opt_p}\n"); + rename("${opt_p}.new", ${opt_p}); + } else { + unlink("${opt_p}.new"); + } +} diff --git a/lib/auth/sia/krb4_matrix.conf b/cf/maybe-valgrind.sh old mode 100644 new mode 100755 similarity index 59% rename from lib/auth/sia/krb4_matrix.conf rename to cf/maybe-valgrind.sh index 1e2ab9edf..5e20d98a8 --- a/lib/auth/sia/krb4_matrix.conf +++ b/cf/maybe-valgrind.sh @@ -1,4 +1,6 @@ -# Copyright (c) 1998 Kungliga Tekniska Högskolan +#!/bin/sh +# +# Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan # (Royal Institute of Technology, Stockholm, Sweden). # All rights reserved. # @@ -29,31 +31,38 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. -# $Id$ -# sia matrix configuration file (Kerberos 4 + BSD) +while true +do + case $1 in + -s) tsrcdir="$2"; shift 2;; + -o) tobjdir="$2"; shift 2;; + -*) echo "$0: Bad option $1"; echo $usage; exit 1;; + *) break;; + esac +done -siad_init=(KRB4,/usr/athena/lib/libsia_krb4.so)(BSD,libc.so) -siad_chk_invoker=(BSD,libc.so) -siad_ses_init=(KRB4,/usr/athena/lib/libsia_krb4.so) -siad_ses_authent=(KRB4,/usr/athena/lib/libsia_krb4.so)(BSD,libc.so) -siad_ses_estab=(BSD,libc.so) -siad_ses_launch=(KRB4,/usr/athena/lib/libsia_krb4.so)(BSD,libc.so) -siad_ses_suauthent=(KRB4,/usr/athena/lib/libsia_krb4.so)(BSD,libc.so) -siad_ses_reauthent=(KRB4,/usr/athena/lib/libsia_krb4.so)(BSD,libc.so) -siad_chg_finger=(BSD,libc.so) -siad_chg_password=(KRB4,/usr/athena/lib/libsia_krb4.so)(BSD,libc.so) -siad_chg_shell=(BSD,libc.so) -siad_getpwent=(BSD,libc.so) -siad_getpwuid=(BSD,libc.so) -siad_getpwnam=(BSD,libc.so) -siad_setpwent=(BSD,libc.so) -siad_endpwent=(BSD,libc.so) -siad_getgrent=(BSD,libc.so) -siad_getgrgid=(BSD,libc.so) -siad_getgrnam=(BSD,libc.so) -siad_setgrent=(BSD,libc.so) -siad_endgrent=(BSD,libc.so) -siad_ses_release=(KRB4,/usr/athena/lib/libsia_krb4.so)(BSD,libc.so) -siad_chk_user=(KRB4,/usr/athena/lib/libsia_krb4.so)(BSD,libc.so) +if [ X"${tobjdir}" = "X" -o X"${tsrcdir}" = X ] ; then + echo "tobjdir or tsrcdir not defined" + exit 1 +fi +if [ ! -f "${tobjdir}/libtool" ]; then + echo "libtool missing from \"${tobjdir}\"" + exit 1 +fi + +doit=1 + +libtool="${tobjdir}/libtool --mode=execute" + +valgrind="valgrind --leak-check=full --quiet -q --num-callers=30 --suppressions=${tsrcdir}/cf/valgrind-suppressions" + +if head -10 "$1" | grep 'Generated by ltmain.sh' > /dev/null ; then + uselibtool=1 +elif head -10 "$1" | grep 'bin/sh' > /dev/null ; then + libtool= + valgrind= +fi + +exec $libtool $valgrind "$@" diff --git a/cf/pkg.m4 b/cf/pkg.m4 new file mode 100644 index 000000000..8cdc5e416 --- /dev/null +++ b/cf/pkg.m4 @@ -0,0 +1,157 @@ +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# +# Copyright 2004 Scott James Remnant . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# PKG_PROG_PKG_CONFIG([MIN-VERSION]) +# ---------------------------------- +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_PATH)?$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi + +fi[]dnl +])# PKG_PROG_PKG_CONFIG + +# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# Check to see whether a particular set of modules exists. Similar +# to PKG_CHECK_MODULES(), but does not set variables or print errors. +# +# +# Similar to PKG_CHECK_MODULES, make sure that the first instance of +# this or PKG_CHECK_MODULES is called, or make sure to call +# PKG_CHECK_EXISTS manually +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_ifval([$2], [$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + + +# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +# --------------------------------------------- +m4_define([_PKG_CONFIG], +[if test -n "$PKG_CONFIG"; then + if test -n "$$1"; then + pkg_cv_[]$1="$$1" + else + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], + [pkg_failed=yes]) + fi +else + pkg_failed=untried +fi[]dnl +])# _PKG_CONFIG + +# _PKG_SHORT_ERRORS_SUPPORTED +# ----------------------------- +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])# _PKG_SHORT_ERRORS_SUPPORTED + + +# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +# [ACTION-IF-NOT-FOUND]) +# +# +# Note that if there is a possibility the first call to +# PKG_CHECK_MODULES might not happen, you should be sure to include an +# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +# +# +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + ifelse([$4], , [AC_MSG_ERROR(dnl +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT +])], + [AC_MSG_RESULT([no]) + $4]) +elif test $pkg_failed = untried; then + ifelse([$4], , [AC_MSG_FAILURE(dnl +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see .])], + [$4]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + ifelse([$3], , :, [$3]) +fi[]dnl +])# PKG_CHECK_MODULES diff --git a/cf/pthreads.m4 b/cf/pthreads.m4 index f08a9fe1f..4d8439585 100644 --- a/cf/pthreads.m4 +++ b/cf/pthreads.m4 @@ -12,53 +12,73 @@ case "$host" in *-*-solaris2*) native_pthread_support=yes if test "$GCC" = yes; then - PTHREADS_CFLAGS=-pthreads - PTHREADS_LIBS=-pthreads + PTHREAD_CFLAGS="-D_REENTRANT -D_TS_ERRNO" + PTHREAD_LIBADD=-lpthread else - PTHREADS_CFLAGS=-mt - PTHREADS_LIBS=-mt + PTHREAD_CFLAGS="-mt -D_REENTRANT -D_TS_ERRNO" + PTHREAD_LDADD=-mt + PTHREAD_LIBADD="-mt -lpthread" fi ;; -*-*-netbsd[12]*) +*-*-netbsd[[12]]*) native_pthread_support="if running netbsd 1.6T or newer" dnl heim_threads.h knows this - PTHREADS_LIBS="-lpthread" + PTHREAD_LIBADD="-lpthread" ;; -*-*-netbsd[3456789]*) +*-*-netbsd[[3456789]]*) native_pthread_support="netbsd 3 uses explict pthread" dnl heim_threads.h knows this - PTHREADS_LIBS="-lpthread" + PTHREAD_LIBADD="-lpthread" ;; -*-*-freebsd5*) +*-*-freebsd[[1234]]) + ;; +*-*-freebsd*) native_pthread_support=yes + PTHREAD_LIBADD="-pthread" ;; *-*-openbsd*) + native_pthread_support=yes + PTHREAD_CFLAGS=-pthread + PTHREAD_LIBADD=-pthread + ;; +*-*-gnu*) native_pthread_support=yes PTHREADS_CFLAGS=-pthread - PTHREADS_LIBS=-pthread + PTHREAD_LIBADD="-pthread -lpthread" ;; *-*-linux* | *-*-linux-gnu) case `uname -r` in - 2.*) + 2.*|3.*) native_pthread_support=yes - PTHREADS_CFLAGS=-pthread - PTHREADS_LIBS=-pthread + PTHREAD_CFLAGS=-pthread + PTHREAD_LIBADD=-pthread ;; esac ;; *-*-kfreebsd*-gnu*) native_pthread_support=yes - PTHREADS_CFLAGS=-pthread - PTHREADS_LIBS=-pthread + PTHREAD_CFLAGS=-pthread + PTHREAD_LIBADD=-pthread ;; *-*-aix*) dnl AIX is disabled since we don't handle the utmp/utmpx dnl problems that aix causes when compiling with pthread support + dnl (2016-11-14, we longer use utmp). Original logic was: + dnl if test "$GCC" = yes; then + dnl native_pthread_support=yes + dnl PTHREADS_LIBS="-pthread" + dnl elif expr "$CC" : ".*_r" > /dev/null ; then + dnl native_pthread_support=yes + dnl PTHREADS_CFLAGS="" + dnl PTHREADS_LIBS="" + dnl else + dnl native_pthread_support=no + dnl fi native_pthread_support=no ;; mips-sgi-irix6.[[5-9]]) # maybe works for earlier versions too native_pthread_support=yes - PTHREADS_LIBS="-lpthread" + PTHREAD_LIBADD="-lpthread" ;; *-*-darwin*) native_pthread_support=yes @@ -77,14 +97,21 @@ if test "$enable_pthread_support" != no; then [Define if you want have a thread safe libraries]) dnl This sucks, but libtool doesn't save the depenecy on -pthread dnl for libraries. - LIBS="$PTHREADS_LIBS $LIBS" + LIBS="$PTHREAD_LIBADD $LIBS" else - PTHREADS_CFLAGS="" - PTHREADS_LIBS="" + PTHREAD_CFLAGS="" + PTHREAD_LIBADD="" fi -AC_SUBST(PTHREADS_CFLAGS) -AC_SUBST(PTHREADS_LIBS) +AM_CONDITIONAL(ENABLE_PTHREAD_SUPPORT, test "$enable_pthread_support" != no) + +CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +LDADD="$LDADD $PTHREAD_LDADD" +LIBADD="$LIBADD $PTHREAD_LIBADD" + +AC_SUBST(PTHREAD_CFLAGS) +AC_SUBST(PTHREAD_LDADD) +AC_SUBST(PTHREAD_LIBADD) AC_MSG_RESULT($enable_pthread_support) ]) diff --git a/cf/resolv.m4 b/cf/resolv.m4 index 49c868ab0..629497275 100644 --- a/cf/resolv.m4 +++ b/cf/resolv.m4 @@ -73,13 +73,13 @@ AC_FIND_FUNC(res_ndestroy, resolv, ], [0]) -AC_FIND_FUNC_NO_LIBS(dns_search,, +AC_FIND_FUNC(dns_search, resolv, [ #ifdef HAVE_DNS_H #include #endif ], -[0,0,0,0,0,0,0,0]) +[0]) AC_FIND_FUNC(dn_expand, resolv, diff --git a/cf/retsigtype.m4 b/cf/retsigtype.m4 index cd60bda24..5dfd82092 100644 --- a/cf/retsigtype.m4 +++ b/cf/retsigtype.m4 @@ -9,7 +9,7 @@ AC_TYPE_SIGNAL if test "$ac_cv_type_signal" = "void" ; then AC_DEFINE(VOID_RETSIGTYPE, 1, [Define if signal handlers return void.]) fi -AC_SUBST(VOID_RETSIGTYPE) + AH_BOTTOM([#ifdef VOID_RETSIGTYPE #define SIGRETURN(x) return #else diff --git a/cf/roken-frag.m4 b/cf/roken-frag.m4 index eb3a29e6a..90e514c20 100644 --- a/cf/roken-frag.m4 +++ b/cf/roken-frag.m4 @@ -17,16 +17,21 @@ AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_PROG_AWK]) AC_REQUIRE([AC_OBJEXT]) AC_REQUIRE([AC_EXEEXT]) -AC_REQUIRE([AC_PROG_LIBTOOL]) +AC_REQUIRE([LT_INIT]) AC_REQUIRE([AC_MIPS_ABI]) +AC_DEFINE(rk_PATH_DELIM, '/', [Path name delimiter]) + dnl C characteristics AC_REQUIRE([AC_C___ATTRIBUTE__]) AC_REQUIRE([AC_C_INLINE]) AC_REQUIRE([AC_C_CONST]) -rk_WFLAGS(-Wall -Wmissing-prototypes -Wpointer-arith -Wbad-function-cast -Wmissing-declarations -Wnested-externs) +rk_WFLAGS(-Wall -Wextra -Wno-sign-compare -Wno-unused-parameter -Wmissing-prototypes -Wpointer-arith -Wbad-function-cast -Wmissing-declarations -Wnested-externs -Wshadow) + +dnl -Wmissing-prototypes -Wpointer-arith -Wreturn-type -Wstrict-prototypes +dnl -Wcast-qual -Wswitch -Wformat=2 -Wwrite-strings AC_REQUIRE([rk_DB]) @@ -45,6 +50,7 @@ AC_REQUIRE([AC_HEADER_STDC]) AC_REQUIRE([AC_HEADER_TIME]) AC_CHECK_HEADERS([\ + auxv.h \ arpa/inet.h \ config.h \ crypt.h \ @@ -63,9 +69,13 @@ AC_CHECK_HEADERS([\ poll.h \ pwd.h \ rpcsvc/ypclnt.h \ + search.h \ shadow.h \ stdint.h \ + sys/auxv.h \ sys/bswap.h \ + sys/errno.h \ + sys/exec_elf.h \ sys/ioctl.h \ sys/mman.h \ sys/param.h \ @@ -80,12 +90,22 @@ AC_CHECK_HEADERS([\ sys/wait.h \ syslog.h \ termios.h \ + winsock2.h \ + ws2tcpip.h \ unistd.h \ userconf.h \ usersec.h \ util.h \ ]) +AC_HAVE_TYPE([auxv_t],[#ifdef HAVE_AUXV_H +#include +#endif +#ifdef HAVE_SYS_AUXV_H +#include +#endif +]) + AC_HAVE_TYPE([uintptr_t],[#ifdef HAVE_STDINT_H #include #endif]) @@ -145,14 +165,11 @@ AC_REQUIRE([CHECK_NETINET_IP_AND_TCP]) AM_CONDITIONAL(have_err_h, test "$ac_cv_header_err_h" = yes) AM_CONDITIONAL(have_ifaddrs_h, test "$ac_cv_header_ifaddrs_h" = yes) +AM_CONDITIONAL(have_search_h, test "$ac_cv_header_search_h" = yes) AM_CONDITIONAL(have_vis_h, test "$ac_cv_header_vis_h" = yes) dnl Check for functions and libraries -AC_FIND_FUNC(socket, socket) -AC_FIND_FUNC(gethostbyname, nsl) -AC_FIND_FUNC(syslog, syslog) - AC_KRB_IPV6 AC_FIND_FUNC(gethostbyname2, inet6 ip6) @@ -162,48 +179,42 @@ rk_RESOLV AC_BROKEN_SNPRINTF AC_BROKEN_VSNPRINTF -AC_BROKEN_GLOB -if test "$ac_cv_func_glob_working" != yes; then - AC_LIBOBJ(glob) -fi -AM_CONDITIONAL(have_glob_h, test "$ac_cv_func_glob_working" = yes) - - AC_CHECK_FUNCS([ \ asnprintf \ asprintf \ atexit \ - cgetent \ + getauxval \ getconfattr \ getprogname \ getrlimit \ - getspnam \ - initstate \ issetugid \ + memmem \ + mkdtemp \ + mkostemp \ on_exit \ poll \ random \ + secure_getenv \ setprogname \ - setstate \ strsvis \ + strsvisx \ strunvis \ strvis \ strvisx \ svis \ sysconf \ sysctl \ + tdelete \ + tfind \ + twalk \ uname \ + unlinkat \ unvis \ vasnprintf \ vasprintf \ vis \ ]) -if test "$ac_cv_func_cgetent" = no; then - AC_LIBOBJ(getcap) -fi -AM_CONDITIONAL(have_cgetent, test "$ac_cv_func_cgetent" = yes) - AC_REQUIRE([AC_FUNC_GETLOGIN]) AC_REQUIRE([AC_FUNC_MMAP]) @@ -258,6 +269,14 @@ AC_FIND_FUNC_NO_LIBS(bswap32,, #include #endif],0) +AC_FIND_FUNC_NO_LIBS(bswap64,, +[#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_BSWAP_H +#include +#endif],0) + AC_FIND_FUNC_NO_LIBS(pidfile,util, [#ifdef HAVE_UTIL_H #include @@ -266,35 +285,44 @@ AC_FIND_FUNC_NO_LIBS(pidfile,util, AC_FIND_IF_NOT_BROKEN(getaddrinfo,, [#ifdef HAVE_NETDB_H #include +#endif +#ifdef HAVE_WS2TCPIP_H +#include #endif],[0,0,0,0]) AC_FIND_IF_NOT_BROKEN(getnameinfo,, [#ifdef HAVE_NETDB_H #include +#endif +#ifdef HAVE_WS2TCPIP_H +#include #endif],[0,0,0,0,0,0,0]) AC_FIND_IF_NOT_BROKEN(freeaddrinfo,, [#ifdef HAVE_NETDB_H #include +#endif +#ifdef HAVE_WS2TCPIP_H +#include #endif],[0]) AC_FIND_IF_NOT_BROKEN(gai_strerror,, [#ifdef HAVE_NETDB_H #include +#endif +#ifdef HAVE_WS2TCPIP_H +#include #endif],[0]) -dnl Darwin is weird, and in some senses not unix, launchd doesn't want -dnl servers to use daemon(), so its deprecated. +AC_CHECK_LIB(util, emalloc) + case "$host_os" in darwin*) ;; *) - AC_DEFINE([SUPPORT_DETACH], 1, - [Define if os support want to detach is daemonens.]) AC_BROKEN([daemon]) ;; esac - AC_BROKEN([ \ chown \ copyhostent \ @@ -324,10 +352,12 @@ AC_BROKEN([ \ getusershell \ initgroups \ innetgr \ - iruserok \ localtime_r \ lstat \ memmove \ + memset_s \ + mergesort \ + mergesort_r \ mkstemp \ putenv \ rcmd \ @@ -351,8 +381,11 @@ AC_BROKEN([ \ strsep \ strsep_copy \ strtok_r \ + strtoll \ + strtoull \ strupr \ swab \ + tsearch \ timegm \ unsetenv \ verr \ @@ -365,17 +398,50 @@ AC_BROKEN([ \ writev \ ]) +rk_LIBOBJ(closefrom) + AM_CONDITIONAL(have_fnmatch_h, test "$ac_cv_header_fnmatch_h" = yes -a "$ac_cv_func_fnmatch" = yes) AC_FOREACH([rk_func], [strndup strsep strtok_r], [AC_NEED_PROTO([#include ], rk_func)]) -AC_FOREACH([rk_func], [strsvis strunvis strvis strvisx svis unvis vis], +AC_CHECK_FUNC([strtoll], + [AC_DEFINE_UNQUOTED(HAVE_STRTOLL, 1, + [Define if you have the function strtoll.])]) + +AC_CHECK_FUNC([strtoull], + [AC_DEFINE_UNQUOTED(HAVE_STRTOULL, 1, + [Define if you have the function strtoull.])]) + +AC_FOREACH([rk_func], [strsvis strsvisx strunvis strvis strvisx svis unvis vis], [AC_NEED_PROTO([#ifdef HAVE_VIS_H #include #endif], rk_func)]) +AC_MSG_CHECKING([checking for dirfd]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include +#ifdef HAVE_DIRENT_H +#include +#endif +]], + [[DIR *d = 0; dirfd(d);]])], + [ac_rk_have_dirfd=yes], [ac_rk_have_dirfd=no]) +if test "$ac_rk_have_dirfd" = "yes" ; then + AC_DEFINE_UNQUOTED(HAVE_DIRFD, 1, [have a dirfd function/macro]) +fi +AC_MSG_RESULT($ac_rk_have_dirfd) + +AC_HAVE_STRUCT_FIELD(DIR, dd_fd, [#include +#ifdef HAVE_DIRENT_H +#include +#endif]) + +AC_HAVE_STRUCT_FIELD(DIR, d_fd, [#include +#ifdef HAVE_DIRENT_H +#include +#endif]) + AC_BROKEN2(inet_aton, [#ifdef HAVE_SYS_TYPES_H #include @@ -428,13 +494,13 @@ dnl AC_HAVE_STRUCT_FIELD(struct sockaddr, sa_len, [#include #include ]) -if test "$ac_cv_func_getaddrinfo" = "yes"; then - rk_BROKEN_GETADDRINFO - if test "$ac_cv_func_getaddrinfo_numserv" = no; then - AC_LIBOBJ(getaddrinfo) - AC_LIBOBJ(freeaddrinfo) - fi -fi +#if test "$ac_cv_func_getaddrinfo" = "yes"; then +# rk_BROKEN_GETADDRINFO +# if test "$ac_cv_func_getaddrinfo_numserv" = no; then +# AC_LIBOBJ(getaddrinfo) +# AC_LIBOBJ(freeaddrinfo) +# fi +#fi AC_NEED_PROTO([#include ], setenv) AC_NEED_PROTO([#include ], unsetenv) @@ -442,26 +508,6 @@ AC_NEED_PROTO([#include ], gethostname) AC_NEED_PROTO([#include ], mkstemp) AC_NEED_PROTO([#include ], getusershell) AC_NEED_PROTO([#include ], daemon) -AC_NEED_PROTO([ -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif], -iruserok) AC_NEED_PROTO([ #ifdef HAVE_SYS_TYPES_H @@ -482,7 +528,18 @@ AC_FIND_FUNC_NO_LIBS(crypt, crypt)dnl AC_REQUIRE([rk_BROKEN_REALLOC])dnl -dnl AC_KRB_FUNC_GETCWD_BROKEN +dnl strerror_r is great fun, on linux it exists before sus catched up, +dnl so the return type is diffrent, lets check for both + +AC_PROTO_COMPAT([ +#include +#include +], +strerror_r, int strerror_r(int, char *, size_t)) + +AC_CHECK_FUNC([strerror_r], + [AC_DEFINE_UNQUOTED(HAVE_STRERROR_R, 1, + [Define if you have the function strerror_r.])]) dnl dnl Checks for prototypes and declarations @@ -580,16 +637,26 @@ rk_CHECK_VAR(h_errno, #endif #ifdef HAVE_NETDB_H #include -#endif]) +#endif +#ifdef HAVE_WS2TCPIP_H +#include +#endif +]) rk_CHECK_VAR(h_errlist, [#ifdef HAVE_NETDB_H #include +#endif +#ifdef HAVE_WS2TCPIP_H +#include #endif]) rk_CHECK_VAR(h_nerr, [#ifdef HAVE_NETDB_H #include +#endif +#ifdef HAVE_WS2TCPIP_H +#include #endif]) rk_CHECK_VAR([__progname], @@ -619,19 +686,44 @@ rk_CHECK_VAR(altzone,[#include ]) AC_HAVE_TYPE([sa_family_t],[ #include -#include ]) +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_WS2TCPIP_H +#include +#endif]) AC_HAVE_TYPE([socklen_t],[ #include -#include ]) +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_WS2TCPIP_H +#include +#endif]) AC_HAVE_TYPE([struct sockaddr], [ #include -#include ]) +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_WS2TCPIP_H +#include +#endif]) AC_HAVE_TYPE([struct sockaddr_storage], [ #include -#include ]) +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_WS2TCPIP_H +#include +#endif]) AC_HAVE_TYPE([struct addrinfo], [ #include -#include ]) +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_WS2TCPIP_H +#include +#endif]) AC_HAVE_TYPE([struct ifaddrs], [#include ]) AC_HAVE_TYPE([struct iovec],[ #include @@ -639,8 +731,12 @@ AC_HAVE_TYPE([struct iovec],[ ]) AC_HAVE_TYPE([struct msghdr],[ #include +#ifdef HAVE_SYS_SOCKET_H #include -]) +#endif +#ifdef HAVE_WS2TCPIP_H +#include +#endif]) dnl dnl Check for struct winsize diff --git a/cf/roken-h-process.pl b/cf/roken-h-process.pl new file mode 100644 index 000000000..e797dd224 --- /dev/null +++ b/cf/roken-h-process.pl @@ -0,0 +1,184 @@ +#!/usr/bin/perl + +use Getopt::Std; + +my $debug = 0; + +getopts('dc:p:o:') || die "foo"; + +if ($opt_d) { + $debug = 1; +} + +die "missing arg" if (!defined $opt_c || !defined $opt_p || !defined $opt_o); + +my %defines; +my $IN; +my $OUT; + +print "parse config.h\n" if ($debug); + +open IN, $opt_c || die "failed open ${opt_c}"; + +my @nesting; + +push @nesting, 1; + +while () { + if (m/\s*#ifdef\s+(.*)/) { + my $var = $1; + if (defined $defines{$var}) { + push @nesting, 1; + } else { + push @nesting, 0; + } + next; + } elsif (m/\s*#ifndef\s+(.*)/) { + my $var = $1; + if (defined $defines{$var}) { + push @nesting, 0; + } else { + push @nesting, 1; + } + next; + } elsif (m/\s*#else/) { + my $var = pop @nesting; + $var = !$var; + push @nesting, $var; + next; + } elsif ($nesting[$#nesting] and m/\s*#define\s+(\w+)\s+(\S+)/) { + my $res = $2; + $res = 1 if (!defined $res); + $defines{$1} = $res; + } +} + +close IN; + +if ($debug) { + foreach my $i (keys %defines) { + print "k: $i v: $defines{$i}\n"; + } +} + +open IN, "$opt_p" || die "failed open ${opt_p}"; +open OUT, ">$opt_o" || die "failed open ${opt_o}"; + +print "parse roken.h.in\n" if ($debug); + +print OUT "/* This is an OS dependent, generated file */\n"; +print OUT "\n"; +print OUT "\n"; +print OUT "#ifndef __ROKEN_H__\n"; +print OUT "#define __ROKEN_H__\n"; +print OUT "\n"; + +@nesting = (1); + +while () { + if (m/\s*#ifdef\s+(.*)/) { + my $var = $1; + if (defined $defines{$var}) { + push @nesting, 1; + } else { + push @nesting, 0; + } + next; + } elsif (m/\s*#ifndef\s+(.*)/) { + my $var = $1; + if (defined $defines{$var}) { + push @nesting, 0; + } else { + push @nesting, 1; + } + next; + } elsif (m/\s*#if\s+(.*)/) { + my $res = parse_if($1); + print "line = $res: $1\n" if ($debug); + push @nesting, $res; + next; + } elsif (m/\s*#elif\s+(.*)/) { + my $res = pop @nesting; + if ($res gt 0) { + $res = -1; + } else { + my $res = parse_if($1); + } + push @nesting, $res; + next; + } elsif (m/\s*#else/) { + my $var = pop @nesting; + $var = !$var; + push @nesting, $var; + next; + } elsif (m/\s*#endif/) { + pop @nesting; + next; + } + print "line: $_\n" if ($debug); + print "nesting dep $#{nesting}\n" if ($debug); + my $i = 0, $t = 1; + while ($i le $#nesting) { + $t = 0 if ($nesting[$i] le 0); + print "nesting $i val $nesting[$i] -> $t\n" if ($debug); + $i++; + } + if ($t) { + print OUT; + } +} + +print OUT "\n"; +print OUT "#endif /* __ROKEN_H__ */\n"; + + +close IN; + +exit 0; + +sub parse_if +{ + my ($neg, $var); + + $_ = shift; + + if (m/^\s*$/) { + print "end $_\n" if ($debug); + return 1; + } elsif (m/^\(([^&]+)\&\&(.*)\)\s*\|\|\s*\(([^&]+)\&\&(.*)\)$/) { + print "($1 and $2) or ($3 and $4)\n" if ($debug); + return ((parse_if($1) and parse_if($2)) or (parse_if($3) and parse_if($4))); + } elsif (m/^([^&]+)\&\&(.*)$/) { + print "$1 and $2\n" if ($debug); + return parse_if($1) and parse_if($2); + } elsif (m/^([^\|]+)\|\|(.*)$/) { + print "$1 or $2\n" if ($debug); + return (parse_if($1) or parse_if($2)); + } elsif (m/^\s*(\!)?\s*defined\((\w+)\)/) { + ($neg, $var) = ($1, $2); + print "def: ${neg}-defined(${var})\n" if ($debug); + my $res = defined $defines{$var}; + if ($neg eq "!") { + if ($res) { + $res = 0; + } else { + $res = 1; + } + } + print "res: $res\n" if ($debug); + return $res; + } elsif (m/^\s*(\!)?(\w+)/) { + ($neg, $var) = ($1, $2); + print "var: $neg $var\n" if ($debug); + my $res; + if (defined $defines{$var}) { + $res = $defines{$var}; + } else { + $res = 0; + } + $res = ! $res if ($neg =~ m/!/); + print "res: $res\n" if ($debug); + return $res; + } + die "failed parse: $_\n"; +} diff --git a/cf/sunos.m4 b/cf/sunos.m4 index 5bd45d843..d9aa52cb6 100644 --- a/cf/sunos.m4 +++ b/cf/sunos.m4 @@ -5,13 +5,17 @@ dnl AC_DEFUN([rk_SUNOS],[ sunos=no case "$host" in -*-*-sunos4*) - sunos=40 - ;; *-*-solaris2.7) sunos=57 ;; -*-*-solaris2.[[89]] | *-*-solaris2.1[0-9]) +*-*-solaris2.1[[1-9]]) + AC_DEFINE([__EXTENSIONS__], [1], + [Enable general extensions on Solaris.]) + AC_DEFINE([_STDC_C11_BCI], [1], + [Enable C11 prototypes for memset_s and friends]) + sunos=511 + ;; +*-*-solaris2.[[89]] | *-*-solaris2.10) sunos=58 ;; *-*-solaris2*) @@ -22,4 +26,5 @@ if test "$sunos" != no; then AC_DEFINE_UNQUOTED(SunOS, $sunos, [Define to what version of SunOS you are running.]) fi -]) \ No newline at end of file +AM_CONDITIONAL(SUNOS, test "$sunos" != no) +]) diff --git a/cf/telnet.m4 b/cf/telnet.m4 index 637c66f44..c48e5f9b4 100644 --- a/cf/telnet.m4 +++ b/cf/telnet.m4 @@ -57,9 +57,6 @@ case "$host" in esac AH_BOTTOM([ -#if defined(ENCRYPTION) && !defined(AUTHENTICATION) -#define AUTHENTICATION 1 -#endif /* Set this to the default system lead string for telnetd * can contain %-escapes: %s=sysname, %m=machine, %r=os-release diff --git a/cf/test-package.m4 b/cf/test-package.m4 index 3bc079488..afada2fd0 100644 --- a/cf/test-package.m4 +++ b/cf/test-package.m4 @@ -1,7 +1,7 @@ dnl $Id$ dnl -dnl rk_TEST_PACKAGE(package,headers,libraries,extra libs, -dnl default locations, conditional, config-program) +dnl rk_TEST_PACKAGE(package,program,libraries,extra libs, +dnl default locations, conditional, config-program, headers) AC_DEFUN([rk_TEST_PACKAGE],[ AC_ARG_WITH($1, @@ -91,6 +91,7 @@ if test "$with_$1" != no; then if test "$[]$1_cflags" -a "$[]$1_libs"; then CFLAGS="$[]$1_cflags $save_CFLAGS" LIBS="$[]$1_libs $save_LIBS" + m4_ifval([$8],[AC_CHECK_HEADERS([[$8]])]) AC_LINK_IFELSE([AC_LANG_PROGRAM([[$2]],[[]])],[ INCLUDE_$1="$[]$1_cflags" LIB_$1="$[]$1_libs" @@ -101,6 +102,7 @@ if test "$with_$1" != no; then ires= lres= for i in $header_dirs; do CFLAGS="-I$i $save_CFLAGS" + m4_ifval([$8],[AC_CHECK_HEADERS([[$8]])]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[$2]],[[]])],[ires=$i;break]) done for i in $lib_dirs; do diff --git a/cf/valgrind-suppressions b/cf/valgrind-suppressions index ab5ba5288..44f3f379e 100644 --- a/cf/valgrind-suppressions +++ b/cf/valgrind-suppressions @@ -1,4 +1,3 @@ -# $Id$ { linux db init brokenness Memcheck:Param @@ -82,3 +81,88 @@ obj:/lib/ld-2.5.so obj:/lib/ld-2.5.so } +{ + glibc sed leak 1 + Memcheck:Leak + fun:calloc + obj:/bin/sed + obj:/bin/sed + obj:/bin/sed + obj:/bin/sed + obj:/bin/sed + fun:(below main) +} +{ + Heimdal one-time init leak 1 + Memcheck:Leak + ... + fun:heim_base_once_f + ... +} +{ + Heimdal one-time init leak 2 + Memcheck:Leak + fun:pthread_once + ... +} +{ + Heimdal one-time init leak 3 + Memcheck:Leak + fun:calloc + fun:_heim_alloc_object + fun:heim_dict_create + fun:_krb5_load_plugins + fun:init_context_once + fun:once_callback_caller + fun:pthread_once + fun:heim_base_once_f + fun:krb5_init_context + fun:main +} +{ + Heimdal one-time init leak 4 + Memcheck:Leak + fun:calloc + fun:heim_dict_create + fun:_krb5_load_plugins + fun:init_context_once + fun:once_callback_caller + fun:pthread_once + fun:heim_base_once_f + fun:krb5_init_context + fun:main +} +{ + Heimdal ipropd-master leak 1 + Memcheck:Leak + ... + fun:krb5_kt_resolve + fun:main + obj:*ipropd-master +} +{ + Heimdal ipropd-master leak 2 + Memcheck:Leak + ... + fun:kadm5_init_with_skey_ctx + fun:main + obj:*ipropd-master +} +{ + Heimdal ipropd-slave leak 1 + Memcheck:Leak + ... + fun:krb5_auth_con_init + ... + fun:krb5_sendauth + fun:main + obj:*ipropd-slave +} +{ + Heimdal ipropd-slave leak 2 + Memcheck:Leak + ... + fun:kadm5_init_with_password_ctx + fun:main + obj:*ipropd-slave +} diff --git a/cf/w32-check-exported-symbols.pl b/cf/w32-check-exported-symbols.pl new file mode 100644 index 000000000..5de49ff40 --- /dev/null +++ b/cf/w32-check-exported-symbols.pl @@ -0,0 +1,129 @@ +######################################################################## +# +# Copyright (c) 2010, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +use Getopt::Long; +use Pod::Usage; +use feature "switch"; + +my $def_name = ''; +my $vs_name = ''; +my $show_help = 0; + +my %syms; + +my $def_only = 0; +my $vs_only = 0; + +GetOptions ("def=s" => \$def_name, + "vs=s" => \$vs_name, + "help|?" => \$show_help) or pod2usage( -exitval => 2, + -verbose => 3 ); +pod2usage( -exitval => 1, + -verbose => 3 ) if $show_help or !$def_name or !$vs_name; + +open (my $def, '<', $def_name) or die $!; +open (my $vs, '<', $vs_name) or die $!; + +# First go through the version-script + +my $global = 0; + +while(<$vs>) +{ + next unless m/^([^#]+)/; + + @a = split(/\s+|(\{|})/,$1); + + for $f (@a) { + given ($f) { + when (/global\:/) { $global = 1; } + when (/{|}|.*\:/) { $global = 0; } + when (/(.*)\;/ and $global == 1) { + $syms{$1} = 1; + } + } + } +} + +while(<$def>) +{ + next if m/^#/; + next unless m/^;!([^;]+)/ or m/^([^;]+);?(!?)/; + + @a = split(/\s+/, $1); + + for $f (@a) { + next if $f =~ /EXPORTS/ or $f =~ /DATA/ or not $f; + + if (not exists $syms{$f} and not $2) { + print "$f: Only in DEF\n"; + ++$def_only; + } + delete $syms{$f}; + } +} + +#while (($k,$v) = each %syms) { +for $k (sort keys %syms) { + print "$k: Only in VS\n"; + ++$vs_only; +} + +close($def); +close($vs); + +if ($def_only or $vs_only) { + print "\nMismatches found.\n"; + exit(1); +} + +__END__ + +=head1 NAME + +w32-sync-exported-symbols.pl - Synchronize Windows .def with version-script + +=head1 SYNOPSIS + +w32-sync-exported-symbols.pl {options} + + Options: + --def Name of .def file + --vs Name of version-script file + +=head1 DESCRIPTION + +Verifies that all the symbols exported by the version-script is also +accounted for in the .def file. Also checks that no extra symbols are +exported by the .def file unless they are marked as safe. + +=cut + diff --git a/cf/w32-def-from-dll.pl b/cf/w32-def-from-dll.pl new file mode 100644 index 000000000..77fb4d9a7 --- /dev/null +++ b/cf/w32-def-from-dll.pl @@ -0,0 +1,212 @@ +######################################################################## +# +# Copyright (c) 2010, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +my $show_module_name = 1; +my $use_indent = 1; +my $strip_leading_underscore = 0; +my $always_export = 0; +my $module_name = ""; +my $local_prefix = "SHIM_"; +my %forward_exports = (); +my %local_exports = (); + +sub build_forwarder_target_list($) +{ + $fn = shift; + + print STDERR "Processing defs from file [$fn]\n"; + + open(SP, '-|', "dumpbin /exports \"".$fn."\"") or die "Can't open pipe for $fn"; + + LINE: + while () { +# 112 6F 00071CDC krb5_encrypt_size + + /^ +([[:digit:]]+)\s+[[:xdigit:]]+\s[[:xdigit:]]{8,}\s+(\S+)(?:| = (\S*))$/ && do { + my ($ordinal, $symbol, $in) = ($1, $2, $3); + + if ($in eq "") { $in = $symbol }; + $forward_exports{$symbol} = $in; + }; + } + + close SP; +} + +# Dump all symbols for the given dll file that are defined and have +# external scope. + +sub build_def_file($) +{ + $fn = shift; + + print STDERR "Opening dump of DLL [$fn]\n"; + + open(SP, '-|', "dumpbin /exports \"".$fn."\"") or die "Can't open pipe for $fn"; + + LINE: + while () { +# 112 6F 00071CDC krb5_encrypt_size + + /^ +([[:digit:]]+)\s+[[:xdigit:]]+\s[[:xdigit:]]{8,}\s+(\S+)(?:| = (\S*))$/ && do { + my ($ordinal, $symbol, $in) = ($1, $2, $3); + + if ($strip_leading_underscore && $symbol =~ /_(.*)/) { + $symbol = $1; + } + if (exists $local_exports{$symbol}) { + print "\t".$symbol; + print " = ".$local_exports{$symbol}; + if ($in ne $local_exports{$symbol} and $in ne "") { + print STDERR "Incorrect calling convention for local $symbol\n"; + print STDERR " ".$in." != ".$local_exports{$symbol}."\n"; + } + print "\t@".$ordinal."\n"; + } elsif (exists $local_exports{$local_prefix.$symbol}) { + print "\t".$symbol; + print " = ".$local_exports{$local_prefix.$symbol}; + print "\t@".$ordinal."\n"; + } elsif (exists $forward_exports{$symbol}) { + print "\t".$symbol; + print " = ".$module_name; + if ($in ne $forward_exports{$symbol} and $in ne "") { + print STDERR "Incorrect calling convention for $symbol\n"; + print STDERR " ".$in." != ".$forward_exports{$symbol}."\n"; + } + my $texp = $forward_exports{$symbol}; + if ($texp =~ /^_([^@]+)$/) { $texp = $1; } + print $texp."\t@".$ordinal."\n"; + } elsif ($always_export) { + print "\t".$symbol." = ".$local_prefix.$symbol; + print "\t@".$ordinal."\n"; + } else { + print STDERR "Symbol not found: $symbol\n"; + } + }; + } + + close SP; +} + +sub build_local_exports_list($) +{ + $fn = shift; + + print STDERR "Opening dump of object [$fn]\n"; + + open(SP, '-|', "dumpbin /symbols \"".$fn."\"") or die "Can't open pipe for $fn"; + + LINE: + while () { + # 009 00000010 SECT3 notype () External | _remove_error_table@4 + m/^[[:xdigit:]]{3,}\s[[:xdigit:]]{8,}\s(\w+)\s+\w*\s+(?:\(\)| )\s+(\w+)\s+\|\s+(\S+)$/ && do { + my ($section, $visibility, $symbol) = ($1, $2, $3); + + if ($section ne "UNDEF" && $visibility eq "External") { + + my $exp_name = $symbol; + + if ($symbol =~ m/^_(\w+)(?:@.*|)$/) { + $exp_name = $1; + } + + if ($symbol =~ m/^_([^@]+)$/) { + $symbol = $1; + } + + $local_exports{$exp_name} = $symbol; + } + }; + } + + close SP; +} + +sub process_file($) +{ + $fn = shift; + + if ($fn =~ m/\.dll$/i) { + build_def_file($fn); + } elsif ($fn =~ m/\.obj$/i) { + build_local_exports_list($fn); + } else { + die "File type not recognized for $fn."; + } +} + +sub use_response_file($) +{ + $fn = shift; + + open (RF, '<', $fn) or die "Can't open response file $fn"; + + while () { + /^(\S+)$/ && do { + process_file($1); + } + } + close RF; +} + +print "; This is a generated file. Do not modify directly.\n"; +print "EXPORTS\n"; + +for (@ARGV) { + ARG: { + /^-m(.*)$/ && do { + $module_name = $1."."; + last ARG; + }; + + /^-l(.*)$/ && do { + $local_prefix = $1."_"; + last ARG; + }; + + /^-a$/ && do { + $always_export = 1; + last ARG; + }; + + /^-e(.*)$/ && do { + build_forwarder_target_list($1); + last ARG; + }; + + /^@(.*)$/ && do { + use_response_file($1); + last ARG; + }; + + process_file($_); + } +} diff --git a/cf/w32-detect-vc-version.pl b/cf/w32-detect-vc-version.pl new file mode 100644 index 000000000..213ca29c8 --- /dev/null +++ b/cf/w32-detect-vc-version.pl @@ -0,0 +1,49 @@ +######################################################################## +# +# Copyright (c) 2010, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +# Try to detect the version of Visual C++ in use by parsing the output +# of cl.exe. + +$cl_cmd = shift; + +die "C compiler command should be specified" if ($cl_cmd eq ''); + +open(CL, '-|', $cl_cmd." 2>&1") or die "Can't run C compiler command [$cl_cmd]"; + +$verline = ; + +if ($verline =~ /(\d+).(\d+).(\d+).(\d+)/) { + print "Found Version: $1.$2.$3.$4\n"; + exit $1 + 0; +} else { + print "Mismatch"; + exit 1; +} diff --git a/cf/w32-hh-toc-from-info.pl b/cf/w32-hh-toc-from-info.pl new file mode 100644 index 000000000..9be8ef6e7 --- /dev/null +++ b/cf/w32-hh-toc-from-info.pl @@ -0,0 +1,124 @@ +######################################################################## +# +# Copyright (c) 2010, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +use HTML::TreeBuilder; + + +my $input_file = "index.html"; +my $toc_file = "toc.hhc"; + +for (@ARGV) { + ARG: { + /-o(.*)/ && do { + $toc_file = $1; + last ARG; + }; + + $input_file = $_; + } +} + +print "Processing TOC in $input_file\n"; +print "Writing to $toc_file\n"; + +open(TOC, '>', $toc_file) or die "Can't open $toc_file\n"; + +my $tree = HTML::TreeBuilder->new(); + +$tree->parse_file($input_file); + +my $contents = $tree->look_down('class', 'contents'); +if (defined($contents)) { + my $clist = $contents->find_by_tag_name('ul'); +} + +print TOC ' + + + + + +'; + +process_ul_element($clist, 0); + +print TOC ' + + +'; + + +sub process_ul_element +{ + my $e = shift; + my $level = shift; + + return unless defined($e); + + if ($e->tag() eq "ul") { + + print TOC ' 'x$level; + print TOC "
    \n"; + + my @items = $e->content_list(); + + for (@items) { + process_li_element($_, $level + 1); + } + + print TOC ' 'x$level; + print TOC "
\n"; + } +} + +sub process_li_element +{ + my $e = shift; + my $level = shift; + + if ($e->tag() eq "li") { + my $a = $e->find_by_tag_name('a'); + + my $href = $a->attr('href'); + my @ac = $a->content_list(); + my $title = $ac[0]; + + print TOC " "x$level; + print TOC "
  • \n"; + + my @items = $e->content_list(); + + for (@items) { + process_ul_element($_, $level + 1); + } + } +} + diff --git a/cf/w32-list-externs-from-objs.pl b/cf/w32-list-externs-from-objs.pl new file mode 100644 index 000000000..9712120e9 --- /dev/null +++ b/cf/w32-list-externs-from-objs.pl @@ -0,0 +1,114 @@ +######################################################################## +# +# Copyright (c) 2010, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +my $show_module_name = 1; +my $use_indent = 1; +my $strip_leading_underscore = 0; + +# Dump all symbols for the given object file that are defined and have +# external scope. + +sub dump_symbols_for_file($) +{ + $fn = shift; + + print STDERR "Opening dump of object [$fn]\n"; + + open(SP, '-|', "dumpbin /symbols \"".$fn."\"") or die "Can't open pipe for $fn"; + + LINE: + while () { + # 008 00000000 SECT3 notype () External | _encode_AccessDescription + + /^[[:xdigit:]]{3,}\s[[:xdigit:]]{8,}\s(\w+)\s+\w*\s+(\(\)| )\s+(\w+)\s+\|\s+([0-9a-zA-Z\@\_]+)$/ && do { + my ($section, $type, $visibility, $symbol) = ($1, $2, $3, $4); + + if ($section ne "UNDEF" && $visibility eq "External") { + print $fn if $show_module_name; + print "\t" if $use_indent || $show_module_name; + + if ($strip_leading_underscore && $symbol =~ /_(.*)/) { + $symbol = $1; + } + if ($strip_leading_underscore && $symbol =~ /(.*)\@.*$/) { + $symbol = $1; + } + print $symbol; + if ($type ne "()") { + print "\tDATA"; + } + print "\n"; + } + }; + } + + close SP; +} + +sub use_response_file($) +{ + $fn = shift; + + open (RF, '<', $fn) or die "Can't open response file $fn"; + + while () { + /(\S+)/ && do { + dump_symbols_for_file($1); + } + } + close RF; +} + +for (@ARGV) { + ARG: { + /^-q$/ && do { + $show_module_name = 0; + last ARG; + }; + + /^-1$/ && do { + $use_indent = 0; + last ARG; + }; + + /^-u$/ && do { + $strip_leading_underscore = 1; + last ARG; + }; + + /^@(.*)$/ && do { + use_response_file($1); + last ARG; + }; + + dump_symbols_for_file($_); + } +} diff --git a/cf/wflags.m4 b/cf/wflags.m4 index f610ac61e..bc128bce7 100644 --- a/cf/wflags.m4 +++ b/cf/wflags.m4 @@ -9,21 +9,25 @@ AC_ARG_ENABLE(developer, if test "X$enable_developer" = Xyes; then dwflags="-Werror" fi +AM_CONDITIONAL(DEVELOPER_MODE, test "X$enable_developer" = Xyes) WFLAGS_NOUNUSED="" -WFLAGS_NOIMPLICITINT="" if test -z "$WFLAGS" -a "$GCC" = "yes"; then - # -Wno-implicit-int for broken X11 headers # leave these out for now: # -Wcast-align doesn't work well on alpha osf/1 # -Wmissing-prototypes -Wpointer-arith -Wbad-function-cast # -Wmissing-declarations -Wnested-externs # -Wstrict-overflow=5 WFLAGS="ifelse($#, 0,-Wall, $1) $dwflags" - WFLAGS_NOUNUSED="-Wno-unused" - WFLAGS_NOIMPLICITINT="-Wno-implicit-int" + + # + # WFLAGS_LITE can be appended to WFLAGS to turn off a host of warnings + # that fail for various bits of older code in appl/. Let's not use it + # for the main libraries, though. + WFLAGS_LITE="-Wno-extra -Wno-missing-field-initializers -Wno-strict-aliasing -Wno-shadow" + # -Wno-unused-result (not supported on gcc-4.2) + fi AC_SUBST(WFLAGS)dnl -AC_SUBST(WFLAGS_NOUNUSED)dnl -AC_SUBST(WFLAGS_NOIMPLICITINT)dnl +AC_SUBST(WFLAGS_LITE)dnl ]) diff --git a/cf/win32.m4 b/cf/win32.m4 index 9954ec3ca..5561ad966 100644 --- a/cf/win32.m4 +++ b/cf/win32.m4 @@ -3,10 +3,12 @@ dnl rk_WIN32_EXPORT buildsymbol symbol-that-export AC_DEFUN([rk_WIN32_EXPORT],[AH_TOP([#ifdef $1 #ifndef $2 #ifdef _WIN32_ -#define $2_FUNCTION __declspec(dllexport) __stdcall +#define $2_FUNCTION __declspec(dllexport) +#define $2_CALL __stdcall #define $2_VARIABLE __declspec(dllexport) #else #define $2_FUNCTION +#define $2_CALL #define $2_VARIABLE #endif #endif diff --git a/configure.ac b/configure.ac new file mode 100644 index 000000000..650e92246 --- /dev/null +++ b/configure.ac @@ -0,0 +1,863 @@ +dnl Process this file with autoconf to produce a configure script. +AC_REVISION($Revision$) +AC_PREREQ(2.62) +test -z "$CFLAGS" && CFLAGS="-g" +AC_INIT([Heimdal],[7.99.1],[https://github.com/heimdal/heimdal/issues]) +AC_CONFIG_SRCDIR([kuser/kinit.c]) +AC_CONFIG_HEADERS(include/config.h) +AC_CONFIG_MACRO_DIR([cf]) + +AM_INIT_AUTOMAKE([foreign 1.11]) +AM_MAINTAINER_MODE + +LT_PREREQ([2.2]) +LT_INIT([shared static win32-dll]) + + +dnl Checks for programs. +AC_PROG_CC +AM_PROG_CC_C_O +AC_PROG_CPP +AM_PATH_PYTHON +AC_CHECK_PROG(CLANG_FORMAT, clang-format, [clang-format], [no]) +test "$CLANG_FORMAT" = no && CLANG_FORMAT=true + +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +AC_PREFIX_DEFAULT(/usr/heimdal) + +test "$sysconfdir" = '${prefix}/etc' && sysconfdir='/etc' +test "$localstatedir" = '${prefix}/var' && localstatedir='/var/heimdal' + +AC_CANONICAL_HOST +CANONICAL_HOST=$host +AC_SUBST(CANONICAL_HOST) + +rk_SYS_LARGEFILE + +rk_AIX +rk_IRIX +rk_SUNOS + +dnl +dnl this is needed to run the configure tests against glibc +dnl +AC_DEFINE([_GNU_SOURCE], 1, + [Define to enable extensions on glibc-based systems such as Linux.]) + +AC_OBJEXT +AC_EXEEXT + +dnl +dnl this is needed when der-protos.h or der-private.h has to be generated +dnl +if ! test -f "$srcdir/lib/asn1/der-protos.h" || + ! test -f "$srcdir/lib/asn1/der-private.h"; then + AC_KRB_PROG_PERL + AC_KRB_PERL_MOD(Getopt::Std) + AC_KRB_PERL_MOD(File::Compare) +fi + +AC_KRB_PROG_YACC +dnl AC_PROG_YACC +AM_PROG_LEX +AS_IF([$LEX --nounput -V > /dev/null 2>&1 && test $? -eq 0], + [AC_SUBST([FLEXNOUNPUTARGS], ["--nounput"])], + [AC_SUBST([FLEXNOUNPUTARGS], [""])]) +dnl AC_PROG_RANLIB +AC_PROG_AWK +AC_KRB_PROG_LN_S + +AC_MIPS_ABI +CC="$CC $abi" +libdir="$libdir$abilibdirext" + +AC_C___ATTRIBUTE__ + +AM_CONDITIONAL(ENABLE_SHARED, test "$enable_shared" = "yes") +rk_VERSIONSCRIPT + +dnl Code coverage +AC_ARG_ENABLE([gcov], + AC_HELP_STRING([--enable-gcov], [enable gcov code coverage tool])) +AM_CONDITIONAL([ENABLE_GCOV], [test "x$enable_gcov" = xyes]) + + +dnl +dnl Helper bits for cross compiling +dnl + +AM_CONDITIONAL(CROSS_COMPILE, test "${cross_compiling}" = yes) + +AC_ARG_WITH(cross-tools, + AS_HELP_STRING([--with-cross-tools=dir], [use cross tools in dir]), + [if test "$withval" = "yes"; then + AC_MSG_ERROR([Need path to cross tools]) + fi + with_cross_tools="${with_cross_tools}/" + ]) + +if test "${cross_compiling}" != yes ; then + + ASN1_COMPILE="\$(top_builddir)/lib/asn1/asn1_compile\$(EXEEXT)" + SLC="\$(top_builddir)/lib/sl/slc" + + ASN1_COMPILE_DEP="\$(ASN1_COMPILE)" + SLC_DEP="\$(SLC)" +else + ASN1_COMPILE="${with_cross_tools}asn1_compile" + SLC="${with_cross_tools}slc" + + ASN1_COMPILE_DEP= + SLC_DEP= + + ac_cv_prog_COMPILE_ET=${with_cross_tools}compile_et + +fi + +AX_CHECK_COMPILE_FLAG([-Wno-error=enum-conversion], + [WFLAGS_ENUM_CONV=-Wno-error=enum-conversion], + [WFLAGS_ENUM_CONV=], [-Werror]) +AX_CHECK_COMPILE_FLAG([-Wno-unused-but-set-variable], + [WFLAGS_UNUSED_BUT_SET_VAR=-Wno-unused-but-set-variable], + [WFLAGS_UNUSED_BUT_SET_VAR=], [-Werror]) + +AC_SUBST([WFLAGS_ENUM_CONV]) +AC_SUBST([ASN1_COMPILE]) +AC_SUBST([ASN1_COMPILE_DEP]) +AC_SUBST([SLC]) +AC_SUBST([SLC_DEP]) + +dnl --- + +AC_DEFINE(HEIM_WEAK_CRYPTO, 1, [Define if you want support for weak crypto]) + +rk_TEST_PACKAGE(openldap, +[#include +#include ], +[-lldap -llber],,,OPENLDAP) +AM_CONDITIONAL(OPENLDAP, test "$with_openldap" != "no") + +AC_ARG_ENABLE(hdb-openldap-module, + AS_HELP_STRING([--enable-hdb-openldap-module], + [if you want support to build openldap hdb as shared object])) +if test "$enable_hdb_openldap_module" = yes -a "$with_openldap" = yes; then + AC_DEFINE(OPENLDAP_MODULE, 1, [Define if you want support for hdb ldap module]) +fi +AM_CONDITIONAL(OPENLDAP_MODULE, test "$enable_hdb_openldap_module" = yes -a "$with_openldap" = yes) + +AC_ARG_ENABLE(asn1-templating, + AS_HELP_STRING([--disable-asn1-templating], + [if you want disable to use of the ASN.1 templating compiler])) +AM_CONDITIONAL(ASN1_TEMPLATING, test "x$enable_asn1_templating" != xno) + +dnl +dnl Optional modules, pk-init, digest, kx509 +dnl + +AC_ARG_ENABLE(pk-init, + AS_HELP_STRING([--disable-pk-init], + [if you want disable to PK-INIT support])) +if test "$enable_pk_init" != no ;then + AC_DEFINE([PKINIT], 1, [Define to enable PKINIT.]) +fi +AM_CONDITIONAL(PKINIT, test "$enable_pk_init" != no) + +AC_ARG_ENABLE(digest, + AS_HELP_STRING([--disable-digest], + [if you want disable to DIGEST support])) +if test "$enable_digest" != no ;then + AC_DEFINE([DIGEST], 1, [Define to enable DIGEST.]) +fi + +AC_ARG_ENABLE(kx509, + AS_HELP_STRING([--disable-kx509], + [if you want disable to kx509 support])) +if test "$enable_kx509" != no ;then + AC_DEFINE([KX509], 1, [Define to enable kx509.]) +fi + +dnl Need to test if pkg-config exists +PKG_PROG_PKG_CONFIG + +dnl libcap-ng +AC_ARG_WITH([capng], + AC_HELP_STRING([--with-capng], [use libcap-ng to drop KDC privileges @<:@default=check@:>@]), + [], + [with_capng=check]) +if test "$with_capng" != "no"; then + PKG_CHECK_MODULES([CAPNG], [libcap-ng >= 0.4.0], + [with_capng=yes],[with_capng=no]) +fi +if test "$with_capng" = "yes"; then + AC_DEFINE_UNQUOTED([HAVE_CAPNG], 1, [whether capng is available for privilege reduction]) +fi +AM_CONDITIONAL([HAVE_CAPNG], [test "$with_capng" != "no"]) +AC_SUBST([CAPNG_CFLAGS]) +AC_SUBST([CAPNG_LIBS]) + +dnl mitdb +AC_ARG_WITH([mitdb], + AC_HELP_STRING([--with-mitdb], [Path to MIT Kerberos DB include header and shared object]), + [], + [with_mitdb=no]) +if test -n "$with_mitdb" -a -d "$with_mitdb"; then + AC_DEFINE_UNQUOTED([HAVE_MITDB], 1, [Define if building with MIT Kerberos DB driver]) + AC_DEFINE(HAVE_DB1, 1, [define if you have a berkeley db1/2 library]) + mitdb=$with_mitdb +elif test "$with_mitdb" = no; then + with_mitdb= + mitdb= +elif test "$with_mitdb" = yes; then + AC_MSG_ERROR([Need path to MIT Kerberos DB include header and shared object]) +fi +AM_CONDITIONAL([HAVE_MITDB], [test -n "$with_mitdb"]) +AC_SUBST([MITDB], ["$with_mitdb"]) + +dnl libmicrohttpd +AC_ARG_WITH([microhttpd], + AC_HELP_STRING([--with-microhttpd], [use microhttpd to serve KDC REST API @<:@default=check@:>@]), + [], + [with_microhttpd=check]) +if test "$with_microhttpd" != "no"; then + PKG_CHECK_MODULES([MICROHTTPD], [libmicrohttpd >= 0.9.37], + [with_microhttpd=yes],[with_microhttpd=no]) +fi +if test "$with_microhttpd" = "yes"; then + AC_DEFINE_UNQUOTED([HAVE_MICROHTTPD], 1, [whether libmicrohttpd is available for KDC REST API]) +fi +AM_CONDITIONAL([HAVE_MICROHTTPD], [test "$with_microhttpd" != "no"]) +AC_SUBST([MICROHTTPD_CFLAGS]) +AC_SUBST([MICROHTTPD_LIBS]) + +dnl libcjwt +AC_ARG_WITH([cjwt], + AC_HELP_STRING([--with-cjwt], [(Experimental) use cjwt to validate JWT tokens @<:@default=check@:>@]), + [], + [with_cjwt=check]) +if test "$with_cjwt" != "no"; then + PKG_CHECK_MODULES([CJWT], [libcjwt >= 1.0.0], + [with_cjwt=yes],[with_cjwt=no]) +fi +if test "$with_cjwt" = "yes"; then + AC_DEFINE_UNQUOTED([HAVE_CJWT], 1, [whether libcjwt is available for KDC REST API]) +fi +AM_CONDITIONAL([HAVE_CJWT], [test "$with_cjwt" != "no"]) +AC_SUBST([CJWT_CFLAGS]) +AC_SUBST([CJWT_LIBS]) + +dnl libcjson +AC_ARG_WITH([cjson], + AC_HELP_STRING([--with-cjson], [(Experimental) use cJSON to extract private claims from JWT tokens @<:@default=check@:>@]), + [], + [with_cjson=check]) +if test "$with_cjson" != "no"; then + PKG_CHECK_MODULES([CJSON], [libcjson >= 1.0.0], + [with_cjson=yes],[with_cjson=no]) +fi +if test "$with_cjson" = "yes"; then + AC_DEFINE_UNQUOTED([HAVE_CJSON], 1, [whether libcjson is available for KDC REST API]) +fi +AM_CONDITIONAL([HAVE_CJSON], [test "$with_cjson" != "no"]) +AC_SUBST([CJSON_CFLAGS]) +AC_SUBST([CJSON_LIBS]) + +dnl mitkrb5 +AC_ARG_WITH([mitkrb5], + AC_HELP_STRING([--with-mitkrb5], [Path to MIT Kerberos for interop testing @<:@default=check@:>@]), + [], + [with_mikrb5=check]) +AM_CONDITIONAL([MITKRB5], [test "$with_mitkrb5" != "no"]) + +dnl Check for sqlite +rk_TEST_PACKAGE(sqlite3, +[#include +#ifndef SQLITE_OPEN_CREATE +#error "old version" +#endif], +[-lsqlite3],,,SQLITE3) + +if test "X$with_sqlite3" != Xyes ; then + INCLUDE_sqlite3="-I\$(top_srcdir)/lib/sqlite" + LIB_sqlite3="\$(top_builddir)/lib/sqlite/libheimsqlite.la" +fi +AM_CONDITIONAL(SQLITE3, test "X$with_sqlite3" = Xyes) + +AC_DEFINE(HAVE_SQLITE3, 1, [Define if you want support for sqlite in Heimdal.]) + +AC_ARG_ENABLE(sqlite-cache, + AS_HELP_STRING([--disable-sqlite-cache],[if you want support for cache in sqlite])) +if test "$enable_sqlite_cache" != no; then + AC_DEFINE(HAVE_SCC, 1, [Define if you want support for cache in sqlite.]) +fi +AM_CONDITIONAL(have_scc, test "$enable_sqlite_cache" != no) + + +dnl check for libintl +rk_TEST_PACKAGE(libintl, +[#include ], +[-lintl],,,LIBINTL) + +dnl path where the hdb directory is stored +AC_ARG_WITH([hdbdir], + [AS_HELP_STRING([--with-hdbdir],[Default location for KDC database @<:@default=/var/heimdal@:>@])], + [], + [with_hdbdir=/var/heimdal]) +DIR_hdbdir="$with_hdbdir" +AC_SUBST([DIR_hdbdir]) + + +AM_CONDITIONAL(KRB5, true) +AM_CONDITIONAL(do_roken_rename, true) + +AC_DEFINE(SUPPORT_INETD, 1, [Enable use of inetd style startup.])dnl + + +AC_DEFINE(KRB5, 1, [Enable Kerberos 5 support in applications.])dnl +AC_SUBST(LIB_kdb)dnl + +KRB_CRYPTO + +KRB_PTHREADS + +AC_ARG_ENABLE(dce, + AS_HELP_STRING([--enable-dce],[if you want support for DCE/DFS PAG's])) +if test "$enable_dce" = yes; then + AC_DEFINE(DCE, 1, [Define if you want support for DCE/DFS PAG's.]) +fi +AM_CONDITIONAL(DCE, test "$enable_dce" = yes) + +## XXX quite horrible: +if test -f /etc/ibmcxx.cfg; then + dpagaix_ldadd=`sed -n '/^xlc_r4/,/^$/p' /etc/ibmcxx.cfg | sed -n -e '/libraries/{;s/^[[^=]]*=\(.*\)/\1/;s/,/ /gp;}'` + dpagaix_cflags=`sed -n '/^xlc_r4/,/^$/p' /etc/ibmcxx.cfg | sed -n -e '/options/{;s/^[[^=]]*=\(.*\)/\1/;s/-q[^,]*//;s/,/ /gp;}'` + dpagaix_ldflags= +else + dpagaix_cflags="-D_THREAD_SAFE -D_AIX_PTHREADS_D7 -D_AIX32_THREADS=1 -D_AES_SOURCE -D_AIX41 -I/usr/include/dce" + dpagaix_ldadd="-L/usr/lib/threads -ldcelibc_r -ldcepthreads -lpthreads_compat lpthreads -lc_r" + dpagaix_ldflags="-Wl,-bI:dfspag.exp" +fi +AC_SUBST(dpagaix_cflags) +AC_SUBST(dpagaix_ldadd) +AC_SUBST(dpagaix_ldflags) + +AC_ARG_ENABLE([afs-support], + AS_HELP_STRING([--disable-afs-support],[if you don't want support for AFS])) +if test "$enable_afs_support" = no; then + AC_DEFINE(NO_AFS, 1, [Define if you don't wan't support for AFS.]) + NO_AFS="1" +fi +AC_SUBST(NO_AFS)dnl +AM_CONDITIONAL(NO_AFS, test "$enable_afs_support" = no) + +rk_DB + +dnl AC_ROKEN(10,[/usr/heimdal /usr/athena],[lib/roken],[$(top_builddir)/lib/roken/libroken.la],[-I$(top_builddir)/lib/roken -I$(top_srcdir)/lib/roken]) + +rk_ROKEN(lib/roken) +LIBADD_roken="$LIB_roken" +AC_SUBST(LIBADD_roken)dnl +LIB_roken="\$(top_builddir)/lib/vers/libvers.la $LIB_roken" + +rk_OTP + +rk_LIBDISPATCH + +AC_CHECK_OSFC2 + +AC_ARG_ENABLE(mmap, + AS_HELP_STRING([--disable-mmap],[disable use of mmap])) +if test "$enable_mmap" = "no"; then + AC_DEFINE(NO_MMAP, 1, [Define if you don't want to use mmap.]) +fi + +AC_ARG_ENABLE(afs-string-to-key, + AS_HELP_STRING([--disable-afs-string-to-key], + [disable use of weak AFS string-to-key functions]), + [], [enable_afs_string_to_key=yes]) + +if test "$enable_afs_string_to_key" = "yes"; then + AC_DEFINE(ENABLE_AFS_STRING_TO_KEY, 1, [Define if want to use the weak AFS string to key functions.]) + ENABLE_AFS_STRING_TO_KEY=1 +fi +AC_SUBST(ENABLE_AFS_STRING_TO_KEY)dnl + + +rk_CHECK_MAN + +rk_TEST_PACKAGE(readline, +[#include +#if defined(HAVE_READLINE_READLINE_H) +#include +#elif defined(HAVE_READLINE_H) +#include +#endif +],-lreadline,,, READLINE,, [readline.h readline/readline.h]) + +rk_TEST_PACKAGE(libedit, +[#include +#if defined(HAVE_READLINE_READLINE_H) +#include +#elif defined(HAVE_READLINE_H) +#include +#elif defined(HAVE_EDITLINE_READLINE_H) +#include +#endif +],-ledit,,, READLINE,, [readline.h readline/readline.h editline/readline.h]) + +AC_CONFIG_SUBDIRS([lib/libedit]) + +KRB_C_BIGENDIAN +AC_C_INLINE + +dnl AM_C_PROTOTYPES + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_OFF_T +AC_CHECK_TYPE_EXTRA(mode_t, unsigned short, []) +AC_CHECK_TYPE_EXTRA(sig_atomic_t, int, [#include ]) +AC_HAVE_TYPE([long long]) +AC_HEADER_TIME +AC_STRUCT_TM + +dnl Checks for header files. +AC_HEADER_STDC + +AC_CHECK_HEADERS([\ + CommonCrypto/CommonDigest.h \ + CommonCrypto/CommonCryptor.h \ + arpa/telnet.h \ + bind/bitypes.h \ + bsdsetjmp.h \ + curses.h \ + dlfcn.h \ + execinfo.h \ + fnmatch.h \ + inttypes.h \ + io.h \ + keyutils.h \ + libutil.h \ + limits.h \ + maillock.h \ + netgroup.h \ + netinet/in6_machtypes.h \ + netinet/tcp.h \ + pthread.h \ + pty.h \ + sac.h \ + sgtty.h \ + siad.h \ + signal.h \ + strings.h \ + stropts.h \ + sys/bitypes.h \ + sys/category.h \ + sys/file.h \ + sys/filio.h \ + sys/ioccom.h \ + sys/mman.h \ + sys/param.h \ + sys/pty.h \ + sys/ptyio.h \ + sys/select.h \ + sys/socket.h \ + sys/str_tty.h \ + sys/stream.h \ + sys/stropts.h \ + sys/syscall.h \ + sys/termio.h \ + sys/timeb.h \ + sys/times.h \ + sys/types.h \ + sys/un.h \ + locale.h \ + termcap.h \ + termio.h \ + termios.h \ + time.h \ + tmpdir.h \ + udb.h \ + util.h \ +]) + +AC_CHECK_HEADERS([stdatomic.h], + [AC_MSG_CHECKING([whether libatomic is required]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[_Atomic(long long) i; atomic_init(&i, (long long) 0);]])], + [AC_MSG_RESULT([no])], + [AC_MSG_RESULT([yes]) + AC_MSG_CHECKING([whether libatomic works]) + save_LIBS="$LIBS" + LIBS="$LIBS -latomic" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[_Atomic(long long) i; atomic_init(&i, (long long) 0);]])], + [AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no, using fallback]) + LIBS="$save_LIBS" + AC_DEFINE([HEIM_BASE_ATOMICS_FALLBACK], [], [Define if you want fallbacks for atomic operations])] + )] + )], + [] +) + +dnl On Solaris 8 there's a compilation warning for term.h because +dnl it doesn't define `bool'. +AC_CHECK_HEADERS(term.h, , , -) + +dnl aix have asl.h (A/IX screen library) that we don't want +AC_CHECK_HEADERS(asl.h, , , [ +#include +#ifndef ASL_STRING_EMERG +#error ASL_STRING_EMERG missing +#endif]) + +AC_CHECK_HEADERS(net/if.h, , , [AC_INCLUDES_DEFAULT +#if HAVE_SYS_SOCKET_H +#include +#endif]) + +AC_CHECK_HEADERS(sys/ptyvar.h, , , [AC_INCLUDES_DEFAULT +#if HAVE_SYS_TTY_H +#include +#endif]) + +AC_CHECK_HEADERS(sys/strtty.h, , , [AC_INCLUDES_DEFAULT +#if HAVE_TERMIOS_H +#include +#endif +#if HAVE_SYS_STREAM_H +#include +#endif]) + +AC_CHECK_HEADERS(sys/ucred.h, , , [AC_INCLUDES_DEFAULT +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_SYS_PARAM_H +#include +#endif]) + +AC_CHECK_HEADERS(security/pam_modules.h, , , [AC_INCLUDES_DEFAULT +#include +]) + +dnl export symbols +rk_WIN32_EXPORT(BUILD_KRB5_LIB, KRB5_LIB) +rk_WIN32_EXPORT(BUILD_ROKEN_LIB, ROKEN_LIB) +rk_WIN32_EXPORT(BUILD_GSSAPI_LIB, GSSAPI_LIB) +rk_WIN32_EXPORT(BUILD_KDC_LIB, KDC_LIB) + +dnl Deal with switch fallthrough warnings +AH_TOP([ +#if defined(DISPATCH_FALLTHROUGH) +# define HEIM_FALLTHROUGH DISPATCH_FALLTHROUGH +#else +# if defined(__GNUC__) +# if __GNUC__ >= 7 +# define HEIM_FALLTHROUGH __attribute__((fallthrough)) +# else +# define HEIM_FALLTHROUGH do {} while (0) /* fallthrough */ +# endif +# else +# define HEIM_FALLTHROUGH do {} while (0) /* fallthrough */ +# endif +#endif +]) + +dnl Checks for libraries. + +AC_FIND_FUNC_NO_LIBS(openpty, util,[ +#ifdef HAVE_UTIL_H +#include +#endif +],[0,0,0,0,0]) + +AC_FIND_FUNC_NO_LIBS(tgetent, termcap ncurses curses tinfo,[ +#ifdef HAVE_TERMCAP_H +#include +#endif +#ifdef HAVE_CURSES_H +#include +#endif +],[0,0]) + +dnl Checks for library functions. + +AC_CHECK_FUNCS([ \ + _scrsize \ + arc4random \ + backtrace \ + fcntl \ + fork \ + fseeko \ + ftello \ + getpeereid \ + getpeerucred \ + getresgid \ + getresuid \ + grantpt \ + ptsname_r \ + rand \ + setitimer \ + setregid \ + setresgid \ + setresuid \ + setreuid \ + setsid \ + sigaction \ + unlockpt \ + waitpid \ +]) + +AC_MSG_CHECKING([checking for __sync_add_and_fetch]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[unsigned int foo, bar; bar = __sync_add_and_fetch(&foo, 1);]])], + [ac_rk_have___sync_add_and_fetch=yes], [ac_rk_have___sync_add_and_fetch=no]) +if test "$ac_rk_have___sync_add_and_fetch" = "yes" ; then + AC_DEFINE_UNQUOTED(HAVE___SYNC_ADD_AND_FETCH, 1, [have __sync_add_and_fetch]) +fi +AC_MSG_RESULT($ac_rk_have___sync_add_and_fetch) + +AC_FUNC_MMAP + +rk_DLADDR + +AC_CHECK_GETPWNAM_R_POSIX +AC_CHECK_GETPWUID_R_POSIX + +dnl detect doors on solaris +if test "$enable_pthread_support" != no; then + saved_LIBS="$LIBS" + LIBS="$LIBS $PTHREADS_LIBS" + AC_FIND_FUNC_NO_LIBS(door_create, door) + LIBS="$saved_LIBS" +fi + +AC_ARG_ENABLE(kcm, + AS_HELP_STRING([--enable-kcm],[enable Kerberos Credentials Manager]), +,[enable_kcm=yes]) + +if test "$enable_kcm" = yes ; then + if test "$ac_cv_header_sys_un_h" != yes -a "$ac_cv_funclib_door_create" != yes ; then + enable_kcm=no + fi +fi +if test "$enable_kcm" = yes; then + AC_DEFINE(HAVE_KCM, 1, + [Define if you want to use the Kerberos Credentials Manager.]) +fi +AM_CONDITIONAL(KCM, test "$enable_kcm" = yes) + +dnl detect keyring on Linux +if test "$ac_cv_header_keyutils_h" = yes; then + AC_CHECK_SIZEOF([key_serial_t],,[ + #ifdef HAVE_INTTYPES_H + #include + #endif + #ifdef HAVE_SYS_TYPES_H + #include + #endif + #include + ]) +fi + +AC_FIND_FUNC_NO_LIBS(add_key, keyutils) +if test -n "$LIB_add_key"; then + saved_LIBS="$LIBS" + LIBS="$LIBS $LIB_add_key" + AC_CHECK_FUNCS(keyctl_get_persistent) + LIBS="$saved_LIBS" +fi +AM_CONDITIONAL(HAVE_KEYUTILS, test "$ac_cv_func_keyctl_get_persistent" = yes) + +AC_CHECK_SIZEOF([time_t]) + +AX_CHECK_SIGN([time_t], + [ AC_DEFINE(TIME_T_SIGNED, 1, [Define if time_t is signed]) ], + [ AC_DEFINE(TIME_T_UNSIGNED, 1, [Define if time_t is unsigned]) ], [ +#ifdef HAVE_TIME_H +#include +#endif +]) + + +AC_CHECK_TYPES([int8_t, int16_t, int32_t, int64_t, + u_int8_t, u_int16_t, u_int32_t, u_int64_t, + uint8_t, uint16_t, uint32_t, uint64_t],,,[ +#ifdef HAVE_INTTYPES_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_BITYPES_H +#include +#endif +#ifdef HAVE_BIND_BITYPES_H +#include +#endif +#ifdef HAVE_NETINET_IN6_MACHTYPES_H +#include +#endif +]) + +rk_FRAMEWORK_SECURITY +rk_FRAMEWORK_COREFOUNDATION + +KRB_READLINE + +rk_TELNET + +dnl Some operating systems already have com_err and compile_et +CHECK_COMPILE_ET + +rk_AUTH_MODULES([sia afskauthlib]) + +rk_DESTDIRS + +rk_WFLAGS([-Wall -Wmissing-prototypes -Wpointer-arith -Wbad-function-cast -Wmissing-declarations -Wnested-externs]) + + +AH_BOTTOM([#ifdef __APPLE__ +#include +#endif]) + +AH_BOTTOM([#ifdef ROKEN_RENAME +#include "roken_rename.h" +#endif]) + +AC_ARG_ENABLE(heimdal-documentation, + AS_HELP_STRING([--disable-heimdal-documentation], + [if you want disable to heimdal documentation])) +AM_CONDITIONAL(HEIMDAL_DOCUMENTATION, test "$enable_heimdal_documentation" != no) + +AC_CONFIG_FILES(Makefile \ + etc/Makefile \ + include/Makefile \ + include/gssapi/Makefile \ + include/hcrypto/Makefile \ + include/kadm5/Makefile \ + lib/Makefile \ + lib/base/Makefile \ + lib/asn1/Makefile \ + lib/com_err/Makefile \ + lib/hcrypto/Makefile \ + lib/hx509/Makefile \ + lib/gssapi/Makefile \ + lib/ntlm/Makefile \ + lib/hdb/Makefile \ + lib/ipc/Makefile \ + lib/kadm5/Makefile \ + lib/kafs/Makefile \ + lib/kdfs/Makefile \ + lib/krb5/Makefile \ + lib/otp/Makefile \ + lib/roken/Makefile \ + lib/sl/Makefile \ + lib/sqlite/Makefile \ + lib/vers/Makefile \ + lib/wind/Makefile \ + lib/gss_preauth/Makefile \ + po/Makefile \ + kuser/Makefile \ + kpasswd/Makefile \ + kadmin/Makefile \ + admin/Makefile \ + kcm/Makefile \ + kdc/Makefile \ + appl/Makefile \ + appl/afsutil/Makefile \ + appl/dbutils/Makefile \ + appl/gssmask/Makefile \ + appl/otp/Makefile \ + appl/test/Makefile \ + appl/kf/Makefile \ + appl/dceutils/Makefile \ + tests/Makefile \ + tests/bin/Makefile \ + tests/can/Makefile \ + tests/db/Makefile \ + tests/kdc/Makefile \ + tests/ldap/Makefile \ + tests/gss/Makefile \ + tests/java/Makefile \ + tests/plugin/Makefile \ + packages/Makefile \ + packages/mac/Makefile \ + doc/Makefile \ + tools/Makefile \ +) + +AC_OUTPUT + +dnl +dnl This is the release version name-number[beta] +dnl + +if test -d "$srcdir/.git"; then + cat > include/newversion.h.in < include/newversion.h.in </dev/null || + # Linux + date -u -d "@${SOURCE_DATE_EPOCH}" 2>/dev/null || + # Illumos -- sorry, no -r/-d here + date -u || + date` + else + Date=`date -u "+%Y-%m-%dT%H:%M:%SZ"` + fi + if test -n "$SOURCE_HOST"; then + Host=$SOURCE_HOST + else + Host=`uname -n` + fi + if test -n "$SOURCE_USER"; then + User=$SOURCE_USER + else + User=${USER:-${LOGNAME:-`id -nu`}} + fi + if test -d "$srcdir/.git"; then + GitCommit=`cd $srcdir && git rev-parse HEAD` + GitBranch=`cd $srcdir && git rev-parse --abbrev-ref HEAD` + if test "x$GitBranch" = master; then + GitDesc=`cd $srcdir && git describe --all --dirty` + else + GitDesc=`cd $srcdir && \ + git describe --tags --match 'heimdal-*' --dirty` + fi + else + GitCommit='' + GitBranch='' + GitDesc='' + fi + mv -f include/newversion.h.in include/version.h.in + sed -e "s/@HOST@/$Host/" \ + -e "s;@USER@;$User;" \ + -e "s;@DATE@;$Date;" \ + -e "s;@BRANCH@;$GitBranch;" \ + -e "s;@TAG@;$GitDesc;" \ + -e "s;@COMMIT@;$GitCommit;" \ + include/version.h.in > include/version.h +fi diff --git a/configure.in b/configure.in deleted file mode 100644 index b6c0c88e0..000000000 --- a/configure.in +++ /dev/null @@ -1,589 +0,0 @@ -dnl Process this file with autoconf to produce a configure script. -AC_REVISION($Revision$) -AC_PREREQ(2.62) -test -z "$CFLAGS" && CFLAGS="-g" -AC_INIT([Heimdal],[1.3.0pre1],[heimdal-bugs@h5l.org]) -AC_CONFIG_SRCDIR([kuser/kinit.c]) -AC_CONFIG_HEADERS(include/config.h) -AC_CONFIG_MACRO_DIR([cf]) - -AM_INIT_AUTOMAKE([foreign 1.10]) -AM_MAINTAINER_MODE - -dnl Checks for programs. -AC_PROG_CC -AM_PROG_CC_C_O -AC_PROG_CPP - -AC_PREFIX_DEFAULT(/usr/heimdal) - -test "$sysconfdir" = '${prefix}/etc' && sysconfdir='/etc' -test "$localstatedir" = '${prefix}/var' && localstatedir='/var/heimdal' - -AC_CANONICAL_HOST -CANONICAL_HOST=$host -AC_SUBST(CANONICAL_HOST) - -dnl Hints for autobuild -AB_INIT - -rk_SYS_LARGEFILE - -rk_AIX -rk_IRIX -rk_SUNOS - -dnl -dnl this is needed to run the configure tests against glibc -dnl -AC_DEFINE([_GNU_SOURCE], 1, - [Define to enable extensions on glibc-based systems such as Linux.]) - -AC_OBJEXT -AC_EXEEXT - -dnl AC_KRB_PROG_YACC -AC_PROG_YACC -AM_PROG_LEX -dnl AC_PROG_RANLIB -AC_PROG_AWK -AC_KRB_PROG_LN_S - -AC_MIPS_ABI -CC="$CC $abi" -libdir="$libdir$abilibdirext" - -AC_C___ATTRIBUTE__ - -LT_PREREQ([2.2]) -LT_INIT([shared static win32-dll]) - -AM_CONDITIONAL(ENABLE_SHARED, test "$enable_shared" = "yes") -rk_VERSIONSCRIPT - -rk_TEST_PACKAGE(openldap, -[#include -#include ], -[-lldap -llber],,,OPENLDAP) - -AC_ARG_ENABLE(hdb-openldap-module, - AS_HELP_STRING([--enable-hdb-openldap-module], - [if you want support to build openldap hdb as shared object])) -if test "$enable_hdb_openldap_module" = yes -a "$with_openldap" = yes; then - AC_DEFINE(OPENLDAP_MODULE, 1, [Define if you want support for hdb ldap module]) -fi -AM_CONDITIONAL(OPENLDAP_MODULE, test "$enable_hdb_openldap_module" = yes -a "$with_openldap" = yes) - -dnl -dnl Optional modules, pk-init, digest, kx509 -dnl - -AC_ARG_ENABLE(pk-init, - AS_HELP_STRING([--disable-pk-init], - [if you want disable to PK-INIT support])) -if test "$enable_pk_init" != no ;then - AC_DEFINE([PKINIT], 1, [Define to enable PKINIT.]) -fi -AM_CONDITIONAL(PKINIT, test "$enable_pk_init" != no) - -AC_ARG_ENABLE(digest, - AS_HELP_STRING([--disable-digest], - [if you want disable to DIGEST support])) -if test "$enable_digest" != no ;then - AC_DEFINE([DIGEST], 1, [Define to enable DIGEST.]) -fi - -AC_ARG_ENABLE(kx509, - AS_HELP_STRING([--disable-kx509], - [if you want disable to kx509 support])) -if test "$enable_kx509" != no ;then - AC_DEFINE([KX509], 1, [Define to enable kx509.]) -fi - -AC_ARG_ENABLE(krb4, - AS_HELP_STRING([--disable-krb4], - [if you want disable to krb4 support])) -if test "$enable_krb4" != no ;then - AC_DEFINE([KRB4], 1, [Define to enable Kerberos 4.]) -fi - - -dnl Check for sqlite -rk_TEST_PACKAGE(sqlite3, -[#include -#ifndef SQLITE_OPEN_CREATE -#error "old version" -#endif], -[-lsqlite3],,,SQLITE3) - -if test "X$with_sqlite3" != Xyes ; then - INCLUDE_sqlite3="-I\$(top_srcdir)/lib/sqlite" - LIB_sqlite3="\$(top_builddir)/lib/sqlite/libheimsqlite.la" -fi -AM_CONDITIONAL(SQLITE3, test "X$with_sqlite3" = Xyes) - -dnl check for libintl -rk_TEST_PACKAGE(libintl, -[#include ], -[-lintl],,,LIBINTL) - -dnl path where the hdb directory is stored -AC_ARG_WITH([hdbdir], - [AS_HELP_STRING([--with-hdbdir],[Default location for KDC database @<:@default=/var/heimdal@:>@])], - [], - [with_hdbdir=/var/heimdal]) -DIR_hdbdir="$with_hdbdir" -AC_SUBST([DIR_hdbdir]) - - -dnl no kerberos4 any more -with_krb4=no -AC_SUBST(INCLUDE_krb4) -AC_SUBST(LIB_krb4) -AM_CONDITIONAL(KRB4, false) - -AM_CONDITIONAL(KRB5, true) -AM_CONDITIONAL(do_roken_rename, true) - -AC_DEFINE(KRB5, 1, [Enable Kerberos 5 support in applications.])dnl -AC_SUBST(LIB_kdb)dnl - -KRB_CRYPTO - -KRB_PTHREADS - -AC_ARG_ENABLE(dce, - AS_HELP_STRING([--enable-dce],[if you want support for DCE/DFS PAG's])) -if test "$enable_dce" = yes; then - AC_DEFINE(DCE, 1, [Define if you want support for DCE/DFS PAG's.]) -fi -AM_CONDITIONAL(DCE, test "$enable_dce" = yes) - -## XXX quite horrible: -if test -f /etc/ibmcxx.cfg; then - dpagaix_ldadd=`sed -n '/^xlc_r4/,/^$/p' /etc/ibmcxx.cfg | sed -n -e '/libraries/{;s/^[[^=]]*=\(.*\)/\1/;s/,/ /gp;}'` - dpagaix_cflags=`sed -n '/^xlc_r4/,/^$/p' /etc/ibmcxx.cfg | sed -n -e '/options/{;s/^[[^=]]*=\(.*\)/\1/;s/-q[^,]*//;s/,/ /gp;}'` - dpagaix_ldflags= -else - dpagaix_cflags="-D_THREAD_SAFE -D_AIX_PTHREADS_D7 -D_AIX32_THREADS=1 -D_AES_SOURCE -D_AIX41 -I/usr/include/dce" - dpagaix_ldadd="-L/usr/lib/threads -ldcelibc_r -ldcepthreads -lpthreads_compat lpthreads -lc_r" - dpagaix_ldflags="-Wl,-bI:dfspag.exp" -fi -AC_SUBST(dpagaix_cflags) -AC_SUBST(dpagaix_ldadd) -AC_SUBST(dpagaix_ldflags) - -AC_ARG_ENABLE([afs-support], - AS_HELP_STRING([--disable-afs-support],[if you don't want support for AFS])) -if test "$enable_afs_support" = no; then - AC_DEFINE(NO_AFS, 1, [Define if you don't wan't support for AFS.]) -fi - -rk_DB - -dnl AC_ROKEN(10,[/usr/heimdal /usr/athena],[lib/roken],[$(top_builddir)/lib/roken/libroken.la],[-I$(top_builddir)/lib/roken -I$(top_srcdir)/lib/roken]) - -rk_ROKEN(lib/roken) -LIBADD_roken="$LIB_roken" -AC_SUBST(LIBADD_roken)dnl -LIB_roken="\$(top_builddir)/lib/vers/libvers.la $LIB_roken" - -rk_OTP - -AC_CHECK_OSFC2 - -AC_ARG_ENABLE(mmap, - AS_HELP_STRING([--disable-mmap],[disable use of mmap])) -if test "$enable_mmap" = "no"; then - AC_DEFINE(NO_MMAP, 1, [Define if you don't want to use mmap.]) -fi - -AC_ARG_ENABLE(afs-string-to-key, - AS_HELP_STRING([--disable-afs-string-to-key], - [disable use of weak AFS string-to-key functions]), - [], [enable_afs_string_to_key=yes]) - -if test "$enable_afs_string_to_key" = "yes"; then - AC_DEFINE(ENABLE_AFS_STRING_TO_KEY, 1, [Define if want to use the weak AFS string to key functions.]) -fi - - -rk_CHECK_MAN - -rk_TEST_PACKAGE(readline, -[#include - #include ],-lreadline,,, READLINE) - -rk_TEST_PACKAGE(hesiod,[#include ],-lhesiod,,, HESIOD) - -KRB_C_BIGENDIAN -AC_C_INLINE - -KRB_CHECK_X - -AM_CONDITIONAL(HAVE_X, test "$no_x" != yes) - -AC_CHECK_XAU - -dnl AM_C_PROTOTYPES - -dnl Checks for typedefs, structures, and compiler characteristics. -AC_C_CONST -AC_TYPE_OFF_T -AC_CHECK_TYPE_EXTRA(mode_t, unsigned short, []) -AC_CHECK_TYPE_EXTRA(sig_atomic_t, int, [#include ]) -AC_HAVE_TYPE([long long]) -AC_HEADER_TIME -AC_STRUCT_TM - -dnl Checks for header files. -AC_HEADER_STDC - -AC_CHECK_HEADERS([\ - arpa/ftp.h \ - arpa/telnet.h \ - bind/bitypes.h \ - bsdsetjmp.h \ - curses.h \ - dlfcn.h \ - fnmatch.h \ - inttypes.h \ - io.h \ - libutil.h \ - limits.h \ - maillock.h \ - netgroup.h \ - netinet/in6_machtypes.h \ - pthread.h \ - pty.h \ - sac.h \ - sgtty.h \ - siad.h \ - signal.h \ - strings.h \ - stropts.h \ - sys/bitypes.h \ - sys/category.h \ - sys/file.h \ - sys/filio.h \ - sys/ioccom.h \ - sys/mman.h \ - sys/param.h \ - sys/pty.h \ - sys/ptyio.h \ - sys/select.h \ - sys/socket.h \ - sys/str_tty.h \ - sys/stream.h \ - sys/stropts.h \ - sys/syscall.h \ - sys/termio.h \ - sys/timeb.h \ - sys/times.h \ - sys/types.h \ - sys/un.h \ - locale.h \ - termcap.h \ - termio.h \ - termios.h \ - time.h \ - tmpdir.h \ - udb.h \ - util.h \ - utmp.h \ - utmpx.h \ -]) - -dnl On Solaris 8 there's a compilation warning for term.h because -dnl it doesn't define `bool'. -AC_CHECK_HEADERS(term.h, , , -) - -dnl aix have asl.h (A/IX screen library) that we don't want -AC_CHECK_HEADERS(asl.h, , , [ -#include -#ifndef ASL_STRING_EMERG -#error ASL_STRING_EMERG missing -#endif]) - -AC_CHECK_HEADERS(net/if.h, , , [AC_INCLUDES_DEFAULT -#if HAVE_SYS_SOCKET_H -#include -#endif]) - -AC_CHECK_HEADERS(sys/ptyvar.h, , , [AC_INCLUDES_DEFAULT -#if HAVE_SYS_TTY_H -#include -#endif]) - -AC_CHECK_HEADERS(sys/strtty.h, , , [AC_INCLUDES_DEFAULT -#if HAVE_TERMIOS_H -#include -#endif -#if HAVE_SYS_STREAM_H -#include -#endif]) - -AC_CHECK_HEADERS(sys/ucred.h, , , [AC_INCLUDES_DEFAULT -#if HAVE_SYS_TYPES_H -#include -#endif -#if HAVE_SYS_PARAM_H -#include -#endif]) - -AC_CHECK_HEADERS(security/pam_modules.h, , , [AC_INCLUDES_DEFAULT -#include -]) - -dnl export symbols -rk_WIN32_EXPORT(BUILD_KRB5_LIB, KRB5_LIB) -rk_WIN32_EXPORT(BUILD_ROKEN_LIB, ROKEN_LIB) -rk_WIN32_EXPORT(BUILD_GSSAPI_LIB, GSSAPI_LIB) - -dnl Checks for libraries. - -AC_FIND_FUNC_NO_LIBS(logwtmp, util,[ -#ifdef HAVE_UTIL_H -#include -#endif -],[0,0,0]) -AC_FIND_FUNC_NO_LIBS(logout, util,[ -#ifdef HAVE_UTIL_H -#include -#endif -],[0]) -AC_FIND_FUNC_NO_LIBS(openpty, util,[ -#ifdef HAVE_UTIL_H -#include -#endif -],[0,0,0,0,0]) - -AC_FIND_FUNC_NO_LIBS(tgetent, termcap ncurses curses,[ -#ifdef HAVE_TERMCAP_H -#include -#endif -#ifdef HAVE_CURSES_H -#include -#endif -],[0,0]) - -dnl Checks for library functions. - -AC_CHECK_FUNCS([ \ - _getpty \ - _scrsize \ - arc4random \ - fcntl \ - getpeereid \ - getpeerucred \ - grantpt \ - mktime \ - ptsname \ - rand \ - revoke \ - select \ - setitimer \ - setpcred \ - setpgid \ - setproctitle \ - setregid \ - setresgid \ - setresuid \ - setreuid \ - setsid \ - setutent \ - sigaction \ - strstr \ - ttyname \ - ttyslot \ - umask \ - unlockpt \ - vhangup \ - yp_get_default_domain \ -]) - -AC_FUNC_MMAP - -KRB_CAPABILITIES - -AC_CHECK_GETPWNAM_R_POSIX - -dnl detect doors on solaris -if test "$enable_pthread_support" != no; then - saved_LIBS="$LIBS" - LIBS="$LIBS $PTHREADS_LIBS" - AC_FIND_FUNC_NO_LIBS(door_create, door) - LIBS="$saved_LIBS" -fi - -AC_ARG_ENABLE(kcm, - AS_HELP_STRING([--enable-kcm],[enable Kerberos Credentials Manager]), -,[enable_kcm=yes]) - -if test "$enable_kcm" = yes ; then - if test "$ac_cv_header_sys_un_h" != yes -a "$ac_cv_funclib_door_create" != yes ; then - enable_kcm=no - fi -fi -if test "$enable_kcm" = yes; then - AC_DEFINE(HAVE_KCM, 1, - [Define if you want to use the Kerberos Credentials Manager.]) -fi -AM_CONDITIONAL(KCM, test "$enable_kcm" = yes) - - - -dnl Cray stuff -AC_CHECK_FUNCS(getudbnam setlim) - -dnl AC_KRB_FUNC_GETCWD_BROKEN - -dnl -dnl Check for fields in struct utmp -dnl - -AC_HAVE_STRUCT_FIELD(struct utmp, ut_addr, [#include ]) -AC_HAVE_STRUCT_FIELD(struct utmp, ut_host, [#include ]) -AC_HAVE_STRUCT_FIELD(struct utmp, ut_id, [#include ]) -AC_HAVE_STRUCT_FIELD(struct utmp, ut_pid, [#include ]) -AC_HAVE_STRUCT_FIELD(struct utmp, ut_type, [#include ]) -AC_HAVE_STRUCT_FIELD(struct utmp, ut_user, [#include ]) -AC_HAVE_STRUCT_FIELD(struct utmpx, ut_exit, [#include ]) -AC_HAVE_STRUCT_FIELD(struct utmpx, ut_syslen, [#include ]) - -AC_CHECK_TYPES([int8_t, int16_t, int32_t, int64_t, - u_int8_t, u_int16_t, u_int32_t, u_int64_t, - uint8_t, uint16_t, uint32_t, uint64_t],,,[ -#ifdef HAVE_INTTYPES_H -#include -#endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_BITYPES_H -#include -#endif -#ifdef HAVE_BIND_BITYPES_H -#include -#endif -#ifdef HAVE_NETINET_IN6_MACHTYPES_H -#include -#endif -]) - -rk_FRAMEWORK_SECURITY - -KRB_READLINE - -rk_TELNET - -dnl Some operating systems already have com_err and compile_et -CHECK_COMPILE_ET - -rk_AUTH_MODULES([sia afskauthlib]) - -rk_DESTDIRS - -rk_WFLAGS([-Wall -Wmissing-prototypes -Wpointer-arith -Wbad-function-cast -Wmissing-declarations -Wnested-externs]) - - -AH_BOTTOM([#ifdef ROKEN_RENAME -#include "roken_rename.h" -#endif]) - -AC_CONFIG_FILES(Makefile \ - etc/Makefile \ - include/Makefile \ - include/gssapi/Makefile \ - include/hcrypto/Makefile \ - include/kadm5/Makefile \ - lib/Makefile \ - lib/45/Makefile \ - lib/auth/Makefile \ - lib/auth/afskauthlib/Makefile \ - lib/auth/pam/Makefile \ - lib/auth/sia/Makefile \ - lib/asn1/Makefile \ - lib/com_err/Makefile \ - lib/hcrypto/Makefile \ - lib/editline/Makefile \ - lib/hx509/Makefile \ - lib/gssapi/Makefile \ - lib/ntlm/Makefile \ - lib/hdb/Makefile \ - lib/kadm5/Makefile \ - lib/kafs/Makefile \ - lib/kdfs/Makefile \ - lib/krb5/Makefile \ - lib/otp/Makefile \ - lib/roken/Makefile \ - lib/sl/Makefile \ - lib/sqlite/Makefile \ - lib/vers/Makefile \ - lib/wind/Makefile \ - po/Makefile \ - kuser/Makefile \ - kpasswd/Makefile \ - kadmin/Makefile \ - admin/Makefile \ - kcm/Makefile \ - kdc/Makefile \ - appl/Makefile \ - appl/afsutil/Makefile \ - appl/ftp/Makefile \ - appl/ftp/common/Makefile \ - appl/ftp/ftp/Makefile \ - appl/ftp/ftpd/Makefile \ - appl/gssmask/Makefile \ - appl/kx/Makefile \ - appl/login/Makefile \ - appl/otp/Makefile \ - appl/popper/Makefile \ - appl/push/Makefile \ - appl/rsh/Makefile \ - appl/rcp/Makefile \ - appl/su/Makefile \ - appl/xnlock/Makefile \ - appl/telnet/Makefile \ - appl/telnet/libtelnet/Makefile \ - appl/telnet/telnet/Makefile \ - appl/telnet/telnetd/Makefile \ - appl/test/Makefile \ - appl/kf/Makefile \ - appl/dceutils/Makefile \ - tests/Makefile \ - tests/can/Makefile \ - tests/db/Makefile \ - tests/kdc/Makefile \ - tests/ldap/Makefile \ - tests/gss/Makefile \ - tests/java/Makefile \ - tests/plugin/Makefile \ - packages/Makefile \ - packages/mac/Makefile \ - doc/Makefile \ - tools/Makefile \ -) - -AC_OUTPUT - -dnl -dnl This is the release version name-number[beta] -dnl - -cat > include/newversion.h.in </dev/null | sed 1q` - Date=`date` - mv -f include/newversion.h.in include/version.h.in - sed -e "s/@USER@/$User/" -e "s/@HOST@/$Host/" -e "s/@DATE@/$Date/" include/version.h.in > include/version.h -fi diff --git a/doc/Makefile.am b/doc/Makefile.am index 792b8f3e6..60c6a8c58 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -4,12 +4,16 @@ include $(top_srcdir)/Makefile.am.common AUTOMAKE_OPTIONS = no-texinfo.tex -MAKEINFOFLAGS = --no-split --css-include=$(srcdir)/heimdal.css +MAKEINFOFLAGS = --css-include=$(srcdir)/heimdal.css -TEXI2DVI = true # ARGH, make distcheck can't be disabled to not build dvifiles +#TEXI2DVI = true # ARGH, make distcheck can't be disabled to not build dvifiles info_TEXINFOS = heimdal.texi hx509.texi +BUILT_SOURCES = vars.texi + +#all: html pdf dvi ps info + dxy_subst = sed -e 's,[@]srcdir[@],$(srcdir),g' \ -e 's,[@]objdir[@],.,g' \ -e 's,[@]PACKAGE_VERSION[@],$(PACKAGE_VERSION),g' @@ -24,6 +28,11 @@ hdb.dxy: hdb.din Makefile chmod +x hdb.dxy.tmp mv hdb.dxy.tmp hdb.dxy +base.dxy: base.din Makefile + $(dxy_subst) < $(srcdir)/base.din > base.dxy.tmp + chmod +x base.dxy.tmp + mv base.dxy.tmp base.dxy + hx509.dxy: hx509.din Makefile $(dxy_subst) < $(srcdir)/hx509.din > hx509.dxy.tmp chmod +x hx509.dxy.tmp @@ -50,6 +59,7 @@ wind.dxy: wind.din Makefile mv wind.dxy.tmp wind.dxy texi_subst = sed -e 's,[@]dbdir[@],$(localstatedir),g' \ + -e 's,[@]dbtype[@],$(db_type),g' \ -e 's,[@]PACKAGE_VERSION[@],$(PACKAGE_VERSION),g' vars.texi: vars.tin Makefile @@ -57,17 +67,24 @@ vars.texi: vars.tin Makefile chmod +x vars.texi.tmp mv vars.texi.tmp vars.texi -PROJECTS = hcrypto hdb hx509 gssapi krb5 ntlm wind +PROJECTS = base hdb hx509 gssapi krb5 ntlm wind -$(PROJECTS): doxygen +PROJECTS += hcrypto -doxygen: hdb.dxy hx509.dxy hcrypto.dxy gssapi.dxy krb5.dxy ntlm.dxy wind.dxy - @for a in $(PROJECTS) ; do \ +doxyout doxygen: base.dxy hdb.dxy hx509.dxy hcrypto.dxy gssapi.dxy krb5.dxy ntlm.dxy wind.dxy + @test -d $(srcdir)/doxyout && \ + find $(srcdir)/doxyout -type d ! -perm -200 -exec chmod u+w {} ';' ; \ + rm -rf $(srcdir)/doxyout ; \ + mkdir $(srcdir)/doxyout ; \ + for a in $(PROJECTS) ; do \ echo $$a ; \ - rm -rf $(srcdir)/$$a ; \ - mkdir $(srcdir)/$$a ; \ doxygen $$a.dxy; \ - (cd $(srcdir) && find $$a/man -type f > $$a/manpages ) ; \ + (cd $(srcdir)/doxyout && \ + find $$a/man -name '_*' -type f -print | \ + perl -lne unlink && \ + find $$a/html -name 'dir_*.html' -type f -print | \ + perl -lne unlink && \ + find $$a/man -type f > $$a/manpages ) ; \ done install-data-hook: install-doxygen-manpage @@ -76,19 +93,19 @@ dist-hook: doxygen install-doxygen-manpage: for a in $(PROJECTS) ; do \ - f="$(srcdir)/$$a/manpages" ; \ + f="$(srcdir)/doxyout/$$a/manpages" ; \ test -f $$f || continue ; \ - echo "install $$a manual pages" ; \ + echo "install $$a manual pages $$(wc -l < $$f)" ; \ while read x ; do \ section=`echo "$$x" | sed 's/.*\.\([0-9]\)/\1/'` ; \ $(mkinstalldirs) "$(DESTDIR)$(mandir)/man$$section" ; \ - $(INSTALL_DATA) $(srcdir)/$$x "$(DESTDIR)$(mandir)/man$$section" ; \ + $(INSTALL_DATA) $(srcdir)/doxyout/$$x "$(DESTDIR)$(mandir)/man$$section" ; \ done < $$f ; \ done ; exit 0 uninstall-doxygen-manpage: @for a in $(PROJECTS) ; do \ - f="$(srcdir)/$$a/manpages" ; \ + f="$(srcdir)/doxyout/$$a/manpages" ; \ test -f $$f || continue ; \ echo "removing $$a manual pages" ; \ while read x ; do \ @@ -106,7 +123,6 @@ heimdal_TEXINFOS = \ heimdal.texi \ install.texi \ intro.texi \ - kerberos4.texi \ migration.texi \ misc.texi \ programming.texi \ @@ -116,10 +132,15 @@ heimdal_TEXINFOS = \ win2k.texi EXTRA_DIST = \ - $(PROJECTS) \ + NTMakefile \ + doxyout \ + footer.html \ + gssapi.din \ hdb.din \ hcrypto.din \ + header.html \ heimdal.css \ + base.din \ hx509.din \ krb5.din \ ntlm.din \ @@ -128,10 +149,14 @@ EXTRA_DIST = \ layman.asc \ doxytmpl.dxy \ wind.din \ + base.hhp \ + heimdal.hhp \ + hx509.hhp \ vars.tin CLEANFILES = \ hcrypto.dxy* \ + base.dxy* \ hx509.dxy* \ hdb.dxy* \ gssapi.dxy* \ diff --git a/doc/NTMakefile b/doc/NTMakefile new file mode 100644 index 000000000..4769c9126 --- /dev/null +++ b/doc/NTMakefile @@ -0,0 +1,125 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=doc + +!include ../windows/NTMakefile.w32 + +heimdal_TEXINFOS = \ + $(OBJ)\ack.texi \ + $(OBJ)\apps.texi \ + $(OBJ)\copyright.texi \ + $(OBJ)\heimdal.texi \ + $(OBJ)\install.texi \ + $(OBJ)\intro.texi \ + $(OBJ)\migration.texi \ + $(OBJ)\misc.texi \ + $(OBJ)\programming.texi \ + $(OBJ)\setup.texi \ + $(OBJ)\vars.texi \ + $(OBJ)\whatis.texi \ + $(OBJ)\win2k.texi + +hx509_TEXINFOS = \ + $(OBJ)\hx509.texi + +{}.texi{$(OBJ)}.texi: + $(CP) $** $@ + +{}.tin{$(OBJ)}.texi: + $(SED) -e "s,[@]dbdir[@],x,g" \ + -e "s,[@]dbtype[@],sqlite,g" < $** > $@ \ + -e "s,[@]PACKAGE_VERSION[@],$(VER_PACKAGE_VERSION),g" < $** > $@ + +MAKEINFOFLAGS = --css-include=$(SRCDIR)/heimdal.css + +!ifdef APPVEYOR +MAKEINFO = $(PERL) C:\msys64\usr\bin\makeinfo +!endif + +###################################################################### +# Build heimdal.chm + +# Copyrights-and-Licenses.html is where the table of contents ends up +# when generating HTML output using makeinfo. Same goes for +# How-to-use-the-PKCS11-module.html below. + +$(OBJ)\heimdal\index.html $(OBJ)\heimdal\Copyrights-and-Licenses.html: $(heimdal_TEXINFOS) + cd $(OBJ) + $(MAKEINFO) $(MAKEINFOFLAGS) --html heimdal.texi + -$(MKDIR) heimdal + cd $(SRCDIR) + +$(OBJ)\heimdal\toc.hhc: $(OBJ)\heimdal\Copyrights-and-Licenses.html + $(PERL) $(SRC)\cf\w32-hh-toc-from-info.pl -o$@ $** + +$(OBJ)\heimdal\heimdal.hhp: heimdal.hhp + $(CP) $** $@ + +$(DOCDIR)\heimdal.chm: $(OBJ)\heimdal\heimdal.hhp $(OBJ)\heimdal\toc.hhc + cd $(OBJ)\heimdal + -$(HHC) heimdal.hhp + $(CP) heimdal.chm $@ + cd $(SRCDIR) + +###################################################################### +# Build hx509.chm + +$(OBJ)\hx509\index.html $(OBJ)\hx509\How-to-use-the-PKCS11-module.html: $(hx509_TEXINFOS) + cd $(OBJ) + $(MAKEINFO) $(MAKEINFOFLAGS) --html hx509.texi + -$(MKDIR) hx509 + cd $(SRCDIR) + +$(OBJ)\hx509\toc.hhc: $(OBJ)\hx509\How-to-use-the-PKCS11-module.html + $(PERL) $(SRC)\cf\w32-hh-toc-from-info.pl -o$@ $** + +$(OBJ)\hx509\hx509.hhp: hx509.hhp + $(CP) $** $@ + +$(DOCDIR)\hx509.chm: $(OBJ)\hx509\hx509.hhp $(OBJ)\hx509\toc.hhc + cd $(OBJ)\hx509 + -$(HHC) hx509.hhp + $(CP) hx509.chm $@ + cd $(SRCDIR) + +!ifndef NO_DOC +all:: $(OBJ)\heimdal\index.html $(OBJ)\hx509\index.html \ + $(DOCDIR)\heimdal.chm $(DOCDIR)\hx509.chm +!endif + +clean:: + -$(RM) $(OBJ)\heimdal\*.* + -$(RM) $(OBJ)\hx509\*.* + -$(RM) $(DOCDIR)\heimdal.chm + -$(RM) $(DOCDIR)\hx509.chm + +.SUFFIXES: .texi .tin diff --git a/doc/ack.texi b/doc/ack.texi index 567bf7c84..89b83c1b8 100644 --- a/doc/ack.texi +++ b/doc/ack.texi @@ -1,5 +1,3 @@ -@c $Id$ - @node Acknowledgments, Copyrights and Licenses, Migration, Top @comment node-name, next, previous, up @appendix Acknowledgments @@ -37,46 +35,87 @@ The @code{pkcs11.h} headerfile was written by the Scute project. Bugfixes, documentation, encouragement, and code has been contributed by: @table @asis @item Alexander Boström +@item Allan McRae @item Andrew Bartlett +@item Andrew Cobaugh +@item Andrew Tridge +@item Anton Lundin +@item Asanka Herath +@item Björn Grönvall @item Björn Sandell @item Björn Schlögl @item Brandon S. Allbery KF8NH @item Brian A May +@item Buck Huppmann +@item Cacdric Schieli @item Chaskiel M Grundman +@item Christos Zoulas @item Cizzi Storm @item Daniel Kouril @item David Love @item David Markey +@item David R Boldt @item Derrick J Brashear +@item Donald Norwood @item Douglas E Engert @item Frank van der Linden +@item Gabor Gombas @item Guido Günther +@item Guillaume Rousse +@item Harald Barth +@item Ingo Schwarze +@item Jacques A. Vidrine +@item Jaideep Padhye +@item Jan Rekorajski @item Jason McIntyre +@item Jeffrey Altman +@item Jelmer Vernooij +@item Joerg Pulz +@item Johan Danielsson +@item Johan Gadsjö @item Johan Ihrén @item John Center +@item Julian Ospald @item Jun-ichiro itojun Hagino @item KAMADA Ken'ichi +@item Kamen Mazdrashki +@item Karolin Seeger @item Ken Hornstein +@item Love Hörnquist Åstrand +@item Luke Howard @item Magnus Ahltorp +@item Magnus Holmberg @item Marc Horowitz @item Mario Strasser @item Mark Eichin -@item Mattias Amnefelt @item Martin von Gagern +@item Matthias Dieter Wallnöfer +@item Matthieu Patou +@item Mattias Amnefelt @item Michael B Allen @item Michael Fromberger @item Michal Vocu @item Milosz Kmieciak @item Miroslav Ruda @item Mustafa A. Hashmi +@item Nicolas Williams +@item Patrik Lundin @item Petr Holub @item Phil Fisher @item Rafal Malinowski +@item Ragnar Sundblad @item Rainer Toebbicke -@item Roman Divacky @item Richard Nyberg +@item Roland C. Dowdeswell +@item Roman Divacky +@item Russ Allbery @item Sho Hosoda, 細田 将 +@item Simon Wilkinson @item Stefan Metzmacher +@item Ted Percival +@item Timothy Pearson +@item Tom Payerle +@item Victor Guerra @item Zeqing Xia @item Åke Sandgren @item and we hope that those not mentioned here will forgive us. diff --git a/doc/apps.texi b/doc/apps.texi index 0aa987ab8..2b48edaaf 100644 --- a/doc/apps.texi +++ b/doc/apps.texi @@ -5,164 +5,10 @@ @chapter Applications @menu -* Authentication modules:: * AFS:: @end menu -@node Authentication modules, AFS, Applications, Applications -@section Authentication modules - -The problem of having different authentication mechanisms has been -recognised by several vendors, and several solutions have appeared. In -most cases these solutions involve some kind of shared modules that are -loaded at run-time. Modules for some of these systems can be found in -@file{lib/auth}. Presently there are modules for Digital's SIA, -and IRIX' @code{login} and @code{xdm} (in -@file{lib/auth/afskauthlib}). - -@menu -* Digital SIA:: -* IRIX:: -@end menu - -@node Digital SIA, IRIX, Authentication modules, Authentication modules -@subsection Digital SIA - -How to install the SIA module depends on which OS version you're -running. Tru64 5.0 has a new command, @file{siacfg}, which makes this -process quite simple. If you have this program, you should just be able -to run: -@example -siacfg -a KRB5 /usr/athena/lib/libsia_krb5.so -@end example - -On older versions, or if you want to do it by hand, you have to do the -following (not tested by us on Tru64 5.0): - -@itemize @bullet - -@item -Make sure @file{libsia_krb5.so} is available in -@file{/usr/athena/lib}. If @file{/usr/athena} is not on local disk, you -might want to put it in @file{/usr/shlib} or someplace else. If you do, -you'll have to edit @file{krb5_matrix.conf} to reflect the new location -(you will also have to do this if you installed in some other directory -than @file{/usr/athena}). If you built with shared libraries, you will -have to copy the shared @file{libkrb.so}, @file{libdes.so}, -@file{libkadm.so}, and @file{libkafs.so} to a place where the loader can -find them (such as @file{/usr/shlib}). -@item -Copy (your possibly edited) @file{krb5_matrix.conf} to @file{/etc/sia}. -@item -Apply @file{security.patch} to @file{/sbin/init.d/security}. -@item -Turn on KRB5 security by issuing @kbd{rcmgr set SECURITY KRB5} and -@kbd{rcmgr set KRB5_MATRIX_CONF krb5_matrix.conf}. -@item -Digital thinks you should reboot your machine, but that really shouldn't -be necessary. It's usually sufficient just to run -@kbd{/sbin/init.d/security start} (and restart any applications that use -SIA, like @code{xdm}.) -@end itemize - -Users with local passwords (like @samp{root}) should be able to login -safely. - -When using Digital's xdm the @samp{KRB5CCNAME} environment variable isn't -passed along as it should (since xdm zaps the environment). Instead you -have to set @samp{KRB5CCNAME} to the correct value in -@file{/usr/lib/X11/xdm/Xsession}. Add a line similar to -@example -KRB5CCNAME=FILE:/tmp/krb5cc`id -u`_`ps -o ppid= -p $$`; export KRB5CCNAME -@end example -If you use CDE, @code{dtlogin} allows you to specify which additional -environment variables it should export. To add @samp{KRB5CCNAME} to this -list, edit @file{/usr/dt/config/Xconfig}, and look for the definition of -@samp{exportList}. You want to add something like: -@example -Dtlogin.exportList: KRB5CCNAME -@end example - -@subsubheading Notes to users with Enhanced security - -Digital's @samp{ENHANCED} (C2) security, and Kerberos solve two -different problems. C2 deals with local security, adds better control of -who can do what, auditing, and similar things. Kerberos deals with -network security. - -To make C2 security work with Kerberos you will have to do the -following. - -@itemize @bullet -@item -Replace all occurrences of @file{krb5_matrix.conf} with -@file{krb5+c2_matrix.conf} in the directions above. -@item -You must enable ``vouching'' in the @samp{default} database. This will -make the OSFC2 module trust other SIA modules, so you can login without -giving your C2 password. To do this use @samp{edauth} to edit the -default entry @kbd{/usr/tcb/bin/edauth -dd default}, and add a -@samp{d_accept_alternate_vouching} capability, if not already present. -@item -For each user who does @emph{not} have a local C2 password, you should -set the password expiration field to zero. You can do this for each -user, or in the @samp{default} table. To do this use @samp{edauth} to -set (or change) the @samp{u_exp} capability to @samp{u_exp#0}. -@item -You also need to be aware that the shipped @file{login}, @file{rcp}, and -@file{rshd}, don't do any particular C2 magic (such as checking for -various forms of disabled accounts), so if you rely on those features, -you shouldn't use those programs. If you configure with -@samp{--enable-osfc2}, these programs will, however, set the login -UID. Still: use at your own risk. -@end itemize - -At present @samp{su} does not accept the vouching flag, so it will not -work as expected. - -Also, kerberised ftp will not work with C2 passwords. You can solve this -by using both Digital's ftpd and our on different ports. - -@strong{Remember}, if you do these changes you will get a system that -most certainly does @emph{not} fulfil the requirements of a C2 -system. If C2 is what you want, for instance if someone else is forcing -you to use it, you're out of luck. If you use enhanced security because -you want a system that is more secure than it would otherwise be, you -probably got an even more secure system. Passwords will not be sent in -the clear, for instance. - -@node IRIX, , Digital SIA, Authentication modules -@subsection IRIX - -The IRIX support is a module that is compatible with Transarc's -@file{afskauthlib.so}. It should work with all programs that use this -library. This should include @command{login} and @command{xdm}. - -The interface is not very documented but it seems that you have to copy -@file{libkafs.so}, @file{libkrb.so}, and @file{libdes.so} to -@file{/usr/lib}, or build your @file{afskauthlib.so} statically. - -The @file{afskauthlib.so} itself is able to reside in -@file{/usr/vice/etc}, @file{/usr/afsws/lib}, or the current directory -(wherever that is). - -IRIX 6.4 and newer seem to have all programs (including @command{xdm} and -@command{login}) in the N32 object format, whereas in older versions they -were O32. For it to work, the @file{afskauthlib.so} library has to be in -the same object format as the program that tries to load it. This might -require that you have to configure and build for O32 in addition to the -default N32. - -Apart from this it should ``just work''; there are no configuration -files. - -Note that recent Irix 6.5 versions (at least 6.5.22) have PAM, -including a @file{pam_krb5.so} module. Not all relevant programs use -PAM, though, e.g.@: @command{ssh}. In particular, for console -graphical login you need to turn off @samp{visuallogin} and turn on -@samp{xdm} with @command{chkconfig}. - -@node AFS, , Authentication modules, Applications +@node AFS, , Applications, Applications @section AFS @cindex AFS @@ -174,6 +20,32 @@ For more information about AFS see OpenAFS @url{http://www.openafs.org/} and Arla @url{http://www.stacken.kth.se/projekt/arla/}. +@subsection kafs and afslog +@cindex afslog + +@manpage{afslog,1} will obtains AFS tokens for a number of cells. What cells to get +tokens for can either be specified as an explicit list, as file paths to +get tokens for, or be left unspecified, in which case will use whatever +magic @manpage{kafs,3} decides upon. + +If not told what cell to get credentials for, @manpage{kafs,3} will +search for the files ThisCell and TheseCells in the locations +specified in @manpage{kafs,3} and try to get tokens for these cells +and the cells specified in $HOME/.TheseCells. + +More usefully it will look at and ~/.TheseCells in your home directory +and for each line which is a cell get afs token for these cells. + +The TheseCells file defines the the cells to which applications on the +local client machine should try to aquire tokens for. It must reside in +the directories searched by @manpage{kafs,3} on every AFS client machine. + +The file is in ASCII format and contains one character string, the cell +name, per line. Cell names are case sensitive, but most cell names +are lower case. + +See manpage for @manpage{kafs,3} for search locations of ThisCell and TheseCells. + @subsection How to get a KeyFile @file{ktutil -k AFSKEYFILE:KeyFile get afs@@MY.REALM} @@ -197,48 +69,3 @@ AFS-cell. If keyfile already exists, this will add the new key in afs-srvtab to KeyFile. -@section Using 2b tokens with AFS - -@subsection What is 2b ? - -2b is the name of the proposal that was implemented to give basic -Kerberos 5 support to AFS in rxkad. It's not real Kerberos 5 support -since it still uses fcrypt for data encryption and not Kerberos -encryption types. - -Its only possible (in all cases) to do this for DES encryption types -because only then the token (the AFS equivalent of a ticket) will be -smaller than the maximum size that can fit in the token cache in the -OpenAFS/Transarc client. It is a so tight fit that some extra wrapping -on the ASN1/DER encoding is removed from the Kerberos ticket. - -2b uses a Kerberos 5 EncTicketPart instead of a Kerberos 4 ditto for -the part of the ticket that is encrypted with the service's key. The -client doesn't know what's inside the encrypted data so to the client -it doesn't matter. - -To differentiate between Kerberos 4 tickets and Kerberos 5 tickets, 2b -uses a special kvno, 213 for 2b tokens and 255 for Kerberos 5 tokens. - -Its a requirement that all AFS servers that support 2b also support -native Kerberos 5 in rxkad. - -@subsection Configuring a Heimdal kdc to use 2b tokens - -Support for 2b tokens in the kdc are turned on for specific principals -by adding them to the string list option @code{[kdc]use_2b} in the -kdc's @file{krb5.conf} file. - -@example -[kdc] - use_2b = @{ - afs@@SU.SE = yes - afs/it.su.se@@SU.SE = yes - @} -@end example - -@subsection Configuring AFS clients for 2b support - -There is no need to configure AFS clients for 2b support. The only -software that needs to be installed/upgrade is a Kerberos 5 enabled -@file{afslog}. diff --git a/doc/base.din b/doc/base.din new file mode 100644 index 000000000..3ef6d404a --- /dev/null +++ b/doc/base.din @@ -0,0 +1,15 @@ +# Doxyfile 1.5.3 + +PROJECT_NAME = Heimdal base library +PROJECT_NUMBER = @PACKAGE_VERSION@ +OUTPUT_DIRECTORY = @srcdir@/doxyout/base +INPUT = @srcdir@/../lib/base + +WARN_IF_UNDOCUMENTED = YES + +PERL_PATH = /usr/bin/perl + +HTML_HEADER = "@srcdir@/header.html" +HTML_FOOTER = "@srcdir@/footer.html" + +@INCLUDE = "@srcdir@/doxytmpl.dxy" diff --git a/doc/base.hhp b/doc/base.hhp new file mode 100644 index 000000000..e1a3d3cf5 --- /dev/null +++ b/doc/base.hhp @@ -0,0 +1,8 @@ +[OPTIONS] +Compatibility=1.1 or later +Compiled file=heimbase.chm +Contents file=toc.hhc +Default topic=index.html +Display compile progress=No +Language=0x409 English (United States) +Title=Heimdal Base diff --git a/doc/copyright.texi b/doc/copyright.texi index d085731d0..7dd4cc9a0 100644 --- a/doc/copyright.texi +++ b/doc/copyright.texi @@ -1,6 +1,6 @@ @macro copynext{} -@vskip 20pt plus 1fil@penalty-1000 +@vskip 20pt plus 1fil @end macro @macro copyrightstart{} @@ -10,19 +10,19 @@ @end macro -@node Copyrights and Licenses, , Acknowledgments, Top @comment node-name, next, previous, up -@appendix Copyrights and Licenses @heading Kungliga Tekniska Högskolan @copyrightstart @verbatim -Copyright (c) 1997-2008 Kungliga Tekniska Högskolan +Copyright (c) 1997-2011 Kungliga Tekniska Högskolan (Royal Institute of Technology, Stockholm, Sweden). All rights reserved. +Portions Copyright (c) 2009 Apple Inc. All rights reserved. + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -82,7 +82,7 @@ or implied warranty. @heading The Regents of the University of California -The parts of the libroken, most of libtelnet, libeditline, telnet, ftp, +The parts of the libroken, most of libtelnet, telnet, ftp, and popper. @verbatim @@ -120,66 +120,80 @@ SUCH DAMAGE. @end verbatim @copynext -@heading Simmule Turner and Rich Salz +@heading The Regents of the University of California. -libeditline +libedit @verbatim -Copyright 1992 Simmule Turner and Rich Salz. All rights reserved. +Copyright (c) 1992, 1993 + The Regents of the University of California. All rights reserved. -This software is not subject to any license of the American Telephone -and Telegraph Company or of the Regents of the University of California. +This code is derived from software contributed to Berkeley by +Christos Zoulas of Cornell University. -Permission is granted to anyone to use this software for any purpose on -any computer system, and to alter it and redistribute it freely, subject -to the following restrictions: +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. -1. The authors are not responsible for the consequences of use of this - software, no matter how awful, even if they arise from flaws in it. - -2. The origin of this software must not be misrepresented, either by - explicit claim or by omission. Since few users ever read sources, - credits must appear in the documentation. - -3. Altered versions must be plainly marked as such, and must not be - misrepresented as being the original software. Since few users - ever read sources, credits must appear in the documentation. - -4. This notice may not be removed or altered. +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. @end verbatim @copynext -@heading Michael J. Fromberger +@heading TomsFastMath / LibTomMath -The RSA/DH support for libhcrypto. +Tom's fast math (bignum support) and LibTomMath @verbatim -IMath is Copyright 2002-2005 Michael J. Fromberger -You may use it subject to the following Licensing Terms: + The LibTom license -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: +This is free and unencumbered software released into the public domain. -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to + +@end verbatim -@end verbatim @copynext @heading Doug Rabson @@ -218,13 +232,17 @@ SUCH DAMAGE. @heading PADL Software Pty Ltd @table @asis -@item CFX implementation for GSS-API krb5 mech. +@item GSS-API CFX, SPNEGO, naming extensions, API extensions. @item KCM credential cache. +@item HDB LDAP backend. @end table @verbatim -Copyright (c) 2003, PADL Software Pty Ltd. +Copyright (c) 2003-2011, PADL Software Pty Ltd. +Copyright (c) 2004, Andrew Bartlett. +Copyright (c) 2003 - 2008, Kungliga Tekniska Högskolan +Copyright (c) 2015, Timothy Pearson. All rights reserved. Redistribution and use in source and binary forms, with or without @@ -389,6 +407,38 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @end verbatim @copynext +@heading Apple, Inc + +kdc/announce.c + +@verbatim + +Copyright (c) 2008 Apple Inc. All Rights Reserved. + +Export of this software from the United States of America may require +a specific license from the United States Government. It is the +responsibility of any person or organization contemplating export to +obtain such a license before exporting. + +WITHIN THAT CONSTRAINT, permission to use, copy, modify, and +distribute this software and its documentation for any purpose and +without fee is hereby granted, provided that the above copyright +notice appear in all copies and that both that copyright notice and +this permission notice appear in supporting documentation, and that +the name of Apple Inc. not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. Apple Inc. makes no representations about the suitability of +this software for any purpose. It is provided "as is" without express +or implied warranty. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +@end verbatim + +@copynext + @heading Richard Outerbridge DES core in libhcrypto @@ -411,5 +461,84 @@ Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge. @end verbatim +@copynext + +@heading Secure Endpoints Inc + +Windows support + +@verbatim + +Copyright (c) 2009-2015, Secure Endpoints Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. + +@end verbatim + +@copynext + +@heading Novell, Inc + +lib/hcrypto/test_dh.c + +@verbatim + +Copyright (c) 2007, Novell, Inc. +Author: Matthias Koenig + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the Novell nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + + +@end verbatim @copyrightend diff --git a/doc/doxytmpl.dxy b/doc/doxytmpl.dxy index a16b0d8ce..1faab2f52 100644 --- a/doc/doxytmpl.dxy +++ b/doc/doxytmpl.dxy @@ -26,7 +26,6 @@ SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO -DETAILS_AT_TOP = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 8 @@ -65,7 +64,6 @@ GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES -SHOW_DIRECTORIES = NO FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages @@ -105,8 +103,7 @@ FILE_PATTERNS = *.c \ *.inc \ *.m \ *.mm \ - *.dox \ - *.py + *.dox RECURSIVE = YES EXCLUDE = EXCLUDE_SYMLINKS = NO @@ -142,7 +139,6 @@ GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_STYLESHEET = -HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO HTML_DYNAMIC_SECTIONS = NO CHM_FILE = @@ -190,8 +186,6 @@ MAN_LINKS = YES #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml -XML_SCHEMA = -XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output @@ -213,7 +207,7 @@ EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = -PREDEFINED = +PREDEFINED = DOXY EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- @@ -227,7 +221,6 @@ EXTERNAL_GROUPS = YES # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = NO -MSCGEN_PATH = /Applications/Doxygen.app/Contents/Resources/ HIDE_UNDOC_RELATIONS = YES HAVE_DOT = YES CLASS_GRAPH = YES @@ -242,7 +235,6 @@ CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png -DOT_PATH = /Applications/Doxygen.app/Contents/Resources/ DOTFILE_DIRS = DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 1000 diff --git a/doc/gssapi.din b/doc/gssapi.din index 888961ec1..3dd8bb612 100644 --- a/doc/gssapi.din +++ b/doc/gssapi.din @@ -2,7 +2,7 @@ PROJECT_NAME = Heimdal GSS-API library PROJECT_NUMBER = @PACKAGE_VERSION@ -OUTPUT_DIRECTORY = @srcdir@/gssapi +OUTPUT_DIRECTORY = @srcdir@/doxyout/gssapi INPUT = @srcdir@/../lib/gssapi WARN_IF_UNDOCUMENTED = NO diff --git a/doc/hcrypto.din b/doc/hcrypto.din index 217fa9329..aeea17921 100644 --- a/doc/hcrypto.din +++ b/doc/hcrypto.din @@ -2,7 +2,7 @@ PROJECT_NAME = "Heimdal crypto library" PROJECT_NUMBER = @PACKAGE_VERSION@ -OUTPUT_DIRECTORY = @srcdir@/hcrypto +OUTPUT_DIRECTORY = @srcdir@/doxyout/hcrypto INPUT = @srcdir@/../lib/hcrypto EXAMPLE_PATH = @srcdir@/../lib/hcrypto diff --git a/doc/hdb.din b/doc/hdb.din index 564745119..1b100f46f 100644 --- a/doc/hdb.din +++ b/doc/hdb.din @@ -2,7 +2,7 @@ PROJECT_NAME = Heimdal hdb library PROJECT_NUMBER = @PACKAGE_VERSION@ -OUTPUT_DIRECTORY = @srcdir@/hdb +OUTPUT_DIRECTORY = @srcdir@/doxyout/hdb INPUT = @srcdir@/../lib/hdb WARN_IF_UNDOCUMENTED = YES diff --git a/doc/header.html b/doc/header.html index 4b0b17e54..b3401c8b8 100644 --- a/doc/header.html +++ b/doc/header.html @@ -7,3 +7,4 @@

    keyhole logo

    + diff --git a/doc/heimdal.hhp b/doc/heimdal.hhp new file mode 100644 index 000000000..2996baa2f --- /dev/null +++ b/doc/heimdal.hhp @@ -0,0 +1,8 @@ +[OPTIONS] +Compatibility=1.1 or later +Compiled file=heimdal.chm +Contents file=toc.hhc +Default topic=index.html +Display compile progress=No +Language=0x409 English (United States) +Title=Heimdal \ No newline at end of file diff --git a/doc/heimdal.texi b/doc/heimdal.texi index d3c71396b..00041ca76 100644 --- a/doc/heimdal.texi +++ b/doc/heimdal.texi @@ -1,4 +1,5 @@ \input texinfo @c -*- texinfo -*- + @c %**start of header @c $Id$ @setfilename heimdal.info @@ -7,36 +8,33 @@ @afourpaper @end iftex @c some sensible characters, please? -@tex -\input latin1.tex -@end tex +@documentencoding UTF-8 @setchapternewpage on @syncodeindex pg cp @c %**end of header @include vars.texi -@set UPDATED $Date$ @set VERSION @value{PACKAGE_VERSION} @set EDITION 1.0 @ifinfo @dircategory Security @direntry -* Heimdal: (heimdal). The Kerberos 5 distribution from KTH +* Heimdal: (heimdal). The Kerberos 5 and PKIX distribution from KTH @end direntry @end ifinfo @c title page @titlepage @title Heimdal -@subtitle Kerberos 5 from KTH +@subtitle Kerberos 5 and PKIX from KTH @subtitle Edition @value{EDITION}, for version @value{VERSION} @subtitle 2008 @author Johan Danielsson @author Love Hörnquist Åstrand @author Assar Westerlund -@author last updated @value{UPDATED} +@author et al @end titlepage @@ -61,18 +59,20 @@ @top Heimdal @end ifnottex -This manual is last updated @value{UPDATED} for version -@value{VERSION} of Heimdal. +This manual for version @value{VERSION} of Heimdal. @menu * Introduction:: * What is Kerberos?:: +* What is PKIX?:: +* What is a Certification Authority (CA)?:: +* What is kx509?:: +* What is bx509?:: * Building and Installing:: * Setting up a realm:: * Applications:: * Things in search for a better place:: -* Kerberos 4 issues:: -* Windows 2000 compatability:: +* Windows compatibility:: * Programming with Kerberos:: * Migration:: * Acknowledgments:: @@ -87,45 +87,34 @@ Setting up a realm * Creating the database:: * Modifying the database:: * keytabs:: -* Serving Kerberos 4/524/kaserver:: * Remote administration:: * Password changing:: * Testing clients and servers:: * Slave Servers:: * Incremental propagation:: * Encryption types and salting:: +* Credential cache server - KCM:: * Cross realm:: * Transit policy:: * Setting up DNS:: * Using LDAP to store the database:: * Providing Kerberos credentials to servers and programs:: * Setting up PK-INIT:: +* Debugging Kerberos problems:: Applications -* Authentication modules:: * AFS:: -Authentication modules +Windows compatibility -* Digital SIA:: -* IRIX:: - -Kerberos 4 issues - -* Principal conversion issues:: -* Converting a version 4 database:: -* kaserver:: - -Windows 2000 compatability - -* Configuring Windows 2000 to use a Heimdal KDC:: -* Inter-Realm keys (trust) between Windows 2000 and a Heimdal KDC:: +* Configuring Windows to use a Heimdal KDC:: +* Inter-Realm keys (trust) between Windows and a Heimdal KDC:: * Create account mappings:: * Encryption types:: * Authorisation data:: * Quirks of Windows 2000 KDC:: -* Useful links when reading about the Windows 2000:: +* Useful links when reading about the Windows:: Programming with Kerberos @@ -138,14 +127,14 @@ Programming with Kerberos @include setup.texi @include apps.texi @include misc.texi -@include kerberos4.texi @include win2k.texi @include programming.texi @include migration.texi @include ack.texi +@node Copyrights and Licenses, , Acknowledgments, Top + @comment node-name, next, previous, up @include copyright.texi @c @shortcontents -@contents @bye diff --git a/doc/hx509.din b/doc/hx509.din index 8951b9e5a..c6d02b287 100644 --- a/doc/hx509.din +++ b/doc/hx509.din @@ -2,7 +2,7 @@ PROJECT_NAME = Heimdal x509 library PROJECT_NUMBER = @PACKAGE_VERSION@ -OUTPUT_DIRECTORY = @srcdir@/hx509 +OUTPUT_DIRECTORY = @srcdir@/doxyout/hx509 INPUT = @srcdir@/../lib/hx509 WARN_IF_UNDOCUMENTED = YES diff --git a/doc/hx509.hhp b/doc/hx509.hhp new file mode 100644 index 000000000..bce680aa9 --- /dev/null +++ b/doc/hx509.hhp @@ -0,0 +1,8 @@ +[OPTIONS] +Compatibility=1.1 or later +Compiled file=hx509.chm +Contents file=toc.hhc +Default topic=index.html +Display compile progress=No +Language=0x409 English (United States) +Title=HX509 \ No newline at end of file diff --git a/doc/hx509.texi b/doc/hx509.texi index 75227797a..4d0f05682 100644 --- a/doc/hx509.texi +++ b/doc/hx509.texi @@ -7,16 +7,13 @@ @afourpaper @end iftex @c some sensible characters, please? -@tex -\input latin1.tex -@end tex +@documentencoding UTF-8 @setchapternewpage on @syncodeindex pg cp @c %**end of header @include vars.texi -@set UPDATED $Date$ @set VERSION @value{PACKAGE_VERSION} @set EDITION 1.0 @@ -34,14 +31,24 @@ @subtitle Edition @value{EDITION}, for version @value{VERSION} @subtitle 2008 @author Love Hörnquist Åstrand -@author last updated @value{UPDATED} -@def@copynext{@vskip 20pt plus 1fil@penalty-1000} +@iftex +@def@copynext{@vskip 20pt plus 1fil} @def@copyrightstart{} @def@copyrightend{} +@end iftex +@ifnottex +@macro copynext +@end macro +@macro copyrightstart +@end macro +@macro copyrightend +@end macro +@end ifnottex + @page @copyrightstart -Copyright (c) 1994-2008 Kungliga Tekniska Högskolan +Copyright (c) 1994-2019 Kungliga Tekniska Högskolan (Royal Institute of Technology, Stockholm, Sweden). All rights reserved. @@ -176,16 +183,22 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @top Heimdal @end ifnottex -This manual is last updated @value{UPDATED} for version -@value{VERSION} of hx509. +This manual is for version @value{VERSION} of hx509. @menu * Introduction:: -* What is X.509 ?:: +* What are X.509 and PKIX ?:: * Setting up a CA:: * CMS signing and encryption:: * Certificate matching:: * Software PKCS 11 module:: +* Creating a CA certificate:: +* Issuing certificates:: +* Issuing CRLs:: +* Application requirements:: +* CMS background:: +* Matching syntax:: +* How to use the PKCS11 module:: @detailmenu --- The Detailed Node Listing --- @@ -217,13 +230,20 @@ Software PKCS 11 module @end detailmenu @end menu -@node Introduction, What is X.509 ?, Top, Top +@node Introduction, What are X.509 and PKIX ?, Top, Top @chapter Introduction -The goals of a PKI infrastructure (as defined in -RFC 3280) is to meet -@emph{the needs of deterministic, automated identification, authentication, access control, and authorization}. +A Public Key Infrastructure (PKI) is an authentication mechanism based on +entities having certified cryptographic public keys and corresponding private +(secret) keys. +The ITU-T PKI specifications are designated "x.509", while the IETF PKI +specifications (PKIX) are specified by a number of Internet RFCs and are based +on x.509. + +The goals of a PKI (as stated in +RFC 5280) is to meet +@emph{the needs of deterministic, automated identification, authentication, access control, and authorization}. The administrator should be aware of certain terminologies as explained by the aforementioned RFC before attemping to put in place a PKI infrastructure. Briefly, these are: @@ -233,6 +253,9 @@ RFC before attemping to put in place a PKI infrastructure. Briefly, these are: Certificate Authority @item RA Registration Authority, i.e., an optional system to which a CA delegates certain management functions. +@item Certificate +A binary document that names an entity and its public key and which is signed +by an issuing CA. @item CRL Issuer An optional system to which a CA delegates the publication of certificate revocation lists. @item Repository @@ -240,7 +263,7 @@ A system or collection of distributed systems that stores certificates and CRLs and serves as a means of distributing these certificates and CRLs to end entities @end itemize -hx509 (Heimdal x509 support) is a near complete X.509 stack that can +hx509 (Heimdal x509 support) is a near complete X.509/PKIX stack that can handle CMS messages (crypto system used in S/MIME and Kerberos PK-INIT) and basic certificate processing tasks, path construction, path validation, OCSP and CRL validation, PKCS10 message construction, CMS @@ -250,10 +273,13 @@ signed), and CMS EnvelopedData (certificate encrypted). hx509 can use PKCS11 tokens, PKCS12 files, PEM files, and/or DER encoded files. -@node What is X.509 ?, Setting up a CA, Introduction, Top -@chapter What is X.509, PKIX, PKCS7 and CMS ? +hx509 consists of a library (libhx509) and a command-line utility (hxtool), as +well as a RESTful, HTTPS-based service that implements an online CA. -X.509 was created by CCITT (later ITU) for the X.500 directory +@node What are X.509 and PKIX ?, Setting up a CA, Introduction, Top +@chapter What are X.509 and PKIX, PKIX, PKCS7 and CMS ? + +X.509 was created by CCITT (later ITU-T) for the X.500 directory service. Today, X.509 discussions and implementations commonly reference the IETF's PKIX Certificate and CRL Profile of the X.509 v3 certificate standard, as specified in RFC 3280. @@ -335,7 +361,7 @@ The process starts by looking at the issuing CA of the certificate, by Name or Key Identifier, and tries to find that certificate while at the same time evaluting any policies in-place. -@node Setting up a CA, Creating a CA certificate, What is X.509 ?, Top +@node Setting up a CA, Creating a CA certificate, What are X.509 and PKIX ?, Top @chapter Setting up a CA Do not let information overload scare you off! If you are simply testing diff --git a/doc/install.texi b/doc/install.texi index f791f16e7..26008fcde 100644 --- a/doc/install.texi +++ b/doc/install.texi @@ -1,107 +1,8 @@ -@c $Id$ - -@node Building and Installing, Setting up a realm, What is Kerberos?, Top +@node Building and Installing, Setting up a realm, What is bx509?, Top @comment node-name, next, previous, up @chapter Building and Installing -Heimdal uses GNU Autoconf to configure for specific hosts, and GNU -Automake to manage makefiles. If this is new to you, the short -instruction is to run the @code{configure} script in the top level -directory, and when that finishes @code{make}. +Build and install instructions are located here: -If you want to build the distribution in a different directory from the -source directory, you will need a make that implements VPATH correctly, -such as GNU make. +@url{https://github.com/heimdal/heimdal/wiki} -You will need to build the distribution: - -@itemize @bullet -@item -A compiler that supports a ``loose'' ANSI C mode, such as @code{gcc}. -@item -lex or flex -@item -awk -@item -yacc or bison -@item -a socket library -@item -NDBM or Berkeley DB for building the server side. -@end itemize - -When everything is built, you can install by doing @kbd{make -install}. The default location for installation is @file{/usr/heimdal}, -but this can be changed by running @code{configure} with -@samp{--prefix=/some/other/place}. - -If you need to change the default behaviour, configure understands the -following options: - -@table @asis -@item @kbd{--without-berkeley-db} -DB is preferred before NDBM, but if you for some reason want to use NDBM -instead, you can use this option. - -@item @kbd{--with-krb4=@file{dir}} -Gives the location of Kerberos 4 libraries and headers. This enables -Kerberos 4 support in the applications (telnet, rsh, popper, etc) and -the KDC. It is automatically found if present under -@file{/usr/athena}. If you keep libraries and headers in different -places, you can instead give the path to each with the -@kbd{--with-krb4-lib=@file{dir}}, and -@kbd{--with-krb4-include=@file{dir}} options. - -You will need a fairly recent version of our Kerberos 4 distribution for -@code{rshd} and @code{popper} to support version 4 clients. - -@item @kbd{--enable-dce} -Enables support for getting DCE credentials and tokens. See the README -files in @file{appl/dceutils} for more information. - -@item @kbd{--disable-otp} -By default some of the application programs will build with support for -one-time passwords (OTP). Use this option to disable that support. - -@item @kbd{--enable-osfc2} -Enable some C2 support for OSF/Digital Unix/Tru64. Use this option if -you are running your OSF operating system in C2 mode. - -@item @kbd{--with-readline=@file{dir}} -Gives the path for the GNU Readline library, which will be used in some -programs. If no readline library is found, the (simpler) editline -library will be used instead. - -@item @kbd{--with-hesiod=@file{dir}} -Enables hesiod support in push. - -@item @kbd{--enable-netinfo} -Add support for using netinfo to lookup configuration information. -Probably only useful (and working) on NextStep/Mac OS X. - -@item @kbd{--without-ipv6} -Disable the IPv6 support. - -@item @kbd{--with-openldap} -Compile Heimdal with support for storing the database in LDAP. Requires -OpenLDAP @url{http://www.openldap.org}. See -@url{http://www.padl.com/Research/Heimdal.html} for more information. - -@item @kbd{--enable-bigendian} -@item @kbd{--enable-littleendian} -Normally, the build process will figure out by itself if the machine is -big or little endian. It might fail in some cases when -cross-compiling. If it does fail to figure it out, use the relevant of -these two options. - -@item @kbd{--with-mips-abi=@var{abi}} -On Irix there are three different ABIs that can be used (@samp{32}, -@samp{n32}, or @samp{64}). This option allows you to override the -automatic selection. - -@item @kbd{--disable-mmap} -Do not use the mmap system call. Normally, configure detects if there -is a working mmap and it is only used if there is one. Only try this -option if it fails to work anyhow. - -@end table diff --git a/doc/intro.texi b/doc/intro.texi index 83c378788..c51eba02a 100644 --- a/doc/intro.texi +++ b/doc/intro.texi @@ -57,8 +57,7 @@ a library @file{libkafs} for authenticating to AFS and a program @item some simple test programs @item -a KDC that supports most things; optionally, it may also support -Kerberos V4 and kaserver, +a KDC that supports most things, @item simple programs for distributing databases between a KDC master and slaves diff --git a/doc/kerberos4.texi b/doc/kerberos4.texi deleted file mode 100644 index 6fe035803..000000000 --- a/doc/kerberos4.texi +++ /dev/null @@ -1,214 +0,0 @@ -@c $Id$ - -@node Kerberos 4 issues, Windows 2000 compatability, Things in search for a better place, Top -@comment node-name, next, previous, up -@chapter Kerberos 4 issues - -The KDC has built-in version 4 support. It is not enabled by default, -see setup how to set it up. - -The KDC will also have kaserver emulation and be able to handle -AFS-clients that use @code{klog}. - -For more about AFS, see the section @xref{AFS}. - -@menu -* Principal conversion issues:: -* Converting a version 4 database:: -* kaserver:: -@end menu - -@node Principal conversion issues, Converting a version 4 database, Kerberos 4 issues, Kerberos 4 issues -@section Principal conversion issues - -First, Kerberos 4 and Kerberos 5 principals are different. A version 4 -principal consists of a name, an instance, and a realm. A version 5 -principal has one or more components, and a realm (the terms ``name'' -and ``instance'' are still used, for the first and second component, -respectively). Also, in some cases the name of a version 4 principal -differs from the first component of the corresponding version 5 -principal. One notable example is the ``host'' type principals, where -the version 4 name is @samp{rcmd} (for ``remote command''), and the -version 5 name is @samp{host}. For the class of principals that has a -hostname as instance, there is an other major difference, Kerberos 4 -uses only the first component of the hostname, whereas Kerberos 5 uses -the fully qualified hostname. - -Because of this it can be hard or impossible to correctly convert a -version 4 principal to a version 5 principal @footnote{the other way is -not always trivial either, but usually easier}. The biggest problem is -to know if the conversion resulted in a valid principal. To give an -example, suppose you want to convert the principal @samp{rcmd.foo}. - -The @samp{rcmd} name suggests that the instance is a hostname (even if -there are exceptions to this rule). To correctly convert the instance -@samp{foo} to a hostname, you have to know which host it is referring -to. You can to this by either guessing (from the realm) which domain -name to append, or you have to have a list of possible hostnames. In the -simplest cases you can cover most principals with the first rule. If you -have several domains sharing a single realm this will not usually -work. If the exceptions are few you can probably come by with a lookup -table for the exceptions. - -In a complex scenario you will need some kind of host lookup mechanism. -Using DNS for this is tempting, but DNS is error prone, slow and unsafe -@footnote{at least until secure DNS is commonly available}. - -Fortunately, the KDC has a trump on hand: it can easily tell if a -principal exists in the database. The KDC will use -@code{krb5_425_conv_principal_ext} to convert principals when handling -to version 4 requests. - -@node Converting a version 4 database, kaserver , Principal conversion issues, Kerberos 4 issues -@section Converting a version 4 database - -If you want to convert an existing version 4 database, the principal -conversion issue arises too. - -If you decide to convert your database once and for all, you will only -have to do this conversion once. It is also possible to run a version 5 -KDC as a slave to a version 4 KDC. In this case this conversion will -happen every time the database is propagated. When doing this -conversion, there are a few things to look out for. If you have stale -entries in the database, these entries will not be converted. This might -be because these principals are not used anymore, or it might be just -because the principal couldn't be converted. - -You might also see problems with a many-to-one mapping of -principals. For instance, if you are using DNS lookups and you have two -principals @samp{rcmd.foo} and @samp{rcmd.bar}, where `foo' is a CNAME -for `bar', the resulting principals will be the same. Since the -conversion function can't tell which is correct, these conflicts will -have to be resolved manually. - -@subsection Conversion example - -Given the following set of hosts and services: - -@example -foo.se rcmd -mail.foo.se rcmd, pop -ftp.bar.se rcmd, ftp -@end example - -you have a database that consists of the following principals: - -@samp{rcmd.foo}, @samp{rcmd.mail}, @samp{pop.mail}, @samp{rcmd.ftp}, and -@samp{ftp.ftp}. - -lets say you also got these extra principals: @samp{rcmd.gone}, -@samp{rcmd.old-mail}, where @samp{gone.foo.se} was a machine that has -now passed away, and @samp{old-mail.foo.se} was an old mail machine that -is now a CNAME for @samp{mail.foo.se}. - -When you convert this database you want the following conversions to be -done: -@example -rcmd.foo host/foo.se -rcmd.mail host/mail.foo.se -pop.mail pop/mail.foo.se -rcmd.ftp host/ftp.bar.se -ftp.ftp ftp/ftp.bar.se -rcmd.gone @i{removed} -rcmd.old-mail @i{removed} -@end example - -A @file{krb5.conf} that does this looks like: - -@example -[realms] - FOO.SE = @{ - v4_name_convert = @{ - host = @{ - ftp = ftp - pop = pop - rcmd = host - @} - @} - v4_instance_convert = @{ - foo = foo.se - ftp = ftp.bar.se - @} - default_domain = foo.se - @} -@end example - -The @samp{v4_name_convert} section says which names should be considered -having an instance consisting of a hostname, and it also says how the -names should be converted (for instance @samp{rcmd} should be converted -to @samp{host}). The @samp{v4_instance_convert} section says how a -hostname should be qualified (this is just a hosts-file in -disguise). Host-instances that aren't covered by -@samp{v4_instance_convert} are qualified by appending the contents of -the @samp{default_domain}. - -Actually, this example doesn't work. Or rather, it works to well. Since -it has no way of knowing which hostnames are valid and which are not, it -will happily convert @samp{rcmd.gone} to @samp{host/gone.foo.se}. This -isn't a big problem, but if you have run your kerberos realm for a few -years, chances are big that you have quite a few `junk' principals. - -If you don't want this you can remove the @samp{default_domain} -statement, but then you will have to add entries for @emph{all} your hosts -in the @samp{v4_instance_convert} section. - -Instead of doing this you can use DNS to convert instances. This is not -a solution without problems, but it is probably easier than adding lots -of static host entries. - -To enable DNS lookup you should turn on @samp{v4_instance_resolve} in -the @samp{[libdefaults]} section. - -@subsection Converting a database - -The database conversion is done with @samp{hprop}. You can run this -command to propagate the database to the machine called -@samp{slave-server} (which should be running a @samp{hpropd}). - -@example -hprop --source=krb4-db --master-key=/.m slave-server -@end example - -This command can also be to use for converting the v4 database on the -server: - -@example -hprop -n --source=krb4-db -d /var/kerberos/principal --master-key=/.m | hpropd -n -@end example - -@node kaserver, , Converting a version 4 database, Kerberos 4 issues -@section kaserver - -@subsection kaserver emulation - -The Heimdal kdc can emulate a kaserver. The kaserver is a Kerberos 4 -server with pre-authentication using Rx as the on-wire protocol. The kdc -contains a minimalistic Rx implementation. - -There are three parts of the kaserver; KAA (Authentication), KAT (Ticket -Granting), and KAM (Maintenance). The KAA interface and KAT interface -both passes over DES encrypted data-blobs (just like the -Kerberos-protocol) and thus do not need any other protection. The KAM -interface uses @code{rxkad} (Kerberos authentication layer for Rx) for -security and data protection, and is used for example for changing -passwords. This part is not implemented in the kdc. - -Another difference between the ka-protocol and the Kerberos 4 protocol -is that the pass-phrase is salted with the cellname in the @code{string to -key} function in the ka-protocol, while in the Kerberos 4 protocol there -is no salting of the password at all. To make sure AFS-compatible keys -are added to each principals when they are created or their password are -changed, @samp{afs3-salt} should be added to -@samp{[kadmin]default_keys}. - -For more about AFS, see the section @xref{AFS}. - -@subsection Transarc AFS Windows client - -The Transarc Windows client uses Kerberos 4 to obtain tokens, and thus -does not need a kaserver. The Windows client assumes that the Kerberos -server is on the same machine as the AFS-database server. If you do not -like to do that you can add a small program that runs on the database -servers that forward all kerberos requests to the real kerberos -server. A program that does this is @code{krb-forward} -(@url{ftp://ftp.stacken.kth.se/pub/projekts/krb-forward}). diff --git a/doc/krb5.din b/doc/krb5.din index a32d2d938..047319bc7 100644 --- a/doc/krb5.din +++ b/doc/krb5.din @@ -2,7 +2,7 @@ PROJECT_NAME = Heimdal Kerberos 5 library PROJECT_NUMBER = @PACKAGE_VERSION@ -OUTPUT_DIRECTORY = @srcdir@/krb5 +OUTPUT_DIRECTORY = @srcdir@/doxyout/krb5 INPUT = @srcdir@/../lib/krb5 WARN_IF_UNDOCUMENTED = NO diff --git a/doc/migration.texi b/doc/migration.texi index 94813cd1c..7c3e1e70e 100644 --- a/doc/migration.texi +++ b/doc/migration.texi @@ -3,9 +3,41 @@ @node Migration, Acknowledgments, Programming with Kerberos, Top @chapter Migration -@section General issues +@section Migration from MIT Kerberos to Heimdal -When migrating from a Kerberos 4 KDC. +hpropd can read MIT Kerberos dump in "kdb5_util load_dump version 5" or +version 6 format. Simply run: +@samp{kdb5_util dump}. + +To load the MIT Kerberos dump file, use the following command: + +@samp{/usr/heimdal/libexec/hprop --database=dump-file --master-key=/var/db/krb5kdc/mit_stash --source=mit-dump --decrypt --stdout | /usr/heimdal/libexec/hpropd --stdin} + +kadmin can dump in MIT Kerberos format. Simply run: +@samp{kadmin -l dump -f MIT}. + +There are some limitations in this functionality. Users should check +the input dump and a native dump after loading to check for +differences. + +The Heimdal KDC and kadmind, as well as kadmin -l and the libkadm5srv +library can read and write MIT KDBs, and can read MIT stash files. To +build with KDB support requires having a standalone libdb from MIT +Kerberos and associated headers, then you can configure Heildal as +follows: + +@samp{./configure ... CPPFLAGS=-I/path-to-mit-db-headers LDFLAGS="-L/path-to-mit-db-object -Wl,-rpath -Wl,/path-to-mit-db-object" LDLIBS=-ldb} + +At this time support for MIT Kerberos KDB dump/load format and direct +KDB access does not include support for PKINIT, or K/M key history, +constrained delegation, and other advanced features. + +Heimdal supports using multiple HDBs at once, with all write going to +just one HDB. This allows for entries to be moved to a native HDB from +an MIT KDB over time as those entries are changed. Or you can use hprop +and hpropd. + +@section General issues @section Order in what to do things: @@ -33,11 +65,5 @@ you can also check the kdc-log to check what ticket are checked out. @item Burn the bridge and change the master. @item Let all users use the Kerberos 5 tools by default. -@item Turn off services that do not need Kerberos 4 authentication. - -Things that might be hard to get away is old programs with support for -Kerberos 4. Example applications are old Eudora installations using -KPOP, and Zephyr. Eudora can use the Kerberos 4 kerberos in the Heimdal -kdc. @end itemize diff --git a/doc/misc.texi b/doc/misc.texi index 1ad6aaab0..2d976f45d 100644 --- a/doc/misc.texi +++ b/doc/misc.texi @@ -1,6 +1,6 @@ @c $Id$ -@node Things in search for a better place, Kerberos 4 issues, Applications, Top +@node Things in search for a better place, Windows compatibility, Applications, Top @chapter Things in search for a better place @section Making things work on Ciscos diff --git a/doc/ntlm.din b/doc/ntlm.din index 903e35c73..71dd5ffa0 100644 --- a/doc/ntlm.din +++ b/doc/ntlm.din @@ -2,7 +2,7 @@ PROJECT_NAME = Heimdal ntlm library PROJECT_NUMBER = @PACKAGE_VERSION@ -OUTPUT_DIRECTORY = @srcdir@/ntlm +OUTPUT_DIRECTORY = @srcdir@/doxyout/ntlm INPUT = @srcdir@/../lib/ntlm EXAMPLE_PATH = @srcdir@/../lib/ntlm diff --git a/doc/oid.txt b/doc/oid.txt deleted file mode 100644 index f907cdc98..000000000 --- a/doc/oid.txt +++ /dev/null @@ -1,32 +0,0 @@ -OIDs used by Heimdal project. - -Contact heimdal-contact@h5l.org - -Oid Name - -1.2.752.43.13 Heimdal GSS-API extentions -1.2.752.43.14 Heimdal GSS-API mechs -1.2.752.43.16 Heimdal Internal crypto ops - - -1.2.752.43.13.1 GSS_KRB5_COPY_CCACHE_X -1.2.752.43.13.2 GSS_KRB5_GET_TKT_FLAGS_X -1.2.752.43.13.3 GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X -1.2.752.43.13.4 GSS_KRB5_COMPAT_DES3_MIC_X -1.2.752.43.13.5 GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X -1.2.752.43.13.6 GSS_KRB5_EXPORT_LUCID_CONTEXT_X -1.2.752.43.13.6.1 GSS_KRB5_EXPORT_LUCID_CONTEXT_V1_X -1.2.752.43.13.7 GSS_KRB5_SET_DNS_CANONICALIZE_X -1.2.752.43.13.8 GSS_KRB5_GET_SUBKEY_X -1.2.752.43.13.9 GSS_KRB5_GET_INITIATOR_SUBKEY_X -1.2.752.43.13.10 GSS_KRB5_GET_ACCEPTOR_SUBKEY_X -1.2.752.43.13.11 GSS_KRB5_SEND_TO_KDC_X -1.2.752.43.13.12 GSS_KRB5_GET_AUTHTIME_X -1.2.752.43.13.13 GSS_KRB5_GET_SERVICE_KEYBLOCK_X -1.2.752.43.13.14 GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X -1.2.752.43.13.15 GSS_KRB5_SET_DEFAULT_REALM_X -1.2.752.43.13.16 GSS_KRB5_CCACHE_NAME_X -1.2.752.43.13.17 GSS_KRB5_CRED_NO_CI_FLAGS_X -1.2.752.43.13.18 GSS_KRB5_IMPORT_CRED_X - -1.2.752.43.14.1 GSS_SASL_DIGEST_MD5_MECHANISM diff --git a/doc/programming.texi b/doc/programming.texi index 9d746cf29..543e42571 100644 --- a/doc/programming.texi +++ b/doc/programming.texi @@ -1,6 +1,6 @@ @c $Id$ -@node Programming with Kerberos, Migration, Windows 2000 compatability, Top +@node Programming with Kerberos, Migration, Windows compatibility, Top @chapter Programming with Kerberos See the Kerberos 5 API introduction and documentation on the Heimdal diff --git a/doc/setup.texi b/doc/setup.texi index 8dbb4150b..8177b7a71 100644 --- a/doc/setup.texi +++ b/doc/setup.texi @@ -6,30 +6,35 @@ A @cindex realm -realm is an administrative domain. The name of a Kerberos realm is -usually the Internet domain name in uppercase. Call your realm the same -as your Internet domain name if you do not have strong reasons for not +realm is an administrative domain containing any number of Kerberos +principals and namespaces. The name of a Kerberos realm is +usually a domain name in uppercase. Call your realm the same +as your site's domain name if you do not have strong reasons for not doing so. It will make life easier for you and everyone else. @menu * Configuration file:: * Creating the database:: * Modifying the database:: +* Using namespaces and synthetic principals to keep the database small:: +* Using hard aliases for realm migration:: +* Using soft aliases for configuring referrals:: * Checking the setup:: * keytabs:: -* Serving Kerberos 4/524/kaserver:: * Remote administration:: * Password changing:: * Testing clients and servers:: * Slave Servers:: * Incremental propagation:: * Encryption types and salting:: +* Credential cache server - KCM:: * Cross realm:: * Transit policy:: * Setting up DNS:: * Using LDAP to store the database:: * Providing Kerberos credentials to servers and programs:: * Setting up PK-INIT:: +* Debugging Kerberos problems:: @end menu @node Configuration file, Creating the database, Setting up a realm, Setting up a realm @@ -39,7 +44,8 @@ To setup a realm you will first have to create a configuration file: @file{/etc/krb5.conf}. The @file{krb5.conf} file can contain many configuration options, some of which are described here. -There is a sample @file{krb5.conf} supplied with the distribution. +There is a sample @file{krb5.conf} supplied with the distribution, and +a page for it in section 5 of the system manual. The configuration file is a hierarchical structure consisting of sections, each containing a list of bindings (either variable @@ -51,7 +57,14 @@ separated from the equal sign with some whitespace). Subsections have a other bindings are treated as variable assignments. The value of a variable extends to the end of the line. +Configuration files can also include other files, or all files in a +directory. Use absolute paths in include directives. When including a +directoty, only files whose names consist of alphanumeric, hyphen, or +underscore characters are allowed, though they may end in '.conf'. + @example +include /some/config/file +includedir /some/config/directory [section1] a-subsection = @{ var = value1 @@ -76,11 +89,9 @@ are briefly described here. The @samp{libdefaults} section contains a list of library configuration parameters, such as the default realm and the timeout for KDC responses. The @samp{realms} section contains information about specific -realms, such as where they hide their KDC@. This section serves the same -purpose as the Kerberos 4 @file{krb.conf} file, but can contain more -information. Finally the @samp{domain_realm} section contains a list of -mappings from domains to realms, equivalent to the Kerberos 4 -@file{krb.realms} file. +realms, such as where they hide their KDC@. +Finally the @samp{domain_realm} section contains a list of +mappings from domains to realms. To continue with the realm setup, you will have to create a configuration file, with contents similar to the following. @@ -92,28 +103,87 @@ with contents similar to the following. MY.REALM = @{ kdc = my.kdc my.slave.kdc kdc = my.third.kdc + kdc = 130.237.237.17 + kdc = [2001:6b0:1:ea::100]:88 @} [domain_realm] .my.domain = MY.REALM @end example -If you use a realm name equal to your domain name, you can omit the -@samp{libdefaults}, and @samp{domain_realm}, sections. If you have a DNS -SRV-record for your realm, or your Kerberos server has DNS CNAME -@samp{kerberos.my.realm}, you can omit the @samp{realms} section too. +When realm names correspond to domain names, one can avoid having to +configure @samp{domain_realm} mappings, and one can avoid having to +configure a @samp{default_realm} in the @samp{libdefaults} section. +DNS SRV resource records can be used for KDC discovery, obviating the +need list KDCs in the @samp{realms} section of the @samp{krb5.conf} +file. + +@cindex KRB5_CONFIG +The Heimdal libraries and commands (and the MIT ones too), support the +use of the environment variable @samp{KRB5_CONFIG} for using an +alternative configuration. + +@example +env KRB5_CONFIG=$HOME/etc/krb5.conf kinit user@@REALM +@end example + +@cindex KRB5CCNAME +The Heimdal libraries and commands (and the MIT ones too), support the +use of the environment variable @samp{KRB5CCNAME} for specifying a +credentials cache to use. See the @manpage{kinit,1} for details. + +@cindex KRB5_KTNAME +The Heimdal libraries and commands (and the MIT ones too), support the +use of the environment variable @samp{KRB5_KTNAME} for specifying a +keytab file to use for server operations. See the @manpage{kinit,1} for +details. + +@cindex KRB5_CLIENT_KTNAME +The Heimdal libraries and commands (and the MIT ones too), support the +use of the environment variable @samp{KRB5_CLIENT_KTNAME} for specifying +a keytab file to use for client operations. See the @manpage{kinit,1} +for details. + +@cindex GSS_MECH_CONFIG +The GSS-API mechanism configuration file can also be changed from the +default with the enviornment variable @samp{GSS_MECH_CONFIG}. Note that +this file can only configure additional plugin mechanisms: Kerberos, +NTLM and SPNEGO are built in to the Heimdal GSS-API library. @node Creating the database, Modifying the database, Configuration file, Setting up a realm @section Creating the database -The database library will look for the database in the directory -@file{@value{dbdir}}, so you should probably create that directory. -Make sure the directory has restrictive permissions. +The Heimdal database library, @code{libhdb}, will look for the +database in the directory @file{@value{dbdir}}, so you should probably +create that directory. Make sure the directory has restrictive +permissions. @example # mkdir /var/heimdal +# chmod og-rwx /var/heimdal @end example +Heimdal supports various database backends: lmdb (LMDB), db3 (Berkeley +DB 3.x, 4.x, or 5.x), db1 (Berkeley DB 2.x), sqlite (SQLite3), and ldap +(LDAP). The default is @value{dbtype}, and is selected at configure +time from one of lmdb, db3, or db1. + +These defaults can be overriden in the 'database' key in the @samp{kdc} +section of the configuration. + +@example +[kdc] + database = @{ + dbname = lmdb:/path/to/db-file + realm = REALM + acl_file = /path/to/kadmind.acl + mkey_file = /path/to/mkey + log_file = /path/to/iprop-log-file + @} +@end example + +To use LDAP, see @xref{Using LDAP to store the database}. + The keys of all the principals are stored in the database. If you choose to, these can be encrypted with a master key. You do not have to remember this key (or password), but just to enter it once and it will @@ -133,6 +203,11 @@ on which attackers can't do a dictionary attack. If you have a master key, make sure you make a backup of your master key file; without it backups of the database are of no use. +Note that encryption of the keys in the database is only useful when +the database is stored on external storage media that is easy to +steal. Thus for the most part there is no need to encrypt the keys in +the database. + To initialise the database use the @command{kadmin} program, with the @kbd{-l} option (to enable local database mode). First issue a @kbd{init MY.REALM} command. This will create the database and insert @@ -187,7 +262,7 @@ krbtgt/MY.REALM@@MY.REALM 1:0:1:52b53b61c875ce16:-:0:7:c8943be ... kadmin/changepw@@MY.REALM 1:0:1:f48c8af2b340e9fb:-:0:7:e3e6088 ... @end smallexample -@node Modifying the database, Checking the setup, Creating the database, Setting up a realm +@node Modifying the database, Using namespaces and synthetic principals to keep the database small, Creating the database, Setting up a realm @section Modifying the database All modifications of principals are done with with kadmin. @@ -249,7 +324,101 @@ R second @c Describe more of kadmin commands here... -@node Checking the setup, keytabs, Modifying the database, Setting up a realm +@node Using namespaces and synthetic principals to keep the database small, Checking the setup, Modifying the database, Setting up a realm +@section Using namespaces and synthetic principals to keep the database small + +Keeping a Kerberos database small is useful for several reasons: + +@itemize @bullet +@item to avoid low write transaction rates +@item to avoid replication latency +@item to keep re-keying costs down +@end itemize + +To avoid needing database entries for client principals, configure and +enable PKINIT and synthetic principals. Alternatively, configure and +enable the use of GSS-API pre-authentication, though this is currently +experimental. + +With synthetic client principals enabled, client principals will be +deemed to exist if they can pre-authenticate using a method that +yields an authenticated principal name, and if the client principal +does not already exist. + +To lock out or disable a specific synthetic client principal, create +it in the database with the desired attributes. + +To avoid needing database entries for host-based service principals, +create virtual host-based service principal namespaces using the +@command{add_ns} sub-command of the @command{kadmin} command. Virtual +host-based service principals will exist for every possible hostname +under a containing namespace, with keys derived from the namespace's +based keys and the current key rotation period. The long-term keys of +virtual host-based service principals rotate on a hard schedule as +configured for their namespaces, so hosts and applications using them +must keep re-fetching their @samp{keytabs}. See the manual pages for +@file{krb5.conf}, @command{kadmin}, and @command{httpkadmind} for more +details. + +Using these features one can end up with a database that contains just +@code{krbtgt} principals, principals for locked users, and principals +that are neither @code{krbtgt}, user, nor host-based services. + +@node Using hard aliases for realm migration, Using soft aliases for configuring referrals, Using namespaces and synthetic principals to keep the database small, Setting up a realm +@section Using hard aliases for realm migration + +The Heimdal @command{kadmin} command can be used to add aliases to +principal entries in the Heimdal database. Aliases of principals of +the form @samp{WELLKNOWN/REFERRALS/TARGET} or +@samp{WELLKNOWN/REFERRALS/TARGET/anything} are "soft" aliases. +Aliases of principals of other forms are "hard" aliases. + +When a client makes a request for a principal's alias, and it does not +use the KDC request "canonicalize" option flag, the Heimdal KDC will +treat the alias as a distinct principal that happens to share +attributes and long-term symmetric keys and salts with the principal +it is an alias of. + +This is useful for, for example, ensuring that host-based principals +can be referred to by any aliases. + +This can also be very useful for renaming realms: add new +@code{krbtgt} principals for the new realms, then add aliases to +existing principals in their new realms. For example, a user with a +principal @code{joe@@A} can be given an alias of +@code{joes@@B}, and +then they can @code{kinit joes@@B} and get Kerberos tickets for +@code{joes@@B}. Similarly, a service principal such as +@code{HTTP/foo.bar.baz.example@@BAZ.EXAMPLE} can be given an alias such as +@code{HTTP/foo.bar.baz.example@@BAR.BAZ.EXAMPLE}, or even +@code{HTTP/foobar.new-domain.example@@NEW-DOMAIN.EXAMPLE}, and +requesting tickets with those aliases as the service names will work. + +@node Using soft aliases for configuring referrals, Checking the setup, Using hard aliases for realm migration, Setting up a realm +@section Using soft aliases for configuring referrals + +Soft aliases, which are aliases of principals of the form +@code{WELLKNOWN/REFERRALS/TARGET} or +@code{WELLKNOWN/REFERRALS/TARGET/anything}, are used to generate +referrals to other realms. Specifically, the realm of a soft alias' +canonical name is the realm to issue referrals to. + +Soft aliases can be used to configure individual referrals, but also +of entire namespaces of hostnames. To configure the issuance of +referrals for entire namespaces, make a soft alias of the form +@code{WELLKNOWN/HOSTBASED-NAMESPACE/service/namespace-fqdn@@REALM} to +have the TGS for that @samp{REALM} issue referrals for all principals +of the form @code{service/hostname@@REALM} where the hostname component +is a sub-domain of the namespace component of the alias name. + +For example, a soft alias name +@code{WELLKNOWN/HOSTBASED-NAMESPACE/host/cloud.bar.example@@BAR.EXAMPLE} +to a realm @samp{B} will cause the KDC to issue referrals to @samp{B} +for any principals such as +@samp{host/foo.cloud.bar.example@@BAR.EXAMPLE}, and +@samp{host/baz.cloud.bar.example@@BAR.EXAMPLE}, and so on. + +@node Checking the setup, keytabs, Using namespaces and synthetic principals to keep the database small, Setting up a realm @section Checking the setup There are two tools that can check the consistency of the Kerberos @@ -267,14 +436,14 @@ check are for existence and flags on important principals. The database check by run by the following command : @example -kadmin check REALM.EXAMPLE.ORG +kadmin -l check REALM.EXAMPLE.ORG @end example -@node keytabs, Serving Kerberos 4/524/kaserver, Checking the setup, Setting up a realm +@node keytabs, Remote administration, Checking the setup, Setting up a realm @section keytabs To extract a service ticket from the database and put it in a keytab, you -need to first create the principal in the database with @samp{ank} +need to first create the principal in the database with @samp{add} (using the @kbd{--random-key} flag to get a random key) and then extract it with @samp{ext_keytab}. @@ -293,59 +462,7 @@ Version Type Principal 1 des3-cbc-sha1 host/my.host.name@@MY.REALM @end example -@node Serving Kerberos 4/524/kaserver, Remote administration, keytabs, Setting up a realm -@section Serving Kerberos 4/524/kaserver - -Heimdal can be configured to support 524, Kerberos 4 or kaserver. All -these services are turned off by default. Kerberos 4 is always -supported by the KDC, but the Kerberos 4 client support also depends -on Kerberos 4 support having been included at compile-time, using -@kbd{--with-krb4=dir}. - -@subsection 524 - -524 is a service that allows the KDC to convert Kerberos 5 tickets to -Kerberos 4 tickets for backward compatibility. See also Using 2b -tokens with AFS in @xref{AFS}. - -524 can be turned on by adding this to the configuration file - -@example -[kdc] - enable-524 = yes -@end example - -@subsection Kerberos 4 - -Kerberos 4 is the predecessor to to Kerberos 5. It only supports -single DES@. You should only enable Kerberos 4 support if you have -needs for compatibility with an installed base of Kerberos 4 -clients/servers. - -Kerberos 4 can be turned on by adding this to the configuration file - -@example -[kdc] - enable-kerberos4 = yes -@end example - -@subsection kaserver - -Kaserver is a Kerberos 4 that is used in AFS@. The protocol has some -extra features over plain Kerberos 4, but like Kerberos 4, only uses -single DES@. - -You should only enable Kaserver support if you have needs for -compatibility with an installed base of AFS machines. - -Kaserver can be turned on by adding this to the configuration file - -@example -[kdc] - enable-kaserver = yes -@end example - -@node Remote administration, Password changing, Serving Kerberos 4/524/kaserver, Setting up a realm +@node Remote administration, Password changing, keytabs, Setting up a realm @section Remote administration The administration server, @command{kadmind}, can be started by @@ -403,7 +520,17 @@ To allow users to change their passwords, you should run @command{kpasswdd}. It is not run from @command{inetd}. You might need to add @samp{kpasswd} to your @file{/etc/services} as -@samp{464/udp}. +@samp{464/udp}. If your realm is not setup to use DNS, you might also +need to add a @samp{kpasswd_server} entry to the realm configuration +in @file{/etc/krb5.conf} on client machines: + +@example +[realms] + MY.REALM = @{ + kdc = my.kdc my.slave.kdc + kpasswd_server = my.kdc + @} +@end example @subsection Password quality assurance @@ -419,16 +546,18 @@ controls, add lines similar to the following to your @example [password_quality] - policies = external-check builtin:minimum-length module:policyname + policies = external-check builtin:minimum-length modulename:policyname external_program = /bin/false policy_libraries = @var{library1.so} @var{library2.so} @end example In @samp{[password_quality]policies} the module name is optional if the policy name is unique in all modules (members of -@samp{policy_libraries}). +@samp{policy_libraries}). All built-in policies can be qualified with +a module name of @samp{builtin} to unambiguously specify the built-in +policy and not a policy by the same name from a loaded module. -The built-in polices are +The built-in policies are @itemize @bullet @@ -470,6 +599,17 @@ classes. Default value if not given is 3. The four different characters classes are, uppercase, lowercase, number, special characters. +@item enforce_on_admin_set + +The enforce_on_admin_set check subjects administrative password updates to the +password policy. An administrative password update is a create principal or +change password request via @command{kadmind}, or a set password request via +@command{kpasswdd}. (A set password request is one where the authenticating +principal differs from the principal whose password is being changed.) Password +policies are always ignored if the authenticating principal is the kadmin +service itself, for example when running @command{kadmin} in local mode. The +default value for enforce_on_admin_set if not given is true. + @end itemize If you want to write your own shared object to check password @@ -488,7 +628,7 @@ If no password quality checking function is configured, the only check performed is that the password is at least six characters long. To check the password policy settings, use the command -@command{password-quality} in @command{kadmin} program. The password +@command{verify-password-quality} in @command{kadmin} program. The password verification is only performed locally, on the client. It may be convenient to set the environment variable @samp{KRB5_CONFIG} to point to a test version of @file{krb5.conf} while you're testing the @@ -625,7 +765,19 @@ slave# /usr/heimdal/libexec/ipropd-slave master & To manage the iprop log file you should use the @command{iprop-log} command. With it you can dump, truncate and replay the logfile. -@node Encryption types and salting, Cross realm, Incremental propagation, Setting up a realm +@subsection Status of iprop master and slave + +Both the master and slave provides status of the world as they see it. + +The master write outs the current status of the slaves, last seen and +their version number in @file{/var/heimdal/slaves-stats}. + +The slave write out the current status in @file{/var/heimdal/ipropd-slave-status}. + +These locations can be changed with command line options, and in the +case of @command{ipropd_master}, the configuration file. + +@node Encryption types and salting, Credential cache server - KCM, Incremental propagation, Setting up a realm @section Encryption types and salting @cindex Salting @cindex Encryption types @@ -645,10 +797,6 @@ fixed size encryption key. In Kerberos 5 the salt is determined by the encryption type, except in some special cases. -In @code{des} there is the Kerberos 4 salt -(none at all) or the afs-salt (using the cell (realm in -AFS lingo)). - In @code{arcfour} (the encryption type that Microsoft Windows 2000 uses) there is no salt. This is to be compatible with NTLM keys in Windows NT 4. @@ -667,12 +815,6 @@ no salt at all). Common types of salting include @itemize @bullet -@item @code{v4} (or @code{des:pw-salt:}) - -The Kerberos 4 salting is using no salt at all. Reason there is colon -at the end of the salt string is that it makes the salt the empty -string (same as no salt). - @item @code{v5} (or @code{pw-salt}) @code{pw-salt} uses the default salt for each encryption type is @@ -686,7 +828,76 @@ the cell name appended to the password. @end itemize -@node Cross realm, Transit policy, Encryption types and salting, Setting up a realm +@node Credential cache server - KCM, Cross realm, Encryption types and salting, Setting up a realm +@section Credential cache server - KCM +@cindex KCM +@cindex Credential cache server + +When KCM running is easy for users to switch between different +kerberos principals using @file{kswitch} or built in support in +application, like OpenSSH's GSSAPIClientIdentity. + +Other advantages are that there is the long term credentials are not +written to disk and on reboot the credential is removed when kcm +process stopps running. + +Configure the system startup script to start the kcm process, +@file{/usr/heimdal/libexec/kcm} and then configure the system to use kcm in @file{krb5.conf}. + +@example +[libdefaults] + default_cc_type = KCM +@end example + +Now when you run @command{kinit} it doesn't overwrite your existing +credentials but rather just add them to the set of +credentials. @command{klist -l} lists the credentials and the star +marks the default credential. + +@example +$ kinit lha@@KTH.SE +lha@@KTH.SE's Password: +$ klist -l + Name Cache name Expires +lha@@KTH.SE 0 Nov 22 23:09:40 * +lha@@SU.SE Initial default ccache Nov 22 14:14:24 +@end example + +When switching between credentials you can use @command{kswitch}. + +@example +$ kswitch -i + Principal +1 lha@@KTH.SE +2 lha@@SU.SE +Select number: 2 +@end example + +After switching, a new set of credentials are used as default. + +@example +$ klist -l + Name Cache name Expires +lha@@SU.SE Initial default ccache Nov 22 14:14:24 * +lha@@KTH.SE 0 Nov 22 23:09:40 +@end example + +Som applications, like openssh with Simon Wilkinsons patch applied, +support specifiying that credential to use. The example below will +login to the host computer.kth.se using lha@@KTH.SE (not the current +default credential). + +@example +$ ssh \ + -o GSSAPIAuthentication=yes \ + -o GSSAPIKeyExchange=yes \ + -o GSSAPIClientIdentity=lha@@KTH.SE \ + computer.kth.se +@end example + + + +@node Cross realm, Transit policy, Credential cache server - KCM, Setting up a realm @section Cross realm @cindex Cross realm @@ -753,17 +964,36 @@ May 3 14:10:54 May 3 23:55:54 host/hummel.it.su.se@@SU.SE @section Transit policy @cindex Transit policy -If you want to use cross realm authentication through an intermediate -realm, it must be explicitly allowed by either the KDCs or the server -receiving the request. This is done in @file{krb5.conf} in the +Under some circumstances, you may not wish to set up direct +cross-realm trust with every realm to which you wish to authenticate +or from which you wish to accept authentications. Kerberos supports +multi-hop cross-realm trust where a client principal in realm A +authenticates to a service in realm C through a realm B with which +both A and C have cross-realm trust relationships. In this situation, +A and C need not set up cross-realm principals between each other. + +If you want to use cross-realm authentication through an intermediate +realm, it must be explicitly allowed by either the KDCs for the realm +to which the client is authenticating (in this case, realm C), or the +server receiving the request. This is done in @file{krb5.conf} in the @code{[capaths]} section. +In addition, the client in realm A need to be configured to know how +to reach realm C via realm B. This can be done either on the client or +via KDC configuration in the KDC for realm A. + +@subsection Allowing cross-realm transits + When the ticket transits through a realm to another realm, the destination realm adds its peer to the "transited-realms" field in the -ticket. The field is unordered, since there is no way to know if -know if one of the transited-realms changed the order of the list. +ticket. The field is unordered, since there is no way to know if know +if one of the transited-realms changed the order of the list. For the +authentication to be accepted by the final destination realm, all of +the transited realms must be listed as trusted in the @code{[capaths]} +configuration, either in the KDC for the destination realm or on the +server receiving the authentication. -The syntax for @code{[capaths]} section: +The syntax for @code{[capaths]} section is: @example [capaths] @@ -772,11 +1002,15 @@ The syntax for @code{[capaths]} section: @} @end example -The realm @code{STACKEN.KTH.SE} allows clients from @code{SU.SE} and -@code{DSV.SU.SE} to cross it. Since @code{STACKEN.KTH.SE} only has -direct cross realm setup with @code{KTH.SE}, and @code{DSV.SU.SE} only -has direct cross realm setup with @code{SU.SE} they need to use both -@code{SU.SE} and @code{KTH.SE} as transit realms. +In the following example, the realm @code{STACKEN.KTH.SE} only has +direct cross-realm set up with @code{KTH.SE}. @code{KTH.SE} has +direct cross-realm set up with @code{STACKEN.KTH.SE} and @code{SU.SE}. +@code{DSV.SU.SE} only has direct cross-realm set up with @code{SU.SE}. +The goal is to allow principals in the @code{DSV.SU.SE} or +@code{SU.SE} realms to authenticate to services in +@code{STACKEN.KTH.SE}. This is done with the following +@code{[capaths]} entry on either the server accepting authentication +or on the KDC for @code{STACKEN.KTH.SE}. @example [capaths] @@ -786,17 +1020,100 @@ has direct cross realm setup with @code{SU.SE} they need to use both DSV.SU.SE = @{ STACKEN.KTH.SE = SU.SE KTH.SE @} - @end example +The first entry allows cross-realm authentication from clients in +@code{SU.SE} transiting through @code{KTH.SE} to +@code{STACKEN.KTH.SE}. The second entry allows cross-realm +authentication from clients in @code{DSV.SU.SE} transiting through +both @code{SU.SE} and @code{KTH.SE} to @code{STACKEN.KTH.SE}. + +Be careful of which realm goes where; it's easy to put realms in the +wrong place. The block is tagged with the client realm (the realm of +the principal authenticating), and the realm before the equal sign is +the final destination realm: the realm to which the client is +authenticating. After the equal sign go all the realms that the +client transits through. + The order of the @code{PERMITTED-CROSS-REALMS} is not important when doing transit cross realm verification. -However, the order is important when the @code{[capaths]} section is used -to figure out the intermediate realm to go to when doing multi-realm -transit. When figuring out the next realm, the first realm of the list -of @code{PERMITTED-CROSS-REALMS} is chosen. This is done in both the -client kerberos library and the KDC. +@subsection Configuring client cross-realm transits + +The @code{[capaths]} section is also used for another purpose: to tell +clients which realm to transit through to reach a realm with which +their local realm does not have cross-realm trust. This can be done +by either putting a @code{[capaths]} entry in the configuration of the +client or by putting the entry in the configuration of the KDC for the +client's local realm. In the latter case, the KDC will then hand back +a referral to the client when the client requests a cross-realm ticket +to the destination realm, telling the client to try to go through an +intermediate realm. + +For client configuration, the order of @code{PERMITTED-CROSS-REALMS} +is significant, since only the first realm in this section (after the +equal sign) is used by the client. + +For example, again consider the @code{[capaths]} entry above for the +case of a client in the @code{SU.SE} realm, and assume that the client +or the @code{SU.SE} KDC has that @code{[capaths]} entry. If the +client attempts to authenticate to a service in the +@code{STACKEN.KTH.SE} realm, that entry says to first authenticate +cross-realm to the @code{KTH.SE} realm (the first realm listed in the +@code{PERMITTED-CROSS-REALMS} section), and then from there to +@code{STACKEN.KTH.SE}. + +Each entry in @code{[capaths]} can only give the next hop, since only +the first realm in @code{PERMITTED-CROSS-REALMS} is used. If, for +instance, a client in @code{DSV.SU.SE} had a @code{[capaths]} +configuration as above but without the first block for @code{SU.SE}, +they would not be able to reach @code{STACKEN.KTH.SE}. They would get +as far as @code{SU.SE} based on the @code{DSV.SU.SE} entry in +@code{[capaths]} and then attempt to go directly from there to +@code{STACKEN.KTH.SE} and get stuck (unless, of course, the +@code{SU.SE} KDC had the additional entry required to tell the client +to go through @code{KTH.SE}). + +@subsection Active Directory forest example + +One common place where a @code{[capaths]} configuration is desirable +is with Windows Active Directory forests. One common Active Directory +configuration is to have one top-level Active Directory realm but then +divide systems, services, and users into child realms (perhaps based +on organizational unit). One generally establishes cross-realm trust +only with the top-level realm, and then uses transit policy to permit +authentications to and from the child realms. + +For example, suppose an organization has a Heimdal realm +@code{EXAMPLE.COM}, a Windows Active Directory realm +@code{WIN.EXAMPLE.COM}, and then child Active Directory realms +@code{ENGR.WIN.EXAMPLE.COM} and @code{SALES.WIN.EXAMPLE.COM}. The +goal is to allow users in any of these realms to authenticate to +services in any of these realms. The @code{EXAMPLE.COM} KDC (and +possibly client) configuration should therefore contain a +@code{[capaths]} section as follows: + +@example +[capaths] + ENGR.WIN.EXAMPLE.COM = @{ + EXAMPLE.COM = WIN.EXAMPLE.COM + @} + SALES.WIN.EXAMPLE.COM = @{ + EXAMPLE.COM = WIN.EXAMPLE.COM + @} + EXAMPLE.COM = @{ + ENGR.WIN.EXAMPLE.COM = WIN.EXAMPLE.COM + SALES.WIN.EXAMPLE.COM = WIN.EXAMPLE.COM + @} +@end example + +The first two blocks allow clients in the @code{ENGR.WIN.EXAMPLE.COM} +and @code{SALES.WIN.EXAMPLE.COM} realms to authenticate to services in +the @code{EXAMPLE.COM} realm. The third block tells the client (or +tells the KDC to tell the client via referrals) to transit through +@code{WIN.EXAMPLE.COM} to reach these realms. Both sides of the +configuration are needed for bi-directional transited cross-realm +authentication. @c To test the cross realm configuration, use: @c kmumble transit-check client server transit-realms ... @@ -895,7 +1212,8 @@ Its also possible to configure the ldap backend as a shared module, see option --hdb-openldap-module to configure. @item -Configure OpenLDAP with @kbd{--enable-local} to enable the local transport. +Optionally configure OpenLDAP with @kbd{--enable-local} to enable the +local transport. @item Add the hdb schema to the LDAP server, it's included in the source-tree @@ -906,8 +1224,8 @@ include /usr/local/etc/openldap/schema/hdb.schema @end example @item -Configure the LDAP server ACLs to accept writes from clients over the -local transport. For example: +Configure the LDAP server ACLs to accept writes from clients. For +example: @example access to * @@ -927,10 +1245,15 @@ krb5Principal aux object with krb5PrincipalName set so that the Another option is to create an admins group and add the dn to that group. -Since Heimdal talks to the LDAP server over a UNIX domain socket, and -uses external sasl authentication, it's not possible to require -security layer quality (ssf in cyrus-sasl lingo). So that requirement -has to be turned off in OpenLDAP @command{slapd} configuration file +If a non-local LDAP connection is used, the authz-regexp is not +needed as Heimdal will bind to LDAP over the network using +provided credentials. + +Since Heimdal talks to the LDAP server over a UNIX domain socket when +configured for ldapi:///, and uses external sasl authentication, it's +not possible to require security layer quality (ssf in cyrus-sasl lingo). +So that requirement has to be turned off in OpenLDAP @command{slapd} +configuration file @file{slapd.conf}. @example @@ -958,9 +1281,14 @@ enter the path to the kadmin acl file: @example [kdc] + # Optional configuration + hdb-ldap-structural-object = inetOrgPerson + hdb-ldap-url = ldapi:/// (default), ldap://hostname or ldaps://hostname + hdb-ldap-secret-file = /path/to/file/containing/ldap/credentials + hdb-ldap-start-tls = false + database = @{ dbname = ldap:ou=KerberosPrincipals,dc=example,dc=com - hdb-ldap-structural-object = inetOrgPerson acl_file = /path/to/kadmind.acl mkey_file = /path/to/mkey @} @@ -971,7 +1299,18 @@ directory to have the raw keys inside it. The hdb-ldap-structural-object is not necessary if you do not need Samba comatibility. +If connecting to a server over a non-local transport, the @samp{hdb-ldap-url} +and @samp{hdb-ldap-secret-file} options must be provided. The +@samp{hdb-ldap-secret-file} must contain the bind credentials: +@example +[kdc] + hdb-ldap-bind-dn = uid=heimdal,dc=services,dc=example,dc=com + hdb-ldap-bind-password = secretBindPassword +@end example + +The @samp{hdb-ldap-secret-file} and should be protected with appropriate +file permissions @item Once you have built Heimdal and started the LDAP server, run kadmin @@ -983,7 +1322,7 @@ kdc# kadmin -l kadmin> init EXAMPLE.COM Realm max ticket life [unlimited]: Realm max renewable ticket life [unlimited]: -kadmin> ank lukeh +kadmin> add lukeh Max ticket life [1 day]: Max renewable life [1 week]: Principal expiration time [never]: @@ -1094,56 +1433,61 @@ service@@host$ kinit --cache=/var/run/service_krb5_cache \ @end example -@node Setting up PK-INIT, , Providing Kerberos credentials to servers and programs, Setting up a realm +@node Setting up PK-INIT, Debugging Kerberos problems, Providing Kerberos credentials to servers and programs, Setting up a realm @section Setting up PK-INIT -PK-INIT is levering the existing PKI infrastructure to use -certificates to get the initial ticket, that is usually the krbtgt. +PK-INIT leverages an existing PKI (public key infrastructure), using +certificates to get the initial ticket (usually the krbtgt +ticket-granting ticket). -To use PK-INIT you must first have a PKI, so if you don't have one, -it is time to create it. Note that you should read the whole chapter -of the document to see the requirements on the CA software. +To use PK-INIT you must first have a PKI. If you don't have one, it is +time to create it. You should first read the whole current chapter of +the document to see the requirements imposed on the CA software. -There needs to exist a mapping between the certificate and what -principals that certificate is allowed to use. There are several ways -to do this. The administrator can use a configuration file, storing -the principal in the SubjectAltName extension of the certificate, or store the -mapping in the principals entry in the kerberos database. +A mapping between the PKI certificate and what principals that +certificate is allowed to use must exist. There are several ways to do +this. The administrator can use a configuration file, store the +principal in the SubjectAltName extension of the certificate, or store +the mapping in the principals entry in the kerberos database. @section Certificates -This section documents the requirements on the KDC and client -certificates and the format used in the id-pkinit-san OtherName -extention. +This and following subsection documents the requirements on the KDC +and client certificates and the format used in the id-pkinit-san +OtherName extension. + +On how to create certificates, you should read @ref{Use OpenSSL to +create certificates}. @subsection KDC certificate -The certificate for the KDC have serveral requirements. +The certificate for the KDC has several requirements. -First the certificate should have an Extended Key Usage (EKU) -id-pkkdcekuoid (1.3.6.1.5.2.3.5) set. Second there must be a -subjectAltName otherName using oid id-pkinit-san (1.3.6.1.5.2.2) in +First, the certificate should have an Extended Key Usage (EKU) +id-pkkdcekuoid (1.3.6.1.5.2.3.5) set. Second, there must be a +subjectAltName otherName using OID id-pkinit-san (1.3.6.1.5.2.2) in the type field and a DER encoded KRB5PrincipalName that matches the -name of the TGS of the target realm. +name of the TGS of the target realm. Also, if the certificate has a +nameConstraints extension with a Generalname with dNSName or iPAddress, +it must match the hostname or address of the KDC. -Both of these two requirements are not required by the standard to be -checked by the client if it have external information what the -certificate the KDC is supposed to be used. So it's in the interest of -minimum amount of configuration on the clients they should be included. +The client is not required by the standard to check the server +certificate for this information if the client has external +information confirming which certificate the KDC is supposed to be +using. However, adding this information to the KDC certificate removes +the need to specially configure the client to recognize the KDC +certificate. Remember that if the client would accept any certificate as the KDC's certificate, the client could be fooled into trusting something that isn't a KDC and thus expose the user to giving away information (like -password or other private information) that it is supposed to secret. - -Also, if the certificate has a nameConstraints extention with a -Generalname with dNSName or iPAdress it must match the hostname or -adress of the KDC. +a password or other private information) that it is supposed to keep +secret. @subsection Client certificate The client certificate may need to have a EKU id-pkekuoid -(1.3.6.1.5.2.3.4) set depending on the certifiate on the KDC. +(1.3.6.1.5.2.3.4) set depending on the configuration on the KDC. It possible to store the principal (if allowed by the KDC) in the certificate and thus delegate responsibility to do the mapping between @@ -1156,15 +1500,16 @@ This behavior is controlled by KDC configuration option: pkinit_principal_in_certificate = yes @end example - @subsubsection Using KRB5PrincipalName in id-pkinit-san -OtherName extention in the GeneralName is used to do the -mapping between certifiate and principal in the certifiate or storing -the krbtgt principal in the KDC certificate. +The OtherName extension in the GeneralName is used to do the mapping +between certificate and principal. For the KDC certificate, this +stores the krbtgt principal name for that KDC. For the client +certificate, this stores the principal for which that certificate is +allowed to get tickets. The principal is stored in a SubjectAltName in the certificate using -OtherName. The oid in the type is id-pkinit-san. +OtherName. The OID in the type is id-pkinit-san. @example id-pkinit-san OBJECT IDENTIFIER ::= @{ iso (1) org (3) dod (6) @@ -1181,32 +1526,32 @@ KRB5PrincipalName ::= SEQUENCE @{ @} @end example -where Realm and PrincipalName is defined by the Kerberos ASN.1 specification. +where Realm and PrincipalName is defined by the Kerberos ASN.1 +specification. @section Naming certificate using hx509 hx509 is the X.509 software used in Heimdal to handle -certificates. hx509 uses different syntaxes to specify the different -formats the certificates are stored in and what formats they exist in. - -There are several formats that can be used, PEM, embedded into PKCS12 -files, embedded into PKCS11 devices and raw DER encoded certificates. -Below is a list of types to use. +certificates. hx509 supports several different syntaxes for specifying +certificate files or formats. Several formats may be used: PEM, +certificates embedded in PKCS#12 files, certificates embedded in +PKCS#11 devices, and raw DER encoded certificates. +Those formats may be specified as follows: @table @asis @item DIR: -DIR is reading all certificates in a directory that is DER or PEM -formatted. +DIR specifies a directory which contains certificates in the DER or +PEM format. The main feature of DIR is that the directory is read on demand when -iterating over certificates, that way applictions can for some cases -avoid to store all certificates in memory. It's very useful for tests -that iterate over larger amount of certificates. +iterating over certificates. This allows applications, in some +situations, to avoid having to store all certificates in memory. It's +very useful for tests that iterate over large numbers of certificates. -Syntax is: +The syntax is: @example DIR:/path/to/der/files @@ -1214,15 +1559,16 @@ DIR:/path/to/der/files @item FILE: -FILE: is used to have the lib pick up a certificate chain and a -private key. The file can be either a PEM (openssl) file or a raw DER -encoded certificate. If it's a PEM file it can contain several keys and +FILE: specifies a file that contains a certificate or private key. +The file can be either a PEM (openssl) file or a raw DER encoded +certificate. If it's a PEM file, it can contain several keys and certificates and the code will try to match the private key and -certificate together. +certificate together. Multiple files may be specified, separated by +commas. -Its useful to have one PEM file that contains all the trust anchors. +It's useful to have one PEM file that contains all the trust anchors. -Syntax is: +The syntax is: @example FILE:certificate.pem,private-key.key,other-cert.pem,.... @@ -1230,11 +1576,12 @@ FILE:certificate.pem,private-key.key,other-cert.pem,.... @item PKCS11: -PKCS11: is used to handle smartcards via PKCS11 drivers, for example -soft-token, opensc, or muscle. The default is to use all slots on the -device/token. +PKCS11: is used to handle smartcards via PKCS#11 drivers, such as +soft-token, opensc, or muscle. The argument specifies a shared object +that implements the PKCS#11 API. The default is to use all slots on +the device/token. -Syntax is: +The syntax is: @example PKCS11:shared-object.so @@ -1242,10 +1589,10 @@ PKCS11:shared-object.so @item PKCS12: -PKCS12: is used to handle PKCS12 files. PKCS12 files commonly have the -extension pfx or p12. +PKCS12: is used to handle PKCS#12 files. PKCS#12 files commonly have +the extension pfx or p12. -Syntax is: +The syntax is: @example PKCS12:/path/to/file.pfx @@ -1256,8 +1603,8 @@ PKCS12:/path/to/file.pfx @section Configure the Kerberos software First configure the client's trust anchors and what parameters to -verify, see subsection below how to do that. Now you can use kinit to -get yourself tickets. One example how that can look like is: +verify. See the subsections below for how to do that. Then, you can +use kinit to get yourself tickets. For example: @example $ kinit -C FILE:$HOME/.certs/lha.crt,$HOME/.certs/lha.key lha@@EXAMPLE.ORG @@ -1270,7 +1617,7 @@ Credentials cache: FILE:/tmp/krb5cc_19100a Apr 20 02:08:08 Apr 20 12:08:08 krbtgt/EXAMPLE.ORG@@EXAMPLE.ORG @end example -Using PKCS11 it can look like this instead: +Using PKCS#11 it can look like this instead: @example $ kinit -C PKCS11:/usr/heimdal/lib/hx509.so lha@@EXAMPLE.ORG @@ -1283,9 +1630,6 @@ Credentials cache: API:4 Mar 26 23:40:10 Mar 27 09:40:10 krbtgt/EXAMPLE.ORG@@EXAMPLE.ORG @end example - -Write about the kdc. - @section Configure the client @example @@ -1304,6 +1648,45 @@ Write about the kdc. @section Configure the KDC +Configuration options for the KDC. + +@table @asis +@item enable-pkinit = bool + +Enable PKINIT for this KDC. + +@item pkinit_identity = string + +Identity that the KDC will use when talking to clients. Mandatory. + +@item pkinit_anchors = string + +Trust anchors that the KDC will use when evaluating the trust of the +client certificate. Mandatory. + +@item pkinit_pool = strings ... + +Extra certificate the KDC will use when building trust chains if it +can't find enough certificates in the request from the client. + +@item pkinit_allow_proxy_certificate = bool + +Allow clients to use proxy certificates. The root certificate +of the client's End Entity certificate is used for authorisation. + +@item pkinit_win2k_require_binding = bool + +Require windows clients up be upgrade to not allow cut and paste +attack on encrypted data, applies to Windows XP and windows 2000 +servers. + +@item pkinit_principal_in_certificate = bool + +Enable the KDC to use id-pkinit-san to determine to determine the +mapping between a certificate and principal. + +@end table + @example [kdc] enable-pkinit = yes @@ -1318,7 +1701,7 @@ Write about the kdc. @subsection Using pki-mapping file -Note that the file name is space sensitive. +Note that the file contents are space sensitive. @example # cat /var/heimdal/pki-mapping @@ -1329,14 +1712,22 @@ lha@@EXAMPLE.ORG:CN=Love,UID=lha @subsection Using the Kerberos database +You can also store the subject of the certificate in the principal +entry in the kerberos database. + +@example +kadmin modify --pkinit-acl="CN=baz,DC=test,DC=h5l,DC=se" user@@REALM +@end example + @section Use hxtool to create certificates @subsection Generate certificates -First you need to generate a CA certificate, change the --subject to -something appropriate, the CA certificate will be valid for 10 years. +First, you need to generate a CA certificate. This example creates a +CA certificate that will be valid for 10 years. -You need to change --subject in the command below. +You need to change --subject in the command below to something +appropriate for your site. @example hxtool issue-certificate \ @@ -1352,7 +1743,8 @@ The KDC needs to have a certificate, so generate a certificate of the type ``pkinit-kdc'' and set the PK-INIT specifial SubjectAltName to the name of the krbtgt of the realm. -You need to change --subject and --pk-init-principal in the command below. +You need to change --subject and --pk-init-principal in the command +below to something appropriate for your site. @example hxtool issue-certificate \ @@ -1364,12 +1756,14 @@ hxtool issue-certificate \ --certificate="FILE:kdc.pem" @end example -The users also needs to have a certificate, so generate a certificate -of the type ``pkinit-client''. The client doesn't need to have the PK-INIT -SubjectAltName set, you can have the Subject DN in the ACL file -(pki-mapping) instead. +The users also needs to have certificates. For your first client, +generate a certificate of type ``pkinit-client''. The client doesn't +need to have the PK-INIT SubjectAltName set; you can have the Subject +DN in the ACL file (pki-mapping) instead. -You need to change --subject and --pk-init-principal in the command below. +You need to change --subject and --pk-init-principal in the command +below to something appropriate for your site. You can omit +--pk-init-principal if you're going to use the ACL file instead. @example hxtool issue-certificate \ @@ -1383,22 +1777,24 @@ hxtool issue-certificate \ @subsection Validate the certificate -hxtool also contains a tool that will validate certificates according to -rules from the PKIX document. These checks are not complete, but a good test -to check if you got all of the basic bits right in your certificates. +hxtool also contains a tool that will validate certificates according +to rules from the PKIX document. These checks are not complete, but +they provide a good test of whether you got all of the basic bits +right in your certificates. @example hxtool validate FILE:user.pem @end example @section Use OpenSSL to create certificates +@anchor{Use OpenSSL to create certificates} This section tries to give the CA owners hints how to create certificates using OpenSSL (or CA software based on OpenSSL). @subsection Using OpenSSL to create certificates with krb5PrincipalName -To make OpenSSL create certificates with krb5PrincipalName use +To make OpenSSL create certificates with krb5PrincipalName, use an @file{openssl.cnf} as described below. To see a complete example of creating client and KDC certificates, see the test-data generation script @file{lib/hx509/data/gen-req.sh} in the source-tree. The @@ -1425,7 +1821,7 @@ princ1 = GeneralString:userid @end example -Command usage +Command usage: @example openssl x509 -extensions user_certificate @@ -1455,9 +1851,9 @@ Clients using a Windows KDC with PK-INIT need configuration since windows uses pre-standard format and this can't be autodetected. The pkinit_win2k_require_binding option requires the reply for the KDC -to be of the new, secure, type that binds the request to reply. Before -clients should fake the reply from the KDC. To use this option you -have to apply a fix from Microsoft. +to be of the new, secure, type that binds the request to +reply. Before, clients could fake the reply from the KDC. To use this +option you have to apply a fix from Microsoft. @example [realms] @@ -1470,16 +1866,32 @@ have to apply a fix from Microsoft. @subsection Certificates The client certificates need to have the extended keyusage ``Microsoft -Smartcardlogin'' (openssl have the oid shortname msSmartcardLogin). +Smartcardlogin'' (openssl has the OID shortname msSmartcardLogin). See Microsoft Knowledge Base Article - 281245 ``Guidelines for Enabling Smart Card Logon with Third-Party Certification Authorities'' for a -more extensive description of how set setup an external CA to it -includes all information that will make a Windows KDC happy. +more extensive description of how set setup an external CA so that it +includes all the information required to make a Windows KDC happy. @subsection Configure Windows 2000 CA -To enable Microsoft Smartcardlogin> for certificates in your Windows -2000 CA, you want to look at Microsoft Knowledge Base Article - -313274 ``HOW TO: Configure a Certification Authority to Issue -Smart Card Certificates in Windows''. +To enable Microsoft Smartcardlogin for certificates in your Windows +2000 CA, you want to look at Microsoft Knowledge Base Article - 313274 +``HOW TO: Configure a Certification Authority to Issue Smart Card +Certificates in Windows''. + +@node Debugging Kerberos problems, , Setting up PK-INIT, Setting up a realm +@section Debugging Kerberos problems + +To debug Kerberos client and server problems you can enable debug +tracing by adding the following to @file{/etc/krb5.conf}. Note that the +trace logging is sparse at the moment, but will continue to improve. + +@example +[logging] + libkrb5 = 0-/SYSLOG: +@end example + + + + diff --git a/doc/standardisation/draft-howard-gss-sanon-13.txt b/doc/standardisation/draft-howard-gss-sanon-13.txt new file mode 100644 index 000000000..e533e3dc8 --- /dev/null +++ b/doc/standardisation/draft-howard-gss-sanon-13.txt @@ -0,0 +1,616 @@ + + + + +Network Working Group L. Howard +Internet-Draft PADL +Intended status: Informational April 27, 2020 +Expires: October 29, 2020 + + + A Simple Anonymous GSS-API Mechanism + draft-howard-gss-sanon-13 + +Abstract + + This document defines protocols, procedures and conventions for a + Generic Security Service Application Program Interface (GSS-API) + security mechanism that provides key agreement without authentication + of either party. + +Status of This Memo + + This Internet-Draft is submitted in full conformance with the + provisions of BCP 78 and BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF). Note that other groups may also distribute + working documents as Internet-Drafts. The list of current Internet- + Drafts is at https://datatracker.ietf.org/drafts/current/. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + This Internet-Draft will expire on October 29, 2020. + +Copyright Notice + + Copyright (c) 2020 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + + + + +Howard Expires October 29, 2020 [Page 1] + +Internet-Draft SAnon GSS-API Mechanism April 2020 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2 + 2. Requirements notation . . . . . . . . . . . . . . . . . . . . 2 + 3. Discovery and Negotiation . . . . . . . . . . . . . . . . . . 3 + 4. Naming . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 4.1. Mechanism Names . . . . . . . . . . . . . . . . . . . . . . 3 + 4.2. Display Name Format . . . . . . . . . . . . . . . . . . . . 3 + 4.3. Exported Name Format . . . . . . . . . . . . . . . . . . . 3 + 5. Definitions and Token Formats . . . . . . . . . . . . . . . . 4 + 5.1. Context Establishment Tokens . . . . . . . . . . . . . . . 4 + 5.1.1. Initial context token . . . . . . . . . . . . . . . . . . 4 + 5.1.2. Acceptor context token . . . . . . . . . . . . . . . . . 5 + 5.1.3. Initiator context completion . . . . . . . . . . . . . . 5 + 5.2. Per-Message Tokens . . . . . . . . . . . . . . . . . . . . 6 + 5.3. Context Deletion Tokens . . . . . . . . . . . . . . . . . . 6 + 6. Key derivation . . . . . . . . . . . . . . . . . . . . . . . 6 + 7. Pseudo-Random Function . . . . . . . . . . . . . . . . . . . 7 + 8. Security Considerations . . . . . . . . . . . . . . . . . . . 7 + 9. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . 7 + 10. References . . . . . . . . . . . . . . . . . . . . . . . . . 7 + 10.1. Normative References . . . . . . . . . . . . . . . . . . . 7 + 10.2. Informative References . . . . . . . . . . . . . . . . . . 8 + Appendix A. Test Vectors . . . . . . . . . . . . . . . . . . . . 9 + Appendix B. Mechanism Attributes . . . . . . . . . . . . . . . . 10 + Appendix C. NegoEx . . . . . . . . . . . . . . . . . . . . . . . 10 + Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 11 + +1. Introduction + + The Generic Security Service Application Program Interface (GSS-API) + [RFC2743] provides a framework for authentication and message + protection services through a common programming interface. + + The Simple Anonymous mechanism (hereafter SAnon) described in this + document is a simple protocol based on the X25519 elliptic curve + Diffie-Hellman (ECDH) key agreement scheme defined in [RFC7748]. No + authentication of initiator or acceptor is provided. A potential use + of SAnon is to provide a degree of privacy when bootstrapping unkeyed + entities. + +2. Requirements notation + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC2119]. + + + + + +Howard Expires October 29, 2020 [Page 2] + +Internet-Draft SAnon GSS-API Mechanism April 2020 + + +3. Discovery and Negotiation + + The SAnon mechanism is identified by the following OID: + + sanon-x25519 OBJECT IDENTIFIER ::= + {iso(1)identified-organization(3)dod(6)internet(1) + private(4)enterprise(1)padl(5322)gss-sanon(26) + mechanisms(1)sanon-x25519(110)} + + The means of discovering GSS-API peers and their supported mechanisms + is out of this specification's scope. To avoid multiple layers of + negotiation, SAnon is not crypto-agile; a future variant using a + different algorithm would be assigned a different OID. + + If anonymity is not desired then SAnon MUST NOT be used. Either + party can test for anon_state (GSS_C_ANON_FLAG) to check if anonymous + authentication was performed. + +4. Naming + +4.1. Mechanism Names + + A SAnon mechanism name is abstractly a boolean indicating whether it + represents an anonymous identity. Anonymous identities are names + imported with the GSS_C_NT_ANONYMOUS name type. Implementations MAY + map other names to anonymous identities according to local policy. + Names representing non-anonymous identities MUST be importable so + that initiators with non-default credentials can engage SAnon by + setting anon_req_flag (GSS_C_ANON_FLAG). + +4.2. Display Name Format + + When GSS_Display_name() is called on a mechanism name representing an + anonymous identity, the display string is WELLKNOWN/ + ANONYMOUS@WELLKNOWN:ANONYMOUS [RFC8062] and the name type is + GSS_C_NT_ANONYMOUS. This is always the name observed by a SAnon + peer. All context APIs that return peer names MUST return this name + for both parties if the context is established. + +4.3. Exported Name Format + + SAnon uses the mechanism-independent exported name object format + defined in [RFC2743] Section 3.2. All lengths are encoded as big- + endian integers. The export of non-anonymous mechanism names MUST + fail with GSS_S_BAD_NAME. + + + + + + +Howard Expires October 29, 2020 [Page 3] + +Internet-Draft SAnon GSS-API Mechanism April 2020 + + + +--------------+--------------+---------------------------------+ + | Length | Name | Description | + +--------------+--------------+---------------------------------+ + | 2 | TOK_ID | 04 01 | + | | | | + | 2 | MECH_OID_LEN | Length of the mechanism OID | + | | | | + | MECH_OID_LEN | MECH_OID | The SAnon mechanism OID, in DER | + | | | | + | 4 | NAME_LEN | 00 00 00 01 | + | | | | + | 1 | NAME | 01 | + +--------------+--------------+---------------------------------+ + +5. Definitions and Token Formats + +5.1. Context Establishment Tokens + +5.1.1. Initial context token + + The initial context token is framed per Section 1 of [RFC2743]: + + GSS-API DEFINITIONS ::= + BEGIN + + MechType ::= OBJECT IDENTIFIER -- 1.3.6.1.4.1.5322.26.1.110 + GSSAPI-Token ::= + [APPLICATION 0] IMPLICIT SEQUENCE { + thisMech MechType, + innerToken ANY DEFINED BY thisMech + -- 32 byte initiator public key + -- 8 byte protocol flags (optional) + } + END + + On the first call to GSS_Init_sec_context(), the mechanism checks if + one or more of the following are true: + + The caller set anon_req_flag (GSS_C_ANON_FLAG) + + The claimant credential identity is anonymous (see Section 4.1) + + The claimant credential is the default one and target identity is + anonymous + + If none of these are the case, the call MUST fail with + GSS_S_UNAVAILABLE. + + + + +Howard Expires October 29, 2020 [Page 4] + +Internet-Draft SAnon GSS-API Mechanism April 2020 + + + If proceeding, the initiator generates a fresh secret and public key + pair per [RFC7748] Section 6.1 and returns GSS_S_CONTINUE_NEEDED, + indicating that a subsequent context token from the acceptor is + expected. The innerToken field of the output_token contains the + initiator's 32 byte public key, optionally concatenated with a 64-bit + big-endian integer containing flags the acceptor would be otherwise + be unable to infer (such as those defined in [RFC4757] Section 7.1). + + Portable initiators are RECOMMENDED to use default credentials + whenever possible and request anonymity only through anon_req_flag + (see [RFC8062] Section 6). + +5.1.2. Acceptor context token + + Upon receiving a context token from the initiator, the acceptor + validates that the token is well formed and contains a public key of + the requisite length. The acceptor generates a fresh secret and + public key pair. The context session key is computed as specified in + Section 6. + + The acceptor constructs an output_token by concatenating its public + key with the token emitted by calling GSS_GetMIC() with the default + QOP and zero-length octet string. The output token is sent to the + initiator without additional framing. + + The acceptor then returns GSS_S_COMPLETE, setting src_name to the + canonical anonymous name. The reply_det_state (GSS_C_REPLAY_FLAG), + sequence_state (GSS_C_SEQUENCE_FLAG), conf_avail (GSS_C_CONF_FLAG), + integ_avail (GSS_C_INTEG_FLAG) and anon_state (GSS_C_ANON_FLAG) + security context flags are set, along with any additional flags + received from the initiator. The context is ready to use. + +5.1.3. Initiator context completion + + Upon receiving the acceptor context token and verifying it is well + formed, the initiator extracts the acceptor's public key (being the + first 32 bytes of the input token) and computes the context session + key per Section 6. + + The initiator calls GSS_VerifyMIC() with the MIC extracted from the + context token and the zero-length octet string. If successful, the + initiator returns GSS_S_COMPLETE to the caller, to indicate the + initiator is authenticated and the context is ready for use. No + output token is emitted. Supported security context flags are as for + the acceptor context. The flags returned to the caller are the + intersection of supported and requested flags, combined with + anon_state (GSS_C_ANON_FLAG) which is set unconditionally. + + + + +Howard Expires October 29, 2020 [Page 5] + +Internet-Draft SAnon GSS-API Mechanism April 2020 + + +5.2. Per-Message Tokens + + The per-message tokens definitions are imported from [RFC4121] + Section 4.2. The base key used to derive specific keys for signing + and sealing messages is defined in Section 6. The [RFC3961] + encryption and checksum algorithms use the aes128-cts-hmac-sha256-128 + encryption type defined in [RFC8009]. The AcceptorSubkey flag as + defined in [RFC4121] Section 4.2.2 MUST be set. + +5.3. Context Deletion Tokens + + Context deletion tokens are empty in this mechanism. The behavior of + GSS_Delete_sec_context() [RFC2743] is as specified in [RFC4121] + Section 4.3. + +6. Key derivation + + The context session key is known as the base key, and is computed + using a key derivation function from [SP800-108] Section 5.1 (using + HMAC as the PRF): + + base key = HMAC-SHA-256(K1, i | label | 0x00 | context | L) + + where: + + K1 the output of X25519(local secret key, peer public key) + as specified in [RFC7748] Section 6.1 + + i the constant 0x00000001, representing the iteration + count expressed in big-endian binary representation of + 4 bytes + + label the string "sanon-x25519" (without quotation marks) + + context initiator public key | acceptor public key | flags | + channel binding application data (if present) + + L the constant 0x00000080, being length in bits of the + key to be outputted expressed in big-endian binary + representation of 4 bytes + + The flags input to the context contains any flags sent by the + initiator, defaulting to zero if none were sent, expressed in big- + endian binary representation of 8 bytes. + + The inclusion of channel bindings in the key derivation function + means that the acceptor cannot ignore initiator channel bindings; + this differs from some other mechanisms. + + + +Howard Expires October 29, 2020 [Page 6] + +Internet-Draft SAnon GSS-API Mechanism April 2020 + + + The base key provides the acceptor-asserted subkey defined in + [RFC4121] Section 2 and is used to generate keys for per-message + tokens and the GSS-API PRF. Its encryption type is aes128-cts-hmac- + sha256-128 per [RFC8009]. The [RFC3961] algorithm protocol + parameters are as given in [RFC8009] Section 5. + +7. Pseudo-Random Function + + The [RFC4401] GSS-API pseudo-random function for this mechanism + imports the definitions from [RFC8009], using the base key for both + GSS_C_PRF_KEY_FULL and GSS_C_PRF_KEY_PARTIAL usages. + +8. Security Considerations + + This document defines a GSS-API security mechanism, and therefore + deals in security and has security considerations text embedded + throughout. This section only addresses security considerations + associated with the SAnon mechanism described in this document. It + does not address security considerations associated with the GSS-API + itself. + + This mechanism provides only for key agreement. It does not + authenticate the identity of either party. It MUST NOT be selected + if either party requires identification of its peer. + + SAnon mechanism names are not unary. Implementations MUST ensure + that GSS_Compare_name() always sets name_equal to FALSE when + comparing mechanism names. + +9. Acknowledgements + + AuriStor, Inc funded the design of this protocol, along with an + implementation for the Heimdal GSS-API library. + + Jeffrey Altman, Greg Hudson, Simon Josefsson, and Nicolas Williams + provided valuable feedback on this document. + +10. References + +10.1. Normative References + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, + DOI 10.17487/RFC2119, March 1997, + . + + + + + + +Howard Expires October 29, 2020 [Page 7] + +Internet-Draft SAnon GSS-API Mechanism April 2020 + + + [RFC2743] Linn, J., "Generic Security Service Application Program + Interface Version 2, Update 1", RFC 2743, + DOI 10.17487/RFC2743, January 2000, + . + + [RFC3961] Raeburn, K., "Encryption and Checksum Specifications for + Kerberos 5", RFC 3961, DOI 10.17487/RFC3961, February + 2005, . + + [RFC4121] Zhu, L., Jaganathan, K., and S. Hartman, "The Kerberos + Version 5 Generic Security Service Application Program + Interface (GSS-API) Mechanism: Version 2", RFC 4121, + DOI 10.17487/RFC4121, July 2005, + . + + [RFC4401] Williams, N., "A Pseudo-Random Function (PRF) API + Extension for the Generic Security Service Application + Program Interface (GSS-API)", RFC 4401, + DOI 10.17487/RFC4401, February 2006, + . + + [RFC7748] Langley, A., Hamburg, M., and S. Turner, "Elliptic Curves + for Security", RFC 7748, DOI 10.17487/RFC7748, January + 2016, . + + [RFC8009] Jenkins, M., Peck, M., and K. Burgin, "AES Encryption with + HMAC-SHA2 for Kerberos 5", RFC 8009, DOI 10.17487/RFC8009, + October 2016, . + +10.2. Informative References + + [I-D.zhu-negoex] + Short, M., Zhu, L., Damour, K., and D. McPherson, "SPNEGO + Extended Negotiation (NEGOEX) Security Mechanism", draft- + zhu-negoex-04 (work in progress), January 2011. + + [RFC4178] Zhu, L., Leach, P., Jaganathan, K., and W. Ingersoll, "The + Simple and Protected Generic Security Service Application + Program Interface (GSS-API) Negotiation Mechanism", + RFC 4178, DOI 10.17487/RFC4178, October 2005, + . + + [RFC4757] Jaganathan, K., Zhu, L., and J. Brezak, "The RC4-HMAC + Kerberos Encryption Types Used by Microsoft Windows", + RFC 4757, DOI 10.17487/RFC4757, December 2006, + . + + + + + +Howard Expires October 29, 2020 [Page 8] + +Internet-Draft SAnon GSS-API Mechanism April 2020 + + + [RFC5587] Williams, N., "Extended Generic Security Service Mechanism + Inquiry APIs", RFC 5587, DOI 10.17487/RFC5587, July 2009, + . + + [RFC8062] Zhu, L., Leach, P., Hartman, S., and S. Emery, Ed., + "Anonymity Support for Kerberos", RFC 8062, + DOI 10.17487/RFC8062, February 2017, + . + + [SP800-108] + Chen, L., "Recommendation for Key Derivation Using + Pseudorandom Functions (Revised)", October 2009. + +Appendix A. Test Vectors + + The example exchange below contains no extra flags or channel binding + information. + + initiator secret key 83 33 f2 ea 2a 22 eb aa 05 39 c6 06 1d 6a 99 05 + 84 24 49 9e 2c 16 c1 b1 34 d9 22 27 f3 f4 5e bd + + initiator public key 5f 40 66 22 5a 3c fd 72 57 23 c1 8f ae 71 3e 8c + ab 32 a7 2c 93 b9 76 66 04 4b 8f e4 a0 c9 69 19 + + initiator token 60 2c 06 0a 2b 06 01 04 01 a9 4a 1a 01 6e 5f 40 + 66 22 5a 3c fd 72 57 23 c1 8f ae 71 3e 8c ab 32 + a7 2c 93 b9 76 66 04 4b 8f e4 a0 c9 69 1 + + acceptor secret key b0 db 16 32 39 0a dd 93 1e f7 62 bc d3 c9 1d 03 + e8 d9 59 52 48 eb e2 f2 b5 f7 d8 06 ec dd 50 60 + + acceptor public key 2f 81 51 9f a8 9c 07 f8 eb b2 95 6c 0c c3 22 77 + ae a1 0e 62 0c 79 33 81 ef 9a c5 b2 f0 d9 1e 06 + + base key 80 76 2c 43 32 6a 95 f5 be 30 6d ea 10 ba f3 d0 + + acceptor token 2f 81 51 9f a8 9c 07 f8 eb b2 95 6c 0c c3 22 77 + ae a1 0e 62 0c 79 33 81 ef 9a c5 b2 f0 d9 1e 06 + 04 04 05 ff ff ff ff ff 00 00 00 00 00 00 00 00 + 4d 5e a9 e0 e1 9c 7a 61 c2 6a 9a c5 e8 17 5f 04 + + initiator negoex key 2a c8 f9 d0 31 87 40 42 cb d4 50 07 ce db c2 c2 + + acceptor negoex key 73 9f 4d a2 f1 2d f7 f7 d7 ea e4 9d a4 08 62 5b + + + + + + + +Howard Expires October 29, 2020 [Page 9] + +Internet-Draft SAnon GSS-API Mechanism April 2020 + + +Appendix B. Mechanism Attributes + + The [RFC5587] mechanism attributes for this mechanism are: + + GSS_C_MA_MECH_CONCRETE + + GSS_C_MA_ITOK_FRAMED + + GSS_C_MA_AUTH_INIT_ANON + + GSS_C_MA_AUTH_TARG_ANON + + GSS_C_MA_INTEG_PROT + + GSS_C_MA_CONF_PROT + + GSS_C_MA_MIC + + GSS_C_MA_WRAP + + GSS_C_MA_REPLAY_DET + + GSS_C_MA_OOS_DET + + GSS_C_MA_CBINDINGS + + GSS_C_MA_PFS + + GSS_C_MA_CTX_TRANS + +Appendix C. NegoEx + + When SAnon is negotiated by [I-D.zhu-negoex], the authentication + scheme identifier is DEE384FF-1086-4E86-BE78-B94170BFD376. + + The initiator and acceptor keys for NegoEx checksum generation and + verification are derived using the GSS-API PRF (see Section 7), with + the input data "sanon-x25519-initiator-negoex-key" and "sanon-x25519- + acceptor-negoex-key" respectively (without quotation marks). No + metadata is defined and any, if present, SHOULD be ignored. + + It is RECOMMENDED that GSS-API implementations supporting both SPNEGO + [RFC4178] and NegoEx advertise SAnon under both to maximise + interoperability. + + + + + + + +Howard Expires October 29, 2020 [Page 10] + +Internet-Draft SAnon GSS-API Mechanism April 2020 + + +Author's Address + + Luke Howard + PADL Software Pty Ltd + PO Box 59 + Central Park, VIC 3145 + Australia + + Email: lukeh@padl.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Howard Expires October 29, 2020 [Page 11] diff --git a/doc/standardisation/draft-ietf-krb-wg-preauth-framework-14.txt b/doc/standardisation/draft-ietf-krb-wg-preauth-framework-14.txt new file mode 100644 index 000000000..588b87adb --- /dev/null +++ b/doc/standardisation/draft-ietf-krb-wg-preauth-framework-14.txt @@ -0,0 +1,2801 @@ + + + +Kerberos Working Group S. Hartman +Internet-Draft Painless Security +Updates: 4120 (if approved) L. Zhu +Intended status: Standards Track Microsoft Corporation +Expires: February 13, 2010 August 12, 2009 + + + A Generalized Framework for Kerberos Pre-Authentication + draft-ietf-krb-wg-preauth-framework-14 + +Status of this Memo + + This Internet-Draft is submitted to IETF in full conformance with the + provisions of BCP 78 and BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF), its areas, and its working groups. Note that + other groups may also distribute working documents as Internet- + Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on February 13, 2010. + +Copyright Notice + + Copyright (c) 2009 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents in effect on the date of + publication of this document (http://trustee.ietf.org/license-info). + Please review these documents carefully, as they describe your rights + and restrictions with respect to this document. + +Abstract + + Kerberos is a protocol for verifying the identity of principals + (e.g., a workstation user or a network server) on an open network. + + + +Hartman & Zhu Expires February 13, 2010 [Page 1] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + The Kerberos protocol provides a mechanism called pre-authentication + for proving the identity of a principal and for better protecting the + long-term secrets of the principal. + + This document describes a model for Kerberos pre-authentication + mechanisms. The model describes what state in the Kerberos request a + pre-authentication mechanism is likely to change. It also describes + how multiple pre-authentication mechanisms used in the same request + will interact. + + This document also provides common tools needed by multiple pre- + authentication mechanisms. One of these tools is a secure channel + between the client and the KDC with a reply key strengthening + mechanism; this secure channel can be used to protect the + authentication exchange thus eliminate offline dictionary attacks. + With these tools, it is relatively straightforward to chain multiple + authentication mechanisms, utilize a different key management system, + or support a new key agreement algorithm. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Hartman & Zhu Expires February 13, 2010 [Page 2] + +Internet-Draft Kerberos Preauth Framework August 2009 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 5 + 2. Conventions and Terminology Used in This Document . . . . . . 6 + 3. Model for Pre-Authentication . . . . . . . . . . . . . . . . . 6 + 3.1. Information Managed by the Pre-authentication Model . . . 7 + 3.2. Initial Pre-authentication Required Error . . . . . . . . 10 + 3.3. Client to KDC . . . . . . . . . . . . . . . . . . . . . . 10 + 3.4. KDC to Client . . . . . . . . . . . . . . . . . . . . . . 11 + 4. Pre-Authentication Facilities . . . . . . . . . . . . . . . . 12 + 4.1. Client-authentication Facility . . . . . . . . . . . . . . 13 + 4.2. Strengthening-reply-key Facility . . . . . . . . . . . . . 14 + 4.3. Replacing-reply-key Facility . . . . . . . . . . . . . . . 15 + 4.4. KDC-authentication Facility . . . . . . . . . . . . . . . 15 + 5. Requirements for Pre-Authentication Mechanisms . . . . . . . . 16 + 6. Tools for Use in Pre-Authentication Mechanisms . . . . . . . . 17 + 6.1. Combining Keys . . . . . . . . . . . . . . . . . . . . . . 17 + 6.2. Protecting Requests/Responses . . . . . . . . . . . . . . 18 + 6.3. Managing States for the KDC . . . . . . . . . . . . . . . 19 + 6.4. Pre-authentication Set . . . . . . . . . . . . . . . . . . 20 + 6.5. Definition of Kerberos FAST Padata . . . . . . . . . . . . 23 + 6.5.1. FAST Armors . . . . . . . . . . . . . . . . . . . . . 24 + 6.5.2. FAST Request . . . . . . . . . . . . . . . . . . . . . 26 + 6.5.3. FAST Response . . . . . . . . . . . . . . . . . . . . 30 + 6.5.4. Authenticated Kerberos Error Messages using + Kerberos FAST . . . . . . . . . . . . . . . . . . . . 33 + 6.5.5. Outer and Inner Requests . . . . . . . . . . . . . . . 34 + 6.5.6. The Encrypted Challenge FAST Factor . . . . . . . . . 34 + 6.6. Authentication Strength Indication . . . . . . . . . . . . 36 + 7. Assigned Constants . . . . . . . . . . . . . . . . . . . . . . 37 + 7.1. New Errors . . . . . . . . . . . . . . . . . . . . . . . . 37 + 7.2. Key Usage Numbers . . . . . . . . . . . . . . . . . . . . 37 + 7.3. Authorization Data Elements . . . . . . . . . . . . . . . 37 + 7.4. New PA-DATA Types . . . . . . . . . . . . . . . . . . . . 38 + 8. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 38 + 8.1. Pre-authentication and Typed Data . . . . . . . . . . . . 38 + 8.2. Fast Armor Types . . . . . . . . . . . . . . . . . . . . . 40 + 8.3. FAST Options . . . . . . . . . . . . . . . . . . . . . . . 40 + 9. Security Considerations . . . . . . . . . . . . . . . . . . . 41 + 10. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 42 + 11. References . . . . . . . . . . . . . . . . . . . . . . . . . . 43 + 11.1. Normative References . . . . . . . . . . . . . . . . . . . 43 + 11.2. Informative References . . . . . . . . . . . . . . . . . . 43 + Appendix A. Test Vectors for KRB-FX-CF2 . . . . . . . . . . . . . 44 + Appendix B. Change History . . . . . . . . . . . . . . . . . . . 45 + B.1. Changes since 13 . . . . . . . . . . . . . . . . . . . . . 45 + B.2. Changes since 12 . . . . . . . . . . . . . . . . . . . . . 45 + B.3. Changes since 11 . . . . . . . . . . . . . . . . . . . . . 45 + + + +Hartman & Zhu Expires February 13, 2010 [Page 3] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + B.4. Changes since 10 . . . . . . . . . . . . . . . . . . . . . 45 + B.5. Changes since 09 . . . . . . . . . . . . . . . . . . . . . 45 + B.6. Changes since 08 . . . . . . . . . . . . . . . . . . . . . 46 + B.7. Changes since 07 . . . . . . . . . . . . . . . . . . . . . 47 + B.8. Changes since 06 . . . . . . . . . . . . . . . . . . . . . 47 + Appendix C. ASN.1 module . . . . . . . . . . . . . . . . . . . . 47 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 50 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Hartman & Zhu Expires February 13, 2010 [Page 4] + +Internet-Draft Kerberos Preauth Framework August 2009 + + +1. Introduction + + The core Kerberos specification [RFC4120] treats pre-authentication + data as an opaque typed hole in the messages to the KDC that may + influence the reply key used to encrypt the KDC reply. This + generality has been useful: pre-authentication data is used for a + variety of extensions to the protocol, many outside the expectations + of the initial designers. However, this generality makes designing + more common types of pre-authentication mechanisms difficult. Each + mechanism needs to specify how it interacts with other mechanisms. + Also, problems like combining a key with the long-term secrets or + proving the identity of the user are common to multiple mechanisms. + Where there are generally well-accepted solutions to these problems, + it is desirable to standardize one of these solutions so mechanisms + can avoid duplication of work. In other cases, a modular approach to + these problems is appropriate. The modular approach will allow new + and better solutions to common pre-authentication problems to be used + by existing mechanisms as they are developed. + + This document specifies a framework for Kerberos pre-authentication + mechanisms. It defines the common set of functions that pre- + authentication mechanisms perform as well as how these functions + affect the state of the request and reply. In addition several + common tools needed by pre-authentication mechanisms are provided. + Unlike [RFC3961], this framework is not complete--it does not + describe all the inputs and outputs for the pre-authentication + mechanisms. Pre-Authentication mechanism designers should try to be + consistent with this framework because doing so will make their + mechanisms easier to implement. Kerberos implementations are likely + to have plugin architectures for pre-authentication; such + architectures are likely to support mechanisms that follow this + framework plus commonly used extensions. This framework also + facilitates combining multiple pre-authentication mechanisms, each of + which may represent an authentication factor, into a single multi- + factor pre-authentication mechanism. + + One of these common tools is the flexible authentication secure + tunneling (FAST) padata type. FAST provides a protected channel + between the client and the KDC, and it can optionally deliver key + material used to strengthen the reply key within the protected + channel. Based on FAST, pre-authentication mechanisms can extend + Kerberos with ease, to support, for example, password authenticated + key exchange (PAKE) protocols with zero knowledge password proof + (ZKPP) [EKE] [IEEE1363.2]. Any pre-authentication mechanism can be + encapsulated in the FAST messages as defined in Section 6.5. A pre- + authentication type carried within FAST is called a FAST factor. + Creating a FAST factor is the easiest path to create a new pre- + authentication mechanism. FAST factors are significantly easier to + + + +Hartman & Zhu Expires February 13, 2010 [Page 5] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + analyze from a security standpoint than other pre-authentication + mechanisms. + + Mechanism designers should design FAST factors, instead of new pre- + authentication mechanisms outside of FAST. + + +2. Conventions and Terminology Used in This Document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC2119]. + + This document should be read only after reading the documents + describing the Kerberos cryptography framework [RFC3961] and the core + Kerberos protocol [RFC4120]. This document may freely use + terminology and notation from these documents without reference or + further explanation. + + The word padata is used as a shorthand for pre-authentication data. + + A conversation is the set of all authentication messages exchanged + between the client and the client's Authentication Service (AS) in + order to authenticate the client principal. A conversation as + defined here consists of all messages that are necessary to complete + the authentication between the client and the client's AS. In the + Ticket Exchange Service (TGS) exchange, a conversation consists of + the request message and the reply message. The term conversation is + defined here for both AS and TGS for convenience of discussion. See + Section 6.3 for specific rules on the extent of a conversation in the + AS-REQ case. Prior to this framework, implementations needed to use + implementation-specific heuristics to determine the extent of a + conversation. + + If the KDC reply in an AS exchange is verified, the KDC is + authenticated by the client. In this document, verification of the + KDC reply is used as a synonym of authentication of the KDC. + + +3. Model for Pre-Authentication + + When a Kerberos client wishes to obtain a ticket using the + authentication server, it sends an initial Authentication Service + (AS) request. If pre-authentication is required but not being used, + then the KDC will respond with a KDC_ERR_PREAUTH_REQUIRED error. + Alternatively, if the client knows what pre-authentication to use, it + MAY optimize away a round-trip and send an initial request with + padata included in the initial request. If the client includes the + + + +Hartman & Zhu Expires February 13, 2010 [Page 6] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + padata computed using the wrong pre-authentication mechanism or + incorrect keys, the KDC MAY return KDC_ERR_PREAUTH_FAILED with no + indication of what padata should have been included. In that case, + the client MUST retry with no padata and examine the error data of + the KDC_ERR_PREAUTH_REQUIRED error. If the KDC includes pre- + authentication information in the accompanying error data of + KDC_ERR_PREAUTH_FAILED, the client SHOULD process the error data, and + then retry. + + The conventional KDC maintains no state between two requests; + subsequent requests may even be processed by a different KDC. On the + other hand, the client treats a series of exchanges with KDCs as a + single conversation. Each exchange accumulates state and hopefully + brings the client closer to a successful authentication. + + These models for state management are in apparent conflict. For many + of the simpler pre-authentication scenarios, the client uses one + round trip to find out what mechanisms the KDC supports. Then the + next request contains sufficient pre-authentication for the KDC to be + able to return a successful reply. For these simple scenarios, the + client only sends one request with pre-authentication data and so the + conversation is trivial. For more complex conversations, the KDC + needs to provide the client with a cookie to include in future + requests to capture the current state of the authentication session. + Handling of multiple round-trip mechanisms is discussed in + Section 6.3. + + This framework specifies the behavior of Kerberos pre-authentication + mechanisms used to identify users or to modify the reply key used to + encrypt the KDC reply. The PA-DATA typed hole may be used to carry + extensions to Kerberos that have nothing to do with proving the + identity of the user or establishing a reply key. Such extensions + are outside the scope of this framework. However mechanisms that do + accomplish these goals should follow this framework. + + This framework specifies the minimum state that a Kerberos + implementation needs to maintain while handling a request in order to + process pre-authentication. It also specifies how Kerberos + implementations process the padata at each step of the AS request + process. + +3.1. Information Managed by the Pre-authentication Model + + The following information is maintained by the client and KDC as each + request is being processed: + + + + + + +Hartman & Zhu Expires February 13, 2010 [Page 7] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + o The reply key used to encrypt the KDC reply + + o How strongly the identity of the client has been authenticated + + o Whether the reply key has been used in this conversation + + o Whether the reply key has been replaced in this conversation + + o Whether the origin of the KDC reply can be verified by the client + (i.e. whether the KDC is authenticated to the client) + + + Conceptually, the reply key is initially the long-term key of the + principal. However, principals can have multiple long-term keys + because of support for multiple encryption types, salts and + string2key parameters. As described in Section 5.2.7.5 of the + Kerberos protocol [RFC4120], the KDC sends PA-ETYPE-INFO2 to notify + the client what types of keys are available. Thus in full + generality, the reply key in the pre-authentication model is actually + a set of keys. At the beginning of a request, it is initialized to + the set of long-term keys advertised in the PA-ETYPE-INFO2 element on + the KDC. If multiple reply keys are available, the client chooses + which one to use. Thus the client does not need to treat the reply + key as a set. At the beginning of a request, the client picks a key + to use. + + KDC implementations MAY choose to offer only one key in the PA-ETYPE- + INFO2 element. Since the KDC already knows the client's list of + supported enctypes from the request, no interoperability problems are + created by choosing a single possible reply key. This way, the KDC + implementation avoids the complexity of treating the reply key as a + set. + + When the padata in the request is verified by the KDC, then the + client is known to have that key, therefore the KDC SHOULD pick the + same key as the reply key. + + At the beginning of handling a message on both the client and the + KDC, the client's identity is not authenticated. A mechanism may + indicate that it has successfully authenticated the client's + identity. This information is useful to keep track of on the client + in order to know what pre-authentication mechanisms should be used. + The KDC needs to keep track of whether the client is authenticated + because the primary purpose of pre-authentication is to authenticate + the client identity before issuing a ticket. The handling of + authentication strength using various authentication mechanisms is + discussed in Section 6.6. + + + + +Hartman & Zhu Expires February 13, 2010 [Page 8] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + Initially the reply key has not been used. A pre-authentication + mechanism that uses the reply key to encrypt or checksum some data in + the generation of new keys MUST indicate that the reply key is used. + This state is maintained by the client and the KDC to enforce the + security requirement stated in Section 4.3 that the reply key SHOULD + NOT be replaced after it is used. + + Initially the reply key has not been replaced. If a mechanism + implements the Replace Reply Key facility discussed in Section 4.3, + then the state MUST be updated to indicate that the reply key has + been replaced. Once the reply key has been replaced, knowledge of + the reply key is insufficient to authenticate the client. The reply + key is marked replaced in exactly the same situations as the KDC + reply is marked as not being verified to the client principal. + However, while mechanisms can verify the KDC reply to the client, + once the reply key is replaced, then the reply key remains replaced + for the remainder of the conversation. + + Without pre-authentication, the client knows that the KDC reply is + authentic and has not been modified because it is encrypted in a + long-term key of the client. Only the KDC and the client know that + key. So at the start of a conversation, the KDC reply is presumed to + be verified using the client's long-term key. It should be noted + that in this document, verifying the KDC reply means authenticating + the KDC, and these phrases are used interchangeably. Any pre- + authentication mechanism that sets a new reply key not based on the + principal's long-term secret MUST either verify the KDC reply some + other way or indicate that the reply is not verified. If a mechanism + indicates that the reply is not verified then the client + implementation MUST return an error unless a subsequent mechanism + verifies the reply. The KDC needs to track this state so it can + avoid generating a reply that is not verified. + + In this specification, KDC verification/authentication refers to the + level of authentication of the KDC to the client provided by RFC + 4120. There is a stronger form of KDC verification that, while + sometimes important in Kerberos deployments is not addressed in this + specification: the typical Kerberos request does not provide a way + for the client machine to know that it is talking to the correct KDC. + Someone who can inject packets into the network between the client + machine and the KDC and who knows the password that the user will + give to the client machine can generate a KDC reply that will decrypt + properly. So, if the client machine needs to authenticate that the + user is in fact the named principal, then the client machine needs to + do a TGS request for itself as a service. Some pre-authentication + mechanisms may provide a way for the client machine to authenticate + the KDC. Examples of this include signing the reply that can be + verified using a well-known public key or providing a ticket for the + + + +Hartman & Zhu Expires February 13, 2010 [Page 9] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + client machine as a service. + +3.2. Initial Pre-authentication Required Error + + Typically a client starts a conversation by sending an initial + request with no pre-authentication. If the KDC requires pre- + authentication, then it returns a KDC_ERR_PREAUTH_REQUIRED message. + After the first reply with the KDC_ERR_PREAUTH_REQUIRED error code, + the KDC returns the error code KDC_ERR_MORE_PREAUTH_DATA_REQUIRED + (defined in Section 6.3) for pre-authentication configurations that + use multi-round-trip mechanisms; see Section 3.4 for details of that + case. + + The KDC needs to choose which mechanisms to offer the client. The + client needs to be able to choose what mechanisms to use from the + first message. For example consider the KDC that will accept + mechanism A followed by mechanism B or alternatively the single + mechanism C. A client that supports A and C needs to know that it + should not bother trying A. + + Mechanisms can either be sufficient on their own or can be part of an + authentication set--a group of mechanisms that all need to + successfully complete in order to authenticate a client. Some + mechanisms may only be useful in authentication sets; others may be + useful alone or in authentication sets. For the second group of + mechanisms, KDC policy dictates whether the mechanism will be part of + an authentication set, offered alone, or both. For each mechanism + that is offered alone (even if it is also offered in an + authentication set), the KDC includes the pre-authentication type ID + of the mechanism in the padata sequence returned in the + KDC_ERR_PREAUTH_REQUIRED error. Mechanisms that are only offered as + part of an authentication set are not directly represented in the + padata sequence returned in the KDC_ERR_PREAUTH_REQUIRED error, + although they are represented in the PA-AUTHENTICATION-SET sequence. + + The KDC SHOULD NOT send data that is encrypted in the long-term + password-based key of the principal. Doing so has the same security + exposures as the Kerberos protocol without pre-authentication. There + are few situations where the KDC needs to expose cipher text + encrypted in a weak key before the client has proven knowledge of + that key, and pre-authentication is desirable. + +3.3. Client to KDC + + This description assumes that a client has already received a + KDC_ERR_PREAUTH_REQUIRED from the KDC. If the client performs + optimistic pre-authentication then the client needs to guess values + for the information it would normally receive from that error + + + +Hartman & Zhu Expires February 13, 2010 [Page 10] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + response or use cached information obtained in prior interactions + with the KDC. + + The client starts by initializing the pre-authentication state as + specified. It then processes the padata in the + KDC_ERR_PREAUTH_REQUIRED. + + When processing the response to the KDC_ERR_PREAUTH_REQUIRED, the + client MAY ignore any padata it chooses unless doing so violates a + specification to which the client conforms. Clients conforming to + this specification MUST NOT ignore the padata defined in Section 6.3. + Clients SHOULD process padata unrelated to this framework or other + means of authenticating the user. Clients SHOULD choose one + authentication set or mechanism that could lead to authenticating the + user and ignore the rest. Since the list of mechanisms offered by + the KDC is in the decreasing preference order, clients typically + choose the first mechanism or authentication set that the client can + usefully perform. If a client chooses to ignore a padata it MUST NOT + process the padata, allow the padata to affect the pre-authentication + state, nor respond to the padata. + + For each padata the client chooses to process, the client processes + the padata and modifies the pre-authentication state as required by + that mechanism. Padata are processed in the order received from the + KDC. + + After processing the padata in the KDC error, the client generates a + new request. It processes the pre-authentication mechanisms in the + order in which they will appear in the next request, updating the + state as appropriate. The request is sent when it is complete. + +3.4. KDC to Client + + When a KDC receives an AS request from a client, it needs to + determine whether it will respond with an error or an AS reply. + There are many causes for an error to be generated that have nothing + to do with pre-authentication; they are discussed in the core + Kerberos specification. + + From the standpoint of evaluating the pre-authentication, the KDC + first starts by initializing the pre-authentication state. If a PA- + FX-COOKIE pre-authentication data item is present, it is processed + first; see Section 6.3 for a definition. It then processes the + padata in the request. As mentioned in Section 3.3, the KDC MAY + ignore padata that is inappropriate for the configuration and MUST + ignore padata of an unknown type. The KDC MUST NOT ignore padata of + types used in previous messages. For example, if a KDC issues a + KDC_ERR_PREAUTH_REQUIRED error including padata of type x, then the + + + +Hartman & Zhu Expires February 13, 2010 [Page 11] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + KDC cannot ignore padata of type x received in an AS-REQ message from + the client. + + At this point the KDC decides whether it will issue an error or a + reply. Typically a KDC will issue a reply if the client's identity + has been authenticated to a sufficient degree. + + In the case of a KDC_ERR_MORE_PREAUTH_DATA_REQUIRED error, the KDC + first starts by initializing the pre-authentication state. Then it + processes any padata in the client's request in the order provided by + the client. Mechanisms that are not understood by the KDC are + ignored. Next, it generates padata for the error response, modifying + the pre-authentication state appropriately as each mechanism is + processed. The KDC chooses the order in which it will generate + padata (and thus the order of padata in the response), but it needs + to modify the pre-authentication state consistently with the choice + of order. For example, if some mechanism establishes an + authenticated client identity, then the subsequent mechanisms in the + generated response receive this state as input. After the padata is + generated, the error response is sent. Typically the errors with the + code KDC_ERR_MORE_PREAUTH_DATA_REQUIRED in a conversation will + include KDC state as discussed in Section 6.3. + + To generate a final reply, the KDC generates the padata modifying the + pre-authentication state as necessary. Then it generates the final + response, encrypting it in the current pre-authentication reply key. + + +4. Pre-Authentication Facilities + + Pre-Authentication mechanisms can be thought of as providing various + conceptual facilities. This serves two useful purposes. First, + mechanism authors can choose only to solve one specific small + problem. It is often useful for a mechanism designed to offer key + management not to directly provide client authentication but instead + to allow one or more other mechanisms to handle this need. Secondly, + thinking about the abstract services that a mechanism provides yields + a minimum set of security requirements that all mechanisms providing + that facility must meet. These security requirements are not + complete; mechanisms will have additional security requirements based + on the specific protocol they employ. + + A mechanism is not constrained to only offering one of these + facilities. While such mechanisms can be designed and are sometimes + useful, many pre-authentication mechanisms implement several + facilities. By combining multiple facilities in a single mechanism, + it is often easier to construct a secure, simple solution than by + solving the problem in full generality. Even when mechanisms provide + + + +Hartman & Zhu Expires February 13, 2010 [Page 12] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + multiple facilities, they need to meet the security requirements for + all the facilities they provide. If the FAST factor approach is + used, it is likely that one or a small number of facilities can be + provided by a single mechanism without complicating the security + analysis. + + According to Kerberos extensibility rules (Section 1.5 of the + Kerberos specification [RFC4120]), an extension MUST NOT change the + semantics of a message unless a recipient is known to understand that + extension. Because a client does not know that the KDC supports a + particular pre-authentication mechanism when it sends an initial + request, a pre-authentication mechanism MUST NOT change the semantics + of the request in a way that will break a KDC that does not + understand that mechanism. Similarly, KDCs MUST NOT send messages to + clients that affect the core semantics unless the client has + indicated support for the message. + + The only state in this model that would break the interpretation of a + message is changing the expected reply key. If one mechanism changed + the reply key and a later mechanism used that reply key, then a KDC + that interpreted the second mechanism but not the first would fail to + interpret the request correctly. In order to avoid this problem, + extensions that change core semantics are typically divided into two + parts. The first part proposes a change to the core semantic--for + example proposes a new reply key. The second part acknowledges that + the extension is understood and that the change takes effect. + Section 4.2 discusses how to design mechanisms that modify the reply + key to be split into a proposal and acceptance without requiring + additional round trips to use the new reply key in subsequent pre- + authentication. Other changes in the state described in Section 3.1 + can safely be ignored by a KDC that does not understand a mechanism. + Mechanisms that modify the behavior of the request outside the scope + of this framework need to carefully consider the Kerberos + extensibility rules to avoid similar problems. + +4.1. Client-authentication Facility + + The client authentication facility proves the identity of a user to + the KDC before a ticket is issued. Examples of mechanisms + implementing this facility include the encrypted timestamp facility + defined in Section 5.2.7.2 of the Kerberos specification [RFC4120]. + Mechanisms that provide this facility are expected to mark the client + as authenticated. + + Mechanisms implementing this facility SHOULD require the client to + prove knowledge of the reply key before transmitting a successful KDC + reply. Otherwise, an attacker can intercept the pre-authentication + exchange and get a reply to attack. One way of proving the client + + + +Hartman & Zhu Expires February 13, 2010 [Page 13] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + knows the reply key is to implement the Replace Reply Key facility + along with this facility. The PKINIT mechanism [RFC4556] implements + Client Authentication alongside Replace Reply Key. + + If the reply key has been replaced, then mechanisms such as + encrypted-timestamp that rely on knowledge of the reply key to + authenticate the client MUST NOT be used. + +4.2. Strengthening-reply-key Facility + + Particularly when dealing with keys based on passwords, it is + desirable to increase the strength of the key by adding additional + secrets to it. Examples of sources of additional secrets include the + results of a Diffie-Hellman key exchange or key bits from the output + of a smart card [KRB-WG.SAM]. Typically these additional secrets can + be first combined with the existing reply key and then converted to a + protocol key using tools defined in Section 6.1. + + Typically a mechanism implementing this facility will know that the + other side of the exchange supports the facility before the reply key + is changed. For example, a mechanism might need to learn the + certificate for a KDC before encrypting a new key in the public key + belonging to that certificate. However, if a mechanism implementing + this facility wishes to modify the reply key before knowing that the + other party in the exchange supports the mechanism, it proposes + modifying the reply key. The other party then includes a message + indicating that the proposal is accepted if it is understood and + meets policy. In many cases it is desirable to use the new reply key + for client authentication and for other facilities. Waiting for the + other party to accept the proposal and actually modify the reply key + state would add an additional round trip to the exchange. Instead, + mechanism designers are encouraged to include a typed hole for + additional padata in the message that proposes the reply key change. + The padata included in the typed hole are generated assuming the new + reply key. If the other party accepts the proposal, then these + padata are considered as an inner level. As with the outer level, + one authentication set or mechanism is typically chosen for client + authentication, along with auxiliary mechanisms such as KDC cookies, + and other mechanisms are ignored. When mechanisms include such a + container, the hint provided for use in authentication sets (as + defined in Section 6.4) MUST contain a sequence of inner mechanisms + along with hints for those mechanisms. The party generating the + proposal can determine whether the padata were processed based on + whether the proposal for the reply key is accepted. + + The specific formats of the proposal message, including where padata + are included is a matter for the mechanism specification. Similarly, + the format of the message accepting the proposal is mechanism- + + + +Hartman & Zhu Expires February 13, 2010 [Page 14] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + specific. + + Mechanisms implementing this facility and including a typed hole for + additional padata MUST checksum that padata using a keyed checksum or + encrypt the padata. This requirement protects against modification + of the contents of the typed hole. By modifying these contents an + attacker might be able to choose which mechanism is used to + authenticate the client, or to convince a party to provide text + encrypted in a key that the attacker had manipulated. It is + important that mechanisms strengthen the reply key enough that using + it to checksum padata is appropriate. + +4.3. Replacing-reply-key Facility + + The Replace Reply Key facility replaces the key in which a successful + AS reply will be encrypted. This facility can only be used in cases + where knowledge of the reply key is not used to authenticate the + client. The new reply key MUST be communicated to the client and the + KDC in a secure manner. This facility MUST NOT be used if there can + be a man-in-the-middle between the client and the KDC. Mechanisms + implementing this facility MUST mark the reply key as replaced in the + pre-authentication state. Mechanisms implementing this facility MUST + either provide a mechanism to verify the KDC reply to the client or + mark the reply as unverified in the pre-authentication state. + Mechanisms implementing this facility SHOULD NOT be used if a + previous mechanism has used the reply key. + + As with the strengthening-reply-key facility, Kerberos extensibility + rules require that the reply key not be changed unless both sides of + the exchange understand the extension. In the case of this facility + it will likely be the case for both sides to know that the facility + is available by the time that the new key is available to be used. + However, mechanism designers can use a container for padata in a + proposal message as discussed in Section 4.2 if appropriate. + +4.4. KDC-authentication Facility + + This facility verifies that the reply comes from the expected KDC. + In traditional Kerberos, the KDC and the client share a key, so if + the KDC reply can be decrypted then the client knows that a trusted + KDC responded. Note that the client machine cannot trust the client + unless the machine is presented with a service ticket for it + (typically the machine can retrieve this ticket by itself). However, + if the reply key is replaced, some mechanism is required to verify + the KDC. Pre-authentication mechanisms providing this facility allow + a client to determine that the expected KDC has responded even after + the reply key is replaced. They mark the pre-authentication state as + having been verified. + + + +Hartman & Zhu Expires February 13, 2010 [Page 15] + +Internet-Draft Kerberos Preauth Framework August 2009 + + +5. Requirements for Pre-Authentication Mechanisms + + This section lists requirements for specifications of pre- + authentication mechanisms. + + For each message in the pre-authentication mechanism, the + specification describes the pa-type value to be used and the contents + of the message. The processing of the message by the sender and + recipient is also specified. This specification needs to include all + modifications to the pre-authentication state. + + Generally mechanisms have a message that can be sent in the error + data of the KDC_ERR_PREAUTH_REQUIRED error message or in an + authentication set. If the client needs information such as trusted + certificate authorities in order to determine if it can use the + mechanism, then this information should be in that message. In + addition, such mechanisms should also define a pa-hint to be included + in authentication sets. Often, the same information included in the + padata-value is appropriate to include in the pa-hint (as defined in + Section 6.4). + + In order to ease security analysis the mechanism specification should + describe what facilities from this document are offered by the + mechanism. For each facility, the security consideration section of + the mechanism specification should show that the security + requirements of that facility are met. This requirement is + applicable to any FAST factor that provides authentication + information. + + Significant problems have resulted in the specification of Kerberos + protocols because much of the KDC exchange is not protected against + alteration. The security considerations section should discuss + unauthenticated plaintext attacks. It should either show that + plaintext is protected or discuss what harm an attacker could do by + modifying the plaintext. It is generally acceptable for an attacker + to be able to cause the protocol negotiation to fail by modifying + plaintext. More significant attacks should be evaluated carefully. + + As discussed in Section 6.3, there is no guarantee that a client will + use the same KDCs for all messages in a conversation. The mechanism + specification needs to show why the mechanism is secure in this + situation. The hardest problem to deal with, especially for + challenge/response mechanisms is to make sure that the same response + cannot be replayed against two KDCs while allowing the client to talk + to any KDC. + + + + + + +Hartman & Zhu Expires February 13, 2010 [Page 16] + +Internet-Draft Kerberos Preauth Framework August 2009 + + +6. Tools for Use in Pre-Authentication Mechanisms + + This section describes common tools needed by multiple pre- + authentication mechanisms. By using these tools mechanism designers + can use a modular approach to specify mechanism details and ease + security analysis. + +6.1. Combining Keys + + Frequently a weak key needs to be combined with a stronger key before + use. For example, passwords are typically limited in size and + insufficiently random, therefore it is desirable to increase the + strength of the keys based on passwords by adding additional secrets. + Additional source of secrecy may come from hardware tokens. + + This section provides standard ways to combine two keys into one. + + KRB-FX-CF1() is defined to combine two pass-phrases. + + KRB-FX-CF1(UTF-8 string, UTF-8 string) -> (UTF-8 string) + KRB-FX-CF1(x, y) := x || y + + Where || denotes concatenation. The strength of the final key is + roughly the total strength of the individual keys being combined + assuming that the string_to_key() function [RFC3961] uses all its + input evenly. + + An example usage of KRB-FX-CF1() is when a device provides random but + short passwords, the password is often combined with a personal + identification number (PIN). The password and the PIN can be + combined using KRB-FX-CF1(). + + KRB-FX-CF2() combines two protocol keys based on the pseudo-random() + function defined in [RFC3961]. + + Given two input keys, K1 and K2, where K1 and K2 can be of two + different enctypes, the output key of KRB-FX-CF2(), K3, is derived as + follows: + + KRB-FX-CF2(protocol key, protocol key, octet string, + octet string) -> (protocol key) + + PRF+(K1, pepper1) -> octet-string-1 + PRF+(K2, pepper2) -> octet-string-2 + KRB-FX-CF2(K1, K2, pepper1, pepper2) := + random-to-key(octet-string-1 ^ octet-string-2) + + Where ^ denotes the exclusive-OR operation. PRF+() is defined as + + + +Hartman & Zhu Expires February 13, 2010 [Page 17] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + follows: + + PRF+(protocol key, octet string) -> (octet string) + + PRF+(key, shared-info) := pseudo-random( key, 1 || shared-info ) || + pseudo-random( key, 2 || shared-info ) || + pseudo-random( key, 3 || shared-info ) || ... + + Here the counter value 1, 2, 3 and so on are encoded as a one-octet + integer. The pseudo-random() operation is specified by the enctype + of the protocol key. PRF+() uses the counter to generate enough bits + as needed by the random-to-key() [RFC3961] function for the + encryption type specified for the resulting key; unneeded bits are + removed from the tail. Unless otherwise specified, the resulting + enctype of KRB-FX-CF2 is the enctype of k1. + + Mechanism designers MUST specify the values for the input parameter + pepper1 and pepper2 when combining two keys using KRB-FX-CF2(). The + pepper1 and pepper2 MUST be distinct so that if the two keys being + combined are the same, the resulting key is not a trivial key. + +6.2. Protecting Requests/Responses + + Mechanism designers SHOULD protect clear text portions of pre- + authentication data. Various denial of service attacks and downgrade + attacks against Kerberos are possible unless plaintexts are somehow + protected against modification. An early design goal of Kerberos + Version 5 [RFC4120] was to avoid encrypting more of the + authentication exchange that was required. (Version 4 doubly- + encrypted the encrypted part of a ticket in a KDC reply, for + example.) This minimization of encryption reduces the load on the + KDC and busy servers. Also, during the initial design of Version 5, + the existence of legal restrictions on the export of cryptography + made it desirable to minimize of the number of uses of encryption in + the protocol. Unfortunately, performing this minimization created + numerous instances of unauthenticated security-relevant plaintext + fields. + + If there is more than one round trip for an authentication exchange, + mechanism designers need to allow either the client or the KDC to + provide a checksum of all the messages exchanged on the wire in the + conversation, and the checksum is then verified by the receiver. + + New mechanisms MUST NOT be hard-wired to use a specific algorithm. + + Primitives defined in [RFC3961] are RECOMMENDED for integrity + protection and confidentiality. Mechanisms based on these primitives + are crypto-agile as the result of using [RFC3961] along with + + + +Hartman & Zhu Expires February 13, 2010 [Page 18] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + [RFC4120]. The advantage afforded by crypto-agility is the ability + to incrementally deploy a fix specific to a particular algorithm thus + avoid a multi-year standardization and deployment cycle, when real + attacks do arise against that algorithm. + + Note that data used by FAST factors (defined in Section 6.5) is + encrypted in a protected channel, thus they do not share the un- + authenticated-text issues with mechanisms designed as full-blown pre- + authentication mechanisms. + +6.3. Managing States for the KDC + + Kerberos KDCs are stateless in that there is no requirement that + clients will choose the same KDC for the second request in a + conversation. Proxies or other intermediate nodes may also influence + KDC selection. So, each request from a client to a KDC must include + sufficient information that the KDC can regenerate any needed state. + This is accomplished by giving the client a potentially long opaque + cookie in responses to include in future requests in the same + conversation. The KDC MAY respond that a conversation is too old and + needs to restart by responding with a KDC_ERR_PREAUTH_EXPIRED error. + + KDC_ERR_PREAUTH_EXPIRED 90 + + When a client receives this error, the client SHOULD abort the + existing conversation, and restart a new one. + + An example, where more than one message from the client is needed, is + when the client is authenticated based on a challenge-response + scheme. In that case, the KDC needs to keep track of the challenge + issued for a client authentication request. + + The PA-FX-COOKIE padata type is defined in this section to facilitate + state management in the AS exchange. This padata is sent by the KDC + when the KDC requires state for a future transaction. The client + includes this opaque token in the next message in the conversation. + The token may be relatively large; clients MUST be prepared for + tokens somewhat larger than the size of all messages in a + conversation. + + PA-FX-COOKIE 133 + -- Stateless cookie that is not tied to a specific KDC. + + The corresponding padata-value field [RFC4120] contains an opaque + token that will be echoed by the client in its response to an error + from the KDC. + + The cookie token is generated by the KDC and transmitted in a PA-FX- + + + +Hartman & Zhu Expires February 13, 2010 [Page 19] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + COOKIE pre-authentication data item of a KRB-ERROR message. The + client MUST copy the exact cookie encapsulated in a PA-FX-COOKIE data + element into the next message of the same conversation. The content + of the cookie field is a local matter of the KDC. As a result, it is + not generally possible to mix KDC implementations from different + vendors in the same realm. However the KDC MUST construct the cookie + token in such a manner that a malicious client cannot subvert the + authentication process by manipulating the token. The KDC + implementation needs to consider expiration of tokens, key rollover + and other security issues in token design. The content of the cookie + field is likely specific to the pre-authentication mechanisms used to + authenticate the client. If a client authentication response can be + replayed to multiple KDCs via the PA-FX-COOKIE mechanism, an + expiration in the cookie is RECOMMENDED to prevent the response being + presented indefinitely. + + If at least one more message for a mechanism or a mechanism set is + expected by the KDC, the KDC returns a + KDC_ERR_MORE_PREAUTH_DATA_REQUIRED error with a PA-FX-COOKIE to + identify the conversation with the client according to Section 3.2. + The cookie is not expected to stay constant for a conversation: the + KDC is expected to generate a new cookie for each message. + + KDC_ERR_MORE_PREAUTH_DATA_REQUIRED 91 + + A client MAY throw away the state associated with a conversation and + begin a new conversation by discarding its state and not including a + cookie in the first message of a conversation. KDCs that comply with + this specification MUST include a cookie in a response when the + client can continue the conversation. In particular, a KDC MUST + include a cookie in a KDC_ERR_PREAUTH_REQUIRED or + KDC_ERR_MORE_PREAUTH_DATA_REQUIRED. KDCs SHOULD include a cookie in + errors containing additional information allowing a client to retry. + One reasonable strategy for meeting these requirements is to always + include a cookie in KDC errors. + + A KDC MAY indicate that it is terminating a conversation by not + including a cookie in a response. When FAST is used, clients can + assume that the absence of a cookie means that the KDC is ending the + conversation. Clients also need to deal with KDCs prior to this + specification that do not include cookies; if cookies nor FAST are + used in a conversation, the absence of a cookie is not a strong + indication that the KDC is terminating the conversation. + +6.4. Pre-authentication Set + + If all mechanisms in a group need to successfully complete in order + to authenticate a client, the client and the KDC SHOULD use the PA- + + + +Hartman & Zhu Expires February 13, 2010 [Page 20] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + AUTHENTICATION-SET padata element. + + PA-AUTHENTICATION-SET 134 + + A PA-AUTHENTICATION-SET padata element contains the ASN.1 DER + encoding of the PA-AUTHENTICATION-SET structure: + + PA-AUTHENTICATION-SET ::= SEQUENCE OF PA-AUTHENTICATION-SET-ELEM + + PA-AUTHENTICATION-SET-ELEM ::= SEQUENCE { + pa-type [0] Int32, + -- same as padata-type. + pa-hint [1] OCTET STRING OPTIONAL, + pa-value [2] OCTET STRING OPTIONAL, + ... + } + + The pa-type field of the PA-AUTHENTICATION-SET-ELEM structure + contains the corresponding value of padata-type in PA-DATA [RFC4120]. + Associated with the pa-type is a pa-hint, which is an octet-string + specified by the pre-authentication mechanism. This hint may provide + information for the client which helps it determine whether the + mechanism can be used. For example a public-key mechanism might + include the certificate authorities it trusts in the hint info. Most + mechanisms today do not specify hint info; if a mechanism does not + specify hint info the KDC MUST NOT send a hint for that mechanism. + To allow future revisions of mechanism specifications to add hint + info, clients MUST ignore hint info received for mechanisms that the + client believes do not support hint info. The pa-value element of + the PA-AUTHENTICATION-SET-ELEM sequence is included to carry the + first padata-value from the KDC to the client. If the client chooses + this authentication set then the client MUST process this pa-value. + The pa-value element MUST be absent for all but the first entry in + the authentication set. Clients MUST ignore pa-value for the second + and following entries in the authentication set. + + If the client chooses an authentication set, then its first AS-REQ + message MUST contain a PA-AUTH-SET-SELECTED padata element. This + element contains the encoding of the PA-AUTHENTICATION-SET sequence + received from the KDC corresponding to the authentication set that is + chosen. The client MUST use the same octet values received from the + KDC; it cannot re-encode the sequence. This allows KDCs to use bit- + wise comparison to identify the selected authentication set. The PA- + AUTH-SET-SELECTED padata element MUST come before any padata elements + from the authentication set in the padata sequence in the AS-REQ + message. The client MAY cache authentication sets from prior + messages and use them to construct an optimistic initial AS-REQ. If + the KDC receives a PA-AUTH-SET-SELECTED padata element that does not + + + +Hartman & Zhu Expires February 13, 2010 [Page 21] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + correspond to an authentication set that it would offer, then the KDC + returns the KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET error. The e-data + in this error contains a sequence of padata just as for the + KDC_ERR_PREAUTH_REQUIRED error. + + + PA-AUTH-SET-SELECTED 135 + KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET 92 + + The PA-AUTHENTICATION-SET appears only in the first message from the + KDC to the client. In particular, the client MAY fail if the + authentication mechanism sets change as the conversation progresses. + Clients MAY assume that the hints provided in the authentication set + contain enough information that the client knows what user interface + elements need to be displayed during the entire authentication + conversation. Exceptional circumstances such as expired passwords or + expired accounts may require that additional user interface be + displayed. Mechanism designers needs to carefully consider the + design of their hints so that the client has this information. This + way, clients can construct necessary dialogue boxes or wizards based + on the authentication set and can present a coherent user interface. + Current standards for user interface do not provide an acceptable + experience when the client has to ask additional questions later in + the conversation. + + When indicating which sets of pre-authentication mechanisms are + supported, the KDC includes a PA-AUTHENTICATION-SET padata element + for each pre-authentication mechanism set. + + The client sends the padata-value for the first mechanism it picks in + the pre-authentication set, when the first mechanism completes, the + client and the KDC will proceed with the second mechanism, and so on + until all mechanisms complete successfully. The PA-FX-COOKIE as + defined in Section 6.3 MUST be sent by the KDC. One reason for this + requirement is so that the conversation can continue if the + conversation involves multiple KDCs. KDCs MUST support clients that + do not include a cookie because they optimistically choose an + authentication set, although they MAY always return + KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET and include a cookie in that + message. Clients that support PA-AUTHENTICATION-SET MUST support PA- + FX-COOKIE. + + Before the authentication succeeds and a ticket is returned, the + message that the client sends is an AS_REQ and the message that the + KDC sends is a KRB-ERROR message. The error code in the KRB-ERROR + message from the KDC is KDC_ERR_MORE_PREAUTH_DATA_REQUIRED as defined + in Section 6.3 and the accompanying e-data contains the DER encoding + of ASN.1 type METHOD-DATA. The KDC includes the padata elements in + + + +Hartman & Zhu Expires February 13, 2010 [Page 22] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + the METHOD-DATA. If there is no padata, the e-data field is absent + in the KRB-ERROR message. + + If the client sends the last message for a given mechanism, then the + KDC sends the first message for the next mechanism. If the next + mechanism does not start with a KDC-side challenge, then the KDC + includes a padata item with the appropriate pa-type and an empty pa- + data. + + If the KDC sends the last message for a particular mechanism, the KDC + also includes the first padata for the next mechanism. + +6.5. Definition of Kerberos FAST Padata + + As described in [RFC4120], Kerberos is vulnerable to offline + dictionary attacks. An attacker can request an AS-REP and try + various passwords to see if they can decrypt the resulting ticket. + RFC 4120 provides the encrypted timestamp pre-authentication method + that ameliorates the situation somewhat by requiring that an attacker + observe a successful authentication. However stronger security is + desired in many environments. The Kerberos FAST pre-authentication + padata defined in this section provides a tool to significantly + reduce vulnerability to offline dictionary attack. When combined + with encrypted challenge, FAST requires an attacker to mount a + successful man-in-the-middle attack to observe ciphertext. When + combined with host keys, FAST can even protect against active + attacks. FAST also provides solutions to common problems for pre- + authentication mechanisms such as binding of the request and the + reply, freshness guarantee of the authentication. FAST itself, + however, does not authenticate the client or the KDC, instead, it + provides a typed hole to allow pre-authentication data be tunneled. + A pre-authentication data element used within FAST is called a FAST + factor. A FAST factor captures the minimal work required for + extending Kerberos to support a new pre-authentication scheme. + + A FAST factor MUST NOT be used outside of FAST unless its + specification explicitly allows so. The typed holes in FAST messages + can also be used as generic holes for other padata that are not + intended to prove the client's identity, or establish the reply key. + + New pre-authentication mechanisms SHOULD be designed as FAST factors, + instead of full-blown pre-authentication mechanisms. + + FAST factors that are pre-authentication mechanisms MUST meet the + requirements in Section 5. + + FAST employs an armoring scheme. The armor can be a Ticket Granting + Ticket (TGT) obtained by the client's machine using the host keys to + + + +Hartman & Zhu Expires February 13, 2010 [Page 23] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + pre-authenticate with the KDC, or an anonymous TGT obtained based on + anonymous PKINIT [KRB-ANON] [RFC4556]. + + The rest of this section describes the types of armors and the syntax + of the messages used by FAST. Conforming implementations MUST + support Kerberos FAST padata. + + Any FAST armor scheme MUST provide a fresh armor key for each + conversation. Clients and KDCs can assume that if a message is + encrypted and integrity protected with a given armor key then it is + part of the conversation using that armor key. + + All KDCs in a realm MUST support FAST if FAST is offered by any KDC + as a pre-authentication mechanism. + +6.5.1. FAST Armors + + An armor key is used to encrypt pre-authentication data in the FAST + request and the response. The KrbFastArmor structure is defined to + identify the armor key. This structure contains the following two + fields: the armor-type identifies the type of armors, and the armor- + value is an OCTET STRING that contains the description of the armor + scheme and the armor key. + + KrbFastArmor ::= SEQUENCE { + armor-type [0] Int32, + -- Type of the armor. + armor-value [1] OCTET STRING, + -- Value of the armor. + ... + } + + The value of the armor key is a matter of the armor type + specification. Only one armor type is defined in this document. + + FX_FAST_ARMOR_AP_REQUEST 1 + + The FX_FAST_ARMOR_AP_REQUEST armor is based on Kerberos tickets. + + Conforming implementations MUST implement the + FX_FAST_ARMOR_AP_REQUEST armor type. If a FAST KDC receives an + unknown armor type it MUST respond with KDC_ERR_PREAUTH_FAILED. + + An armor type may be appropriate for use in armoring AS requests, + armoring TGS requests or both. TGS armor types MUST authenticate the + client to to the KDC, typically by binding the TGT subsession key to + the armor key. As discussed below, it is desirable for AS armor + types to authenticate the KDC to the client, but this is not + + + +Hartman & Zhu Expires February 13, 2010 [Page 24] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + required. + + FAST implementations MUST maintain state about whether the armor + mechanism authenticates the KDC. If it does not, then a fast factor + that authenticates the KDC MUST be used if the reply key is replaced. + +6.5.1.1. Ticket-based Armors + + This is a ticket-based armoring scheme. The armor-type is + FX_FAST_ARMOR_AP_REQUEST, the armor-value contains an ASN.1 DER + encoded AP-REQ. The ticket in the AP-REQ is called an armor ticket + or an armor TGT. The subkey field in the AP-REQ MUST be present. + The armor key is defined by the following function: + + armor_key = KRB-FX-CF2( subkey, ticket_session_key, + "subkeyarmor", "ticketarmor" ) + + The `ticket_session_key' is the session key from the ticket in the + ap-req. The `subkey' is the ap-req subkey. This construction + guarantees that both the KDC (through the session key) and the client + (through the subkey) contribute to the armor key. + + The server name field of the armor ticket MUST identify the TGS of + the target realm. Here are three common ways in the decreasing + preference order how an armor TGT SHOULD be obtained: + + 1. If the client is authenticating from a host machine whose + Kerberos realm has an authentication path to the client's realm, + the host machine obtains a TGT by using the host keys. If the + client's realm is different than the realm of the local host, the + machine then obtains a cross-realm TGT to the client's realm as + the armor ticket. Otherwise, the host's primary TGT is the armor + ticket. + + 2. If the client's host machine cannot obtain a host ticket strictly + based on RFC4120, but the KDC has an asymmetric signing key whose + binding with the expected KDC can be verified by the client, the + client can use anonymous PKINIT [KRB-ANON] [RFC4556] to + authenticate the KDC and obtain an anonymous TGT as the armor + ticket. The armor ticket can also be a cross-realm TGT obtained + based on the initial primary TGT obtained using anonymous PKINIT + with KDC authentication. + + 3. Otherwise, the client uses anonymous PKINIT to get an anonymous + TGT without KDC authentication and that TGT is the armor ticket. + Note that this mode of operation is vulnerable to man-in-the- + middle attacks at the time of obtaining the initial anonymous + armor TGT. + + + +Hartman & Zhu Expires February 13, 2010 [Page 25] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + If anonymous PKINIT is used to obtain the armor ticket, the KDC + cannot know whether its signing key can be verified by the client, + hence the KDC MUST be marked as unverified from the KDC's point of + view while the client could be able to authenticate the KDC by + verifying the KDC's signing key is bound with the expected KDC. The + client needs to carefully consider the risk and benefit tradeoffs + associated with active attacks before exposing cipher text encrypted + using the user's long-term secrets when the armor does not + authenticate the KDC. + + The TGS MUST reject a request if there is an AD-fx-fast-armor (TBD) + element in the authenticator of the pa-tgs-req padata or if the + ticket in the authenticator of a pa-tgs-req contains the AD-fx-fast- + armor authorization data element. These tickets and authenticators + MAY be used as FAST armor tickets but not to obtain a ticket via the + TGS. This authorization data is used in a system where the + encryption of the user's pre-authentication data is performed in an + unprivileged user process. A privileged process can provide to the + user process a host ticket, an authenticator for use with that + ticket, and the sub session key contained in the authenticator. In + order for the host process to ensure that the host ticket is not + accidentally or intentionally misused, (i.e. the user process might + use the host ticket to authenticate as the host), it MUST include a + critical authorization data element of the type AD-fx-fast-armor when + providing the authenticator or in the enc-authorization-data field of + the TGS request used to obtain the TGT. The corresponding ad-data + field of the AD-fx-fast-armor element is empty. + + Only implicit armors are allowed in the TGS at this time. + +6.5.2. FAST Request + + A padata type PA-FX-FAST is defined for the Kerberos FAST pre- + authentication padata. The corresponding padata-value field + [RFC4120] contains the DER encoding of the ASN.1 type PA-FX-FAST- + REQUEST. As with all pre-authentication types, the KDC SHOULD + advertise PA-FX-FAST in a PREAUTH_REQUIRED error. KDCs MUST send the + advertisement of pa-fx-fast with an empty pa-value. Clients MUST + ignore the pa-value of PA-FX-FAST in an initial PREAUTH_REQUIRED + error. FAST is not expected to be used in an authentication set: + clients will typically use FAST padata if available and this decision + should not depend on what other pre-authentication methods are + available. As such, no pa-hint is defined for FAST at this time. + + + + + + + + +Hartman & Zhu Expires February 13, 2010 [Page 26] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + PA-FX-FAST 136 + -- Padata type for Kerberos FAST + + PA-FX-FAST-REQUEST ::= CHOICE { + armored-data [0] KrbFastArmoredReq, + ... + } + + KrbFastArmoredReq ::= SEQUENCE { + armor [0] KrbFastArmor OPTIONAL, + -- Contains the armor that identifies the armor key. + -- MUST be present in AS-REQ. + req-checksum [1] Checksum, + -- For AS, contains the checksum performed over the type + -- KDC-REQ-BODY for the req-body field of the KDC-REQ + -- structure; + -- For TGS, contains the checksum performed over the type + -- AP-REQ in the PA-TGS-REQ padata. + -- The checksum key is the armor key, the checksum + -- type is the required checksum type for the enctype of + -- the armor key, and the key usage number is + -- KEY_USAGE_FAST_REQ_CHKSUM. + enc-fast-req [2] EncryptedData, -- KrbFastReq -- + -- The encryption key is the armor key, and the key usage + -- number is KEY_USAGE_FAST_ENC. + ... + } + + KEY_USAGE_FAST_REQ_CHKSUM 50 + KEY_USAGE_FAST_ENC 51 + + The PA-FX-FAST-REQUEST structure contains a KrbFastArmoredReq type. + The KrbFastArmoredReq encapsulates the encrypted padata. + + The enc-fast-req field contains an encrypted KrbFastReq structure. + The armor key is used to encrypt the KrbFastReq structure, and the + key usage number for that encryption is KEY_USAGE_FAST_ENC. + + The armor key is selected as follows: + + o In an AS request, the armor field in the KrbFastArmoredReq + structure MUST be present and the armor key is identified + according to the specification of the armor type. + + o There are two possibilities for armor for a TGS request. If the + ticket presented in the PA-TGS-REQ authenticator is a TGT, then + the client SHOULD NOT include the armor field in the Krbfastreq + and a subkey MUST be included in the PA-TGS-REQ authenticator. In + + + +Hartman & Zhu Expires February 13, 2010 [Page 27] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + this case, the armor key is the same armor key that would be + computed if the TGS-REQ authenticator was used in a + FX_FAST_ARMOR_AP_REQUEST armor. Clients MAY present a non-TGT in + the PA-TGS-REQ authenticator and omit the armor field, in which + case the armor key is the same that would be computed if the + authenticator were used in a FX_FAST_ARMOR_AP_REQUEST armor. This + is the only case where a ticket other than a TGT can be used to + establish an armor key; even though the armor key is computed the + same as a FX_FAST_ARMOR_AP_REQUEST, a non-TGT cannot be used as an + armor ticket in FX_FAST_ARMOR_AP_REQUEST. Alternatively, a client + MAY use an armor type defined in the future for use with the TGS + request. + + The req-checksum field contains a checksum computed differently for + AS and TGS. For an AS-REQ, it is performed over the type KDC-REQ- + BODY for the req-body field of the KDC-REQ structure of the + containing message; for an TGS-REQ, it is performed over the type AP- + REQ in the PA-TGS-REQ padata of the TGS request. The checksum key is + the armor key, and the checksum type is the required checksum type + for the enctype of the armor key per [RFC3961]. This checksum MUST + be a keyed checksume and it is included in order to bind the FAST + padata to the outer request. A KDC that implements FAST will ignore + the outer request, but including a checksum is relatively cheap and + may prevent confusing behavior. + + The KrbFastReq structure contains the following information: + + KrbFastReq ::= SEQUENCE { + fast-options [0] FastOptions, + -- Additional options. + padata [1] SEQUENCE OF PA-DATA, + -- padata typed holes. + req-body [2] KDC-REQ-BODY, + -- Contains the KDC request body as defined in Section + -- 5.4.1 of [RFC4120]. + -- This req-body field is preferred over the outer field + -- in the KDC request. + ... + } + + The fast-options field indicates various options that are to modify + the behavior of the KDC. The following options are defined: + + FastOptions ::= KerberosFlags + -- reserved(0), + -- hide-client-names(1), + -- kdc-follow-referrals(16) + + + + +Hartman & Zhu Expires February 13, 2010 [Page 28] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + Bits Name Description + ----------------------------------------------------------------- + 0 RESERVED Reserved for future expansion of this + field. + 1 hide-client-names Requesting the KDC to hide client + names in the KDC response, as + described next in this section. + 16 kdc-follow-referrals Requesting the KDC to follow referrals. + + Bits 1 through 15 inclusive (with bit 1 and bit 15 included) are + critical options. If the KDC does not support a critical option, it + MUST fail the request with KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS, and + there is no accompanying e-data defined in this document for this + error code. Bit 16 and onward (with bit 16 included) are non- + critical options. KDCs conforming to this specification ignore + unknown non-critical options. + + KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS 93 + + The hide-client-names Option + + The Kerberos response defined in [RFC4120] contains the client + identity in clear text, This makes traffic analysis + straightforward. The hide-client-names option is designed to + complicate traffic analysis. If the hide-client-names option is + set, the KDC implementing PA-FX-FAST MUST identify the client as + the anonymous principal [KRB-ANON] in the KDC reply and the error + response. Hence this option is set by the client if it wishes to + conceal the client identity in the KDC response. A conforming KDC + ignores the client principal name in the outer KDC-REQ-BODY field, + and identifies the client using the cname and crealm fields in the + req-body field of the KrbFastReq structure. + + The kdc-follow-referrals Option + + The Kerberos client described in [RFC4120] has to request referral + TGTs along the authentication path in order to get a service + ticket for the target service. The Kerberos client described in + the [REFERRALS] needs to contact the AS specified in the error + response in order to complete client referrals. The kdc-follow- + referrals option is designed to minimize the number of messages + that need to be processed by the client. This option is useful + when, for example, the client may contact the KDC via a satellite + link that has high network latency, or the client has limited + computational capabilities. If the kdc-follow-referrals option is + set, the KDC MAY act as the client to follow TGS referrals + [REFERRALS], and return the service ticket to the named server + principal in the client request using the reply key expected by + + + +Hartman & Zhu Expires February 13, 2010 [Page 29] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + the client. That is, rather than returning a referral, the KDC + follows that referral by contacting a remote KDC and processing + the referral. The kdc-referrals option can be implemented when + the KDC knows the reply key. The KDC can ignore kdc-referrals + option when it does not understand it or it does not allow this + option based on local policy. The client SHOULD be capable of + processing the KDC responses when this option is not honored by + the KDC. Clients SHOULD use TCP to contact a KDC if this option + is going to be used to avoid problems when the client's UDP + retransmit algorithm has timeouts insufficient to allow the KDC to + interact with remote KDCs. + + The padata field contains a list of PA-DATA structures as described + in Section 5.2.7 of [RFC4120]. These PA-DATA structures can contain + FAST factors. They can also be used as generic typed-holes to + contain data not intended for proving the client's identity or + establishing a reply key, but for protocol extensibility. If the KDC + supports the PA-FX-FAST-REQUEST padata, unless otherwise specified, + the client MUST place any padata that is otherwise in the outer KDC + request body into this field. In a TGS request, PA-TGS-REQ padata is + not included in this field and it is present in the outer KDC request + body. + + The KDC-REQ-BODY in the FAST structure is used in preference to the + KDC-REQ-BODY outside of the FAST pre-authentication. The outer KDC- + REQ-BODY structure SHOULD be filled in for backwards compatibility + with KDCs that do not support FAST. A conforming KDC ignores the + outer KDC-REQ-BODY field in the KDC request. Pre-authentication data + methods such as [RFC4556] that include a checksum of the KDC-REQ-BODY + should checksum the KDC-REQ-BODY in the FAST structure. + + In a TGS request, a client MAY include the AD-fx-fast-used authdata + either in the pa-tgs-req authenticator or in the authorization data + in the pa-tgs-req ticket. If the KDC receives this authorization + data but does not find a FAST padata then it MUST return + KRB_APP_ERR_MODIFIED. + +6.5.3. FAST Response + + The KDC that supports the PA-FX-FAST padata MUST include a PA-FX-FAST + padata element in the KDC reply. In the case of an error, the PA-FX- + FAST padata is included in the KDC responses according to + Section 6.5.4. + + The corresponding padata-value field [RFC4120] for the PA-FX-FAST in + the KDC response contains the DER encoding of the ASN.1 type PA-FX- + FAST-REPLY. + + + + +Hartman & Zhu Expires February 13, 2010 [Page 30] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + PA-FX-FAST-REPLY ::= CHOICE { + armored-data [0] KrbFastArmoredRep, + ... + } + + KrbFastArmoredRep ::= SEQUENCE { + enc-fast-rep [0] EncryptedData, -- KrbFastResponse -- + -- The encryption key is the armor key in the request, and + -- the key usage number is KEY_USAGE_FAST_REP. + ... + } + KEY_USAGE_FAST_REP 52 + + The PA-FX-FAST-REPLY structure contains a KrbFastArmoredRep + structure. The KrbFastArmoredRep structure encapsulates the padata + in the KDC reply in the encrypted form. The KrbFastResponse is + encrypted with the armor key used in the corresponding request, and + the key usage number is KEY_USAGE_FAST_REP. + + The Kerberos client who does not receive a PA-FX-FAST-REPLY in the + KDC response MUST support a local policy that rejects the response. + Clients MAY also support policies that fall back to other mechanisms + or that do not use pre-authentication when FAST is unavailable. It + is important to consider the potential downgrade attacks when + deploying such a policy. + + The KrbFastResponse structure contains the following information: + + KrbFastResponse ::= SEQUENCE { + padata [0] SEQUENCE OF PA-DATA, + -- padata typed holes. + strengthen-key [1] EncryptionKey OPTIONAL, + -- This, if present, strengthens the reply key for AS and + -- TGS. MUST be present for TGS. + -- MUST be absent in KRB-ERROR. + finished [2] KrbFastFinished OPTIONAL, + -- Present in AS or TGS reply; absent otherwise. + nonce [3] UInt32, + -- Nonce from the client request. + ... + } + + The padata field in the KrbFastResponse structure contains a list of + PA-DATA structures as described in Section 5.2.7 of [RFC4120]. These + PA-DATA structures are used to carry data advancing the exchange + specific for the FAST factors. They can also be used as generic + typed-holes for protocol extensibility. Unless otherwise specified, + the KDC MUST include any padata that is otherwise in the outer KDC- + + + +Hartman & Zhu Expires February 13, 2010 [Page 31] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + REP structure into this field. The padata field in the KDC reply + structure outside of the PA-FX-FAST-REPLY structure typically + includes only the PA-FX- FAST-REPLY padata. + + The strengthen-key field provides a mechanism for the KDC to + strengthen the reply key. If set, the reply key is strengthened + after all padata items are processed. Let padata-reply-key be the + reply key after padata processing. + + reply-key = KRB-FX-CF2(strengthen-key, padata-reply-key, + "strengthenkey", "replykey") + + The strengthen-key field MAY be set in an AS reply; it MUST be set in + a TGS reply; it must be absent in an error reply. The strengthen key + is required in a TGS reply so that an attacker cannot remove the FAST + PADATA from a TGS reply, causing the KDC to appear not to support + FAST. + + The finished field contains a KrbFastFinished structure. It is + filled by the KDC in the final message in the conversation. This + field is present in an AS-REP or a TGS-REP when a ticket is returned, + and it is not present in an error reply. + + The KrbFastFinished structure contains the following information: + + KrbFastFinished ::= SEQUENCE { + timestamp [0] KerberosTime, + usec [1] Microseconds, + -- timestamp and usec represent the time on the KDC when + -- the reply was generated. + crealm [2] Realm, + cname [3] PrincipalName, + -- Contains the client realm and the client name. + ticket-checksum [4] Checksum, + -- checksum of the ticket in the KDC-REP using the armor + -- and the key usage is KEY_USAGE_FAST_FINISH. + -- The checksum type is the required checksum type + -- of the armor key. + ... + } + KEY_USAGE_FAST_FINISHED 53 + + The timestamp and usec fields represent the time on the KDC when the + reply ticket was generated, these fields have the same semantics as + the corresponding-identically-named fields in Section 5.6.1 of + [RFC4120]. The client MUST use the KDC's time in these fields + thereafter when using the returned ticket. Note that the KDC's time + in AS-REP may not match the authtime in the reply ticket if the kdc- + + + +Hartman & Zhu Expires February 13, 2010 [Page 32] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + follow-referrals option is requested and honored by the KDC. The + client need not confirm that the timestamp returned is within + allowable clock skew: the armor key guarantees that the reply is + fresh. The client MAY trust the time stamp returned. + + The cname and crealm fields identify the authenticated client. If + facilities described in [REFERRALS] are used, the authenticated + client may differ from the client in the FAST request. + + The ticket-checksum is a checksum of the issued ticket. The checksum + key is the armor key, and the checksum type is the required checksum + type of the enctype of that key, and the key usage number is + KEY_USAGE_FAST_FINISHED. + + When FAST padata is included, the PA-FX-COOKIE padata as defined in + Section 6.3 MUST be included in the padata sequence in the + KrbFastResponse sequence if the KDC expects at least one more message + from the client in order to complete the authentication. + + The nonce field in the KrbFastResponse contains the value of the + nonce field in the KDC-REQ of the corresponding client request and it + binds the KDC response with the client request. The client MUST + verify that this nonce value in the reply matches with that of the + request and reject the KDC reply otherwise. To prevent the response + from one message in a conversation from being replayed to a request + in another message, clients SHOULD use a new nonce for each message + in a conversation. + +6.5.4. Authenticated Kerberos Error Messages using Kerberos FAST + + If the Kerberos FAST padata was included in the request, unless + otherwise specified, the e-data field of the KRB-ERROR message + [RFC4120] contains the ASN.1 DER encoding of the type METHOD-DATA + [RFC4120] and a PA-FX-FAST is included in the METHOD-DATA. The KDC + MUST include all the padata elements such as PA-ETYPE-INFO2 and + padata elements that indicate acceptable pre-authentication + mechanisms [RFC4120] in the KrbFastResponse structure. + + The KDC MUST also include a PA-FX-ERROR padata item in the + KRBFastResponse structure. The padata-value element of this sequence + is the ASN.1 DER encoding of the type KRB-ERROR. The e-data field + MUST be absent in the PA-FX-ERROR padata. All other fields should be + the same as the outer KRB-ERROR. The client ignores the outer error + and uses the combination of the padata in the KRBFastResponse and the + error information in the PA-FX-ERROR. + + PA-FX-ERROR 137 + + + + +Hartman & Zhu Expires February 13, 2010 [Page 33] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + If the Kerberos FAST padata is included in the request but not + included in the error reply, it is a matter of the local policy on + the client to accept the information in the error message without + integrity protection. The client SHOULD however process the KDC + errors as the result of the KDC's inability to accept the AP_REQ + armor and potentially retry another request with a different armor + when applicable. The Kerberos client MAY process an error message + without a PA-FX-FAST-REPLY, if that is only intended to return better + error information to the application, typically for trouble-shooting + purposes. + + In the cases where the e-data field of the KRB-ERROR message is + expected to carry a TYPED-DATA [RFC4120] element, then that + information should be transmitted in a pa-data element within the + KRBFastResponse structure. The padata-type is the same as the data- + type would be in the typed data element and the padata-value is the + same as the data-value. As discussed in Section 8, data-types and + padata-types are drawn from the same namespace. For example, the + TD_TRUSTED_CERTIFIERS structure is expected to be in the KRB-ERROR + message when the error code is KDC_ERR_CANT_VERIFY_CERTIFICATE + [RFC4556]. + +6.5.5. Outer and Inner Requests + + Typically, a client will know that FAST is being used before a + request containing PA-FX-FAST is sent. So, the outer AS request + typically only includes one pa-data item: PA-FX-FAST. The client MAY + include additional pa-data, but the KDC MUST ignore the outer request + body and any padata besides PA-FX-FAST if and only if PA-FX-FAST is + processed. In the case of the TGS request, the outer request should + include PA-FX-FAST and PA-TGS-REQ. + + When an AS generates a response, all padata besides PA-FX-FAST should + be included in PA-FX-FAST. The client MUST ignore other padata + outside of PA-FX-FAST. + +6.5.6. The Encrypted Challenge FAST Factor + + The encrypted challenge FAST factor authenticates a client using the + client's long-term key. This factor works similarly to the encrypted + time stamp pre-authentication option described in [RFC4120]. The + word challenge is used instead of timestamp because while the + timestamp is used as an initial challenge, if the KDC and client do + not have synchronized time, then the KDC can provide updated time to + the client to use as a challenge. The client encrypts a structure + containing a timestamp in the challenge key. The challenge key used + by the client to send a message to the KDC is KRB-FX- + CF2(armor_key,long_term_key, "clientchallengearmor", + + + +Hartman & Zhu Expires February 13, 2010 [Page 34] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + "challengelongterm"). The challenge key used by the KDC encrypting + to the client is KRB-FX-CF2(armor_key, long_term_key, + "kdcchallengearmor", "challengelongterm"). Because the armor key is + fresh and random, the challenge key is fresh and random. The only + purpose of the timestamp is to limit the validity of the + authentication so that a request cannot be replayed. A client MAY + base the timestamp on the KDC time in a KDC error and need not + maintain accurate time synchronization itself. If a client bases its + time on an untrusted source, an attacker may trick the client into + producing an authentication request that is valid at some future + time. The attacker may be able to use this authentication request to + make it appear that a client has authenticated at that future time. + If ticket-based armor is used, then the lifetime of the ticket will + limit the window in which an attacker can make the client appear to + have authenticated. For many situations, the ability of an attacker + to cause a client to appear to have authenticated is not a + significant concern; the ability to avoid requiring time + synchronization on clients is more valuable. + + The client sends a padata of type PA-ENCRYPTED-CHALLENGE. The + corresponding padata-value contains the DER encoding of ASN.1 type + EncryptedChallenge. + + EncryptedChallenge ::= EncryptedData + -- Encrypted PA-ENC-TS-ENC, encrypted in the challenge key + -- using key usage KEY_USAGE_ENC_CHALLENGE_CLIENT for the + -- client and KEY_USAGE_ENC_CHALLENGE_KDC for the KDC. + + PA-ENCRYPTED-CHALLENGE 138 + KEY_USAGE_ENC_CHALLENGE_CLIENT 54 + KEY_USAGE_ENC_CHALLENGE_KDC 55 + + The client includes some time stamp reasonably close to the KDC's + current time and encrypts it in the challenge key. Clients MAY use + the current time; doing so prevents the exposure where an attacker + can cause a client to appear to authenticate in the future. The + client sends the request including this factor. + + On receiving an AS-REQ containing the PA-ENCRYPTED-CHALLENGE fast + factor, the KDC decrypts the timestamp. If the decryption fails the + KDC SHOULD return KDC_ERR_PREAUTH_FAILED, including PA-ETYPE-INFO2 in + the KRBFastResponse in the error. The KDC confirms that the + timestamp falls within its current clock skew returning + KRB_APP_ERR_SKEW if not. The KDC then SHOULD check to see if the + encrypted challenge is a replay. The KDC MUST NOT consider two + encrypted challenges replays simply because the time stamps are the + same; to be a replay, the ciphertext MUST be identical. Allowing + clients to re-use time stamps avoids requiring that clients maintain + + + +Hartman & Zhu Expires February 13, 2010 [Page 35] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + state about which time stamps have been used. + + If the KDC accepts the encrypted challenge, it MUST include a padata + element of type PA-ENCRYPTED-CHALLENGE. The KDC encrypts its current + time in the challenge key. The KDC MUST strengthen the reply key + before issuing a ticket. The client MUST check that the timestamp + decrypts properly. The client MAY check that the timestamp is within + the window of acceptable clock skew for the client. The client MUST + NOT require that the timestamp be identical to the timestamp in the + issued credentials or the returned message. + + The encrypted challenge FAST factor provides the following + facilities: client-authentication and KDC authentication. This FAST + factor also takes advantage of the FAST facility to strengthen the + reply key. It does not provide the replacing-reply-key facility. + The security considerations section of this document provides an + explanation why the security requirements are met. + + The encrypted challenge FAST factor can be useful in an + authentication set. No pa-hint is defined because the only + information needed by this mechanism is information contained in the + PA-ETYPE-INFO2 pre-authentication data. KDCs are already required to + send PA-ETYPE-INFO2. If KDCs were not required to send PA-ETYPE- + INFO2 then that information would need to be part of a hint for + encrypted challenge. + + Conforming implementations MUST support the encrypted challenge FAST + factor. + +6.6. Authentication Strength Indication + + Implementations that have pre-authentication mechanisms offering + significantly different strengths of client authentication MAY choose + to keep track of the strength of the authentication used as an input + into policy decisions. For example, some principals might require + strong pre-authentication, while less sensitive principals can use + relatively weak forms of pre-authentication like encrypted timestamp. + + An AuthorizationData data type AD-Authentication-Strength is defined + for this purpose. + + AD-authentication-strength 70 + + The corresponding ad-data field contains the DER encoding of the pre- + authentication data set as defined in Section 6.4. This set contains + all the pre-authentication mechanisms that were used to authenticate + the client. If only one pre-authentication mechanism was used to + authenticate the client, the pre-authentication set contains one + + + +Hartman & Zhu Expires February 13, 2010 [Page 36] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + element. + + The AD-authentication-strength element MUST be included in the AD-IF- + RELEVANT, thus it can be ignored if it is unknown to the receiver. + + +7. Assigned Constants + + The pre-authentication framework and FAST involve using a number of + Kerberos protocol constants. This section lists protocol constants + first introduced in this specification drawn from registries not + managed by IANA. Many of these registries would best be managed by + IANA; that is a known issue that is out of scope for this document. + The constants described in this section have been accounted for and + will appear in the next revision of the Kerberos core specification + or in a document creating IANA registries. + + Section 8 creates IANA registries for a different set of constants + used by the extensions described in this document. + +7.1. New Errors + + KDC_ERR_PREAUTH_EXPIRED 90 + KDC_ERR_MORE_PREAUTH_DATA_REQUIRED 91 + KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET 92 + KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS 93 + +7.2. Key Usage Numbers + + KEY_USAGE_FAST_REQ_CHKSUM 50 + KEY_USAGE_FAST_ENC 51 + KEY_USAGE_FAST_REP 52 + KEY_USAGE_FAST_FINISHED 53 + KEY_USAGE_ENC_CHALLENGE_CLIENT 54 + KEY_USAGE_ENC_CHALLENGE_KDC 55 + +7.3. Authorization Data Elements + + AD-authentication-strength 70 + AD-fx-fast-armor 71 + AD-fx-fast-used 72 + + + + + + + + + + +Hartman & Zhu Expires February 13, 2010 [Page 37] + +Internet-Draft Kerberos Preauth Framework August 2009 + + +7.4. New PA-DATA Types + + PA-FX-COOKIE 133 + PA-AUTHENTICATION-SET 134 + PA-AUTH-SET-SELECTED 135 + PA-FX-FAST 136 + PA-FX-ERROR 137 + PA-ENCRYPTED-CHALLENGE 138 + + +8. IANA Considerations + + This document creates a number of IANA registries. These registries + should all be located under + http://www.iana.org/assignments/kerberos-parameters. + +8.1. Pre-authentication and Typed Data + + RFC 4120 defines pre-authentication data, which can be included in a + KDC request or response in order to authenticate the client or extend + the protocol. In addition, it defines Typed-Data which is an + extension mechanism for errors. Both pre-authentication data and + typed data are carried as a 32-bit signed integer along with an octet + string. The encoding of typed data and pre-authentication data is + slightly different. However the types for pre-authentication data + and typed-data are drawn from the same namespace. By convention, + registrations starting with TD- are typed data and registration + starting with PA- are pre-authentication data. It is important that + these data types be drawn from the same namespace, because some + errors where it would be desirable to include typed data require the + e-data field to be formatted as pre-authentication data. + + When Kerberos FAST is used, pre-authentication data encoding is + always used. + + There is one apparently conflicting registration between typed data + and pre-authentication data. PA-GET-FROM-TYPED-DATA and TD-PADATA + are both assigned the value 22. However this registration is simply + a mechanism to include an element of the other encoding. The use of + both should be deprecated. + + This document creates a registry for pre-authentication and typed + data. The registration procedures are as follows. Expert review for + pre-authentication mechanisms designed to authenticate users, KDCs, + or establish the reply key. The expert first determines that the + purpose of the method is to authenticate clients, KDCs, or to + establish the reply key. If so, expert review is appropriate. The + expert evaluates the security and interoperability of the + + + +Hartman & Zhu Expires February 13, 2010 [Page 38] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + specification. + + IETF review is required if the expert believes that the pre- + authentication method is broader than these three areas. Pre- + authentication methods that change the Kerberos state machine or + otherwise make significant changes to the Kerberos protocol should be + standards track RFCs. A concern that a particular method needs to be + a standards track RFC may be raised as an objection during IETF + review. + + Type Value Reference + ---------------------------------------------------------------------- + PA-TGS-REQ 1 RFC 4120 + PA-ENC-TIMESTAMP 2 RFC 4120 + PA-PW-SALT 3 RFC 4120 + [reserved] 4 + PA-ENC-UNIX-TIME 5 (deprecated) + PA-SANDIA-SECUREID 6 + PA-SESAME 7 + PA-OSF-DCE 8 + PA-CYBERSAFE-SECUREID 9 + PA-AFS3-SALT 10 + PA-ETYPE-INFO 11 RFC 4120 + PA-SAM-CHALLENGE 12 (sam/otp) + PA-SAM-RESPONSE 13 (sam/otp) + PA-PK-AS-REQ_OLD 14 draft-ietf-cat-kerberos-pk-init-09 + PA-PK-AS-REP_OLD 15 draft-ietf-cat-kerberos-pk-init-09 + PA-PK-AS-REQ 16 RFC 4556 + PA-PK-AS-REP 17 RFC 4556 + PA-PK-OCSP-RESPONSE 18 RFC 4557 + PA-ETYPE-INFO2 19 RFC 4120 + PA-USE-SPECIFIED-KVNO 20 + PA-SVR-REFERRAL-INFO 20 (referrals) + PA-SAM-REDIRECT 21 (sam/otp) + PA-GET-FROM-TYPED-DATA 22 (embedded in typed data) + TD-PADATA 22 (embeds padata) + PA-SAM-ETYPE-INFO 23 (sam/otp) + PA-ALT-PRINC 24 (crawdad@fnal.gov) + PA-SERVER-REFERRAL 25 (referrals) + PA-SAM-CHALLENGE2 30 (kenh@pobox.com) + PA-SAM-RESPONSE2 31 (kenh@pobox.com) + PA-EXTRA-TGT 41 Reserved extra TGT + TD-PKINIT-CMS-CERTIFICATES 101 CertificateSet from CMS + TD-KRB-PRINCIPAL 102 PrincipalName + TD-KRB-REALM 103 Realm + TD-TRUSTED-CERTIFIERS 104 PKINIT + TD-CERTIFICATE-INDEX 105 PKINIT + TD-APP-DEFINED-ERROR 106 Application specific + + + +Hartman & Zhu Expires February 13, 2010 [Page 39] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + TD-REQ-NONCE 107 INTEGER + TD-REQ-SEQ 108 INTEGER + PA-PAC-REQUEST 128 MS-KILE + PA-FOR_USER 129 MS-KILE + PA-FOR-X509-USER 130 MS-KILE + PA-FOR-CHECK_DUPS 131 MS-KILE + PA-AS-CHECKSUM 132 MS-KILE + PA-FX-COOKIE 133 draft-ietf-krb-wg-preauth-framework + PA-AUTHENTICATION-SET 134 draft-ietf-krb-wg-preauth-framework + PA-AUTH-SET-SELECTED 135 draft-ietf-krb-wg-preauth-framework + PA-FX-FAST 136 draft-ietf-krb-wg-preauth-framework + PA-FX-ERROR 137 draft-ietf-krb-wg-preauth-framework + PA-ENCRYPTED-CHALLENGE 138 draft-ietf-krb-wg-preauth-framework + PA-OTP-CHALLENGE 141 (gareth.richards@rsa.com) + PA-OTP-REQUEST 142 (gareth.richards@rsa.com) + PA-OTP-CONFIRM 143 (gareth.richards@rsa.com) + PA-OTP-PIN-CHANGE 144 (gareth.richards@rsa.com) + PA-EPAK-AS-REQ 145 (sshock@gmail.com) + PA-EPAK-AS-REP 146 (sshock@gmail.com>) + PA_PKINIT_KX 147 draft-ietf-krb-wg-anon + PA_PKU2U_NAME 148 draft-zhu-pku2u + PA-SUPPORTED-ETYPES 165 MS-KILE + PA-EXTENDED_ERROR 166 MS-KILE + +8.2. Fast Armor Types + + FAST armor types are defined in Section 6.5.1. A FAST armor type is + a signed 32-bit integer. FAST armor types are assigned by standards + action. + + Type Name Description + ------------------------------------------------------------ + 0 Reserved. + 1 FX_FAST_ARMOR_AP_REQUEST Ticket armor using an ap-req. + +8.3. FAST Options + + A FAST request includes a set of bit flags to indicate additional + options. Bits 0-15 are critical; other bits are non-critical. + Assigning bits greater than 31 may require special support in + implementations. Assignment of FAST options requires standards + action. + + + + + + + + + +Hartman & Zhu Expires February 13, 2010 [Page 40] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + Type Name Description + ------------------------------------------------------------------- + 0 RESERVED Reserved for future expansion of this + field. + 1 hide-client-names Requesting the KDC to hide client + names in the KDC response + 16 kdc-follow-referrals Requesting the KDC to follow + referrals + + +9. Security Considerations + + The kdc-referrals option in the Kerberos FAST padata requests the KDC + to act as the client to follow referrals. This can overload the KDC. + To limit the damages of denial of service using this option, KDCs MAY + restrict the number of simultaneous active requests with this option + for any given client principal. + + Regarding to the facilities provided by the Encrypted Challenge FAST + factor, the challenge key is derived from the client secrets and + because the client secrets are known only to the client and the KDC, + the verification of the EncryptedChallenge structure proves the + client's identity, the verification of the EncryptedChallenge + structure in the KDC reply proves that the expected KDC responded. + Therefore, the Encrypted Challenge FAST factor as a pre- + authentication mechanism offers the following facilities: client- + authentication and KDC-authentication. There is no un-authenticated + clear text introduced by the Encrypted Challenge FAST factor. + + FAST provides an encrypted tunnel over which pre-authentication + conversations can take place. In addition, FAST optionally + authenticates the KDC to the client. It is the responsibility of + FAST factors to authenticate the client to the KDC. Care MUST be + taken to design FAST factors such that they are bound to the + conversation. If this is not done, a man-in-the-middle may be able + to cut&paste a fast factor from one conversation to another. The + easiest way to do this is to bind each fast factor to the armor key + which is guaranteed to be unique for each conversation. + + The anonymous pkinit mode for obtaining an armor ticket does not + always authenticate the KDC to the client before the conversation + begins. Tracking the KDC verified state guarantees that by the end + of the conversation, the client has authenticated the KDC. However + fast factor designers need to consider the implications of using + their factor when the KDC has not yet been authenticated. If this + proves problematic in an environment, then the particular fast factor + should not be used with anonymous PKINIT. + + + + +Hartman & Zhu Expires February 13, 2010 [Page 41] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + Existing pre-authentication mechanisms are believed to be at least as + secure when used with FAST as they are when used outside of FAST. + One part of this security is making sure that when pre-authentication + methods checksum the request, they checksum the inner request rather + than the outer request. If the mechanism checksummed the outer + request, a man-in-the-middle could observe it outside a FAST tunnel + and then cut&paste it into a FAST exchange where the inner rather + than outer request would be used to select attributes of the issued + ticket. Such attacks would typically invalidate auditing information + or create a situation where the client and KDC disagree about what + ticket is issued. However, such attacks are unlikely to allow an + attacker who would not be able to authenticate as a principal to do + so. Even so, FAST is believed to defend against these attacks in + existing legacy mechanism. However since there is no standard for + how legacy mechanisms bind the request to the pre-authentication or + provide integrity protection, security analysis can be difficult. In + some cases FAST may significantly improve the integrity protection of + legacy mechanisms. + + The security of the TGS exchange depends on authenticating the client + to the KDC. In the AS exchange, this is done using pre- + authentication data or FAST factors. In the TGS exchange, this is + done by presenting a TGT and by using the session (or sub-session) + key in constructing the request. Because FAST uses a request body in + the inner request, encrypted in the armor key, rather than the + request body in the outer request, it is critical that establishing + the armor key be tied to the authentication of the client to the KDC. + If this is not done, an attacker could manipulate the options + requested in the TGS request, for example requesting a ticket with + different validity or addresses. The easiest way to bind the armor + key to the authentication of the client to the KDC is for the armor + key to depend on the sub-session key of the TGT. This is done with + the implicit TGS armor supported by this specification. Future armor + types designed for use with the TGS MUST either bind their armor keys + to the TGT or provide another mechanism to authenticate the client to + the KDC. + + +10. Acknowledgements + + Sam Hartman would like to thank the MIT Kerberos Consortium for its + funding of his time on this project. + + Several suggestions from Jeffrey Hutzelman based on early revisions + of this documents led to significant improvements of this document. + + The proposal to ask one KDC to chase down the referrals and return + the final ticket is based on requirements in [ID.CROSS]. + + + +Hartman & Zhu Expires February 13, 2010 [Page 42] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + Joel Webber had a proposal for a mechanism similar to FAST that + created a protected tunnel for Kerberos pre-authentication. + + Srinivas Cheruku and Greg Hudson provided valuable review comments. + + +11. References + +11.1. Normative References + + [KRB-ANON] + Zhu, L. and P. Leach, "Kerberos Anonymity Support", + draft-ietf-krb-wg-anon-04.txt (work in progress), 2007. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC3961] Raeburn, K., "Encryption and Checksum Specifications for + Kerberos 5", RFC 3961, February 2005. + + [RFC4120] Neuman, C., Yu, T., Hartman, S., and K. Raeburn, "The + Kerberos Network Authentication Service (V5)", RFC 4120, + July 2005. + + [RFC4556] Zhu, L. and B. Tung, "Public Key Cryptography for Initial + Authentication in Kerberos (PKINIT)", RFC 4556, June 2006. + +11.2. Informative References + + [EKE] Bellovin, S. and M. Merritt, "Augmented Encrypted Key + Exchange: A Password-Based Protocol Secure Against + Dictionary Attacks and Password File Compromise, + Proceedings of the 1st ACM Conference on Computer and + Communications Security, ACM Press.", November 1993. + + [ID.CROSS] + Sakane, S., Zrelli, S., and M. Ishiyama , "Problem + Statement on the Operation of Kerberos in a Specific + System", draft-sakane-krb-cross-problem-statement-02.txt + (work in progress), April 2007. + + [IEEE1363.2] + IEEE, "IEEE P1363.2: Password-Based Public-Key + Cryptography", 2004. + + [KRB-WG.SAM] + Hornstein, K., Renard, K., Neuman, C., and G. Zorn, + "Integrating Single-use Authentication Mechanisms with + + + +Hartman & Zhu Expires February 13, 2010 [Page 43] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + Kerberos", draft-ietf-krb-wg-kerberos-sam-02.txt (work in + progress), October 2003. + + [REFERRALS] + Raeburn, K. and L. Zhu, "Generating KDC Referrals to + Locate Kerberos Realms", + draft-ietf-krb-wg-kerberos-referrals-10.txt (work in + progress), 2007. + + +Appendix A. Test Vectors for KRB-FX-CF2 + + This informative appendix presents test vectors for the KRB-FX-CF2 + function. Test vectors are presented for several encryption types. + In all cases the first key (k1) is the result of string-to- + key("key1", "key1", default_parameters) and the second key (k2) is + the result of string-to-key("key2", "key2", default_parameters). + Both keys are of the same enctype. The presented test vector is the + hexadecimal encoding of the key produced by KRB-FX-CF2(k1, k2, "a", + "b"). The peppers are one-octet ASCII strings. + + In performing interoperability testing, there was significant + ambiguity surrounding [RFC3961] pseudo-random operations. These test + vectors assume that the AES pseudo-random operation is aes- + ecb(trunc128(sha-1(input))) where trunc128 truncates its input to + 128-bits. The 3DES pseudo-random operation is assumed to be des3- + cbc(trunc128(sha-1(input))). The DES pseudo-random operation is + assumed to be des-cbc(md5(input)). As specified in RFC 4757, the RC4 + pseudo-random operation is hmac-sha1(input). + + Interoperability testing also demonstrated ambiguity surrounding the + DES random-to-key operation. The random-to-key operation is assumed + to be distribute 56 bits into high-7-bits of 8 octets and generate + parity. + + These test vectors were produced with revision 22359 of the MIT + Kerberos sources. The AES 256 and AES 128 test vectors have been + confirmed by multiple other implementors. The RC4 test vectors have + been confirmed by one other implementor. The DES and triple DES test + vectors have not been confirmed. + + + aes 128 (enctype 17): 97df97e4b798b29eb31ed7280287a92a + AES256 (enctype 18): 4d6ca4e629785c1f01baf55e2e548566 + b9617ae3a96868c337cb93b5e72b1c7b + DES (enctype 1): 43bae3738c9467e6 + 3DES (enctype 16): e58f9eb643862c13ad38e529313462a7f73e62834fe54a01 + RC4 (enctype 23): 24d7f6b6bae4e5c00d2082c5ebab3672 + + + +Hartman & Zhu Expires February 13, 2010 [Page 44] + +Internet-Draft Kerberos Preauth Framework August 2009 + + +Appendix B. Change History + + RFC editor, please remove this section before publication. + +B.1. Changes since 13 + + Restore DES test vectors; their removal was not mentioned in 13. + Clarify that only implicit TGS armor is defined at this time. In + the future we may define explicit TGS armor. + +B.2. Changes since 12 + + Per comment from Greg Hudson, KDC_ERR_MORE_PREAUTH_DATA_REQUIRED + instead of KDC_ERR_MORE_PREAUTH_DATA_NEEDED + Use pa-authentication-set-selected not pa-auth-set-selected + Update discussion of KDC verification (Love) + Remove explicit TGS armor, note that TGS armor must authenticate + the client to the KDC, describe in security considerations. + +B.3. Changes since 11 + + Checksum the inner request body in methods like PKINIT, not the + outer request body. Per mailing list discussion, this change + addresses a potential security weakness. + Add additional security considerations text + +B.4. Changes since 10 + + The checksum member of the KrbFastFinished sequence has been + removed. A nonce field has been added to KrbFastResponse. + The cookie no longer needs to be outside of FAST. In fact, some + security guarantees depend on the cookie being inside FAST now + that the finish checksum has been removed. Affected that change. + Replace the rep-key field in KrbFastResponse with the strengthen- + key field. Per mailing list discussion, there are security + advantages to strengthening the reply key. + Clarify handling of authentication sets. + Include the AD-fx-fast-used authorization data type. + Include note about random nonces. + +B.5. Changes since 09 + + Clarify conversations by defining for TGS and by describing how + cookies form conversation boundaries. + Simplify text surrounding when finish is included: always for AS + and TGS reply, never for error. + + + + + +Hartman & Zhu Expires February 13, 2010 [Page 45] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + Fill in IANA and constants + +B.6. Changes since 08 + + Fix a number of typos + Rename anonymous flag to hide-client-name; rename kdc-referals to + kdc-follow-referrals + Clarify how anonymous pkinit interacts with KDC verified. + Introduce AD-fx-fast-armor authorization data to deal with + unprivileged processes constructing KDC requests. Note that a TGT + is always used for armor tickets if the armor field is present; if + you proxy or validate you'll end up with a TGT armor ticket and + another ticket in the pa-tgs-req. Alternatively you can simply + use the other ticket in the PA-TGS-REQ; weak consensus within WG. + All KDCs in a realm MUST support FAST if it is to be offered. + The cookie message is always generated by the KDC. + Note that the client can trust and need not verify the time stamp + in the finish message. This can seed the client's idea of KDC + time. + Note that the client name in the finish message may differ from + the name in the request if referrals are used. + Note that KDCs should advertize fast in preauth_required errors. + Armor key is constructed using KRB-FX-CF2. This is true even in + the TGS case; there is no security reason to do this. Using the + subkey as done in draft 08 would be fine, but the current text + uses the same procedure both in the TGS and AS case. + Use a different challenge key in each direction in the encrypted + challenge option. + Note that the KDC should process PA-FX-COOKIE before other padata. + KRB-FX-CF2 uses k1's enctype for the result; change around calling + order so we pass in subkeys and armor keys as k1 in preference to + long-term keys or ticket session keys. + Clarify the relationship between authentication sets and cookies. + A cookie may not be needed in the first message. Clarify how this + interacts with optimistic clients. + Remove text raising a concern that RFC 3961 may permit ciphertext + transformations that do not change plaintext: discussion on the + list came to the conclusion that RFC 3961 does not permit this. + Remove binding key concept; use the armor key instead. The cookie + becomes just an octet string. + Include PA-FX-ERROR to protect the error information per Dublin. + Returning preauth_failed in the failed to decrypt encrypted + challenge seems fine; remove the issue marker + Add a section describing what goes in the inner and outer request. + I believe it is redundant but found it useful while putting + together an implementation proposal. + + + + + +Hartman & Zhu Expires February 13, 2010 [Page 46] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + Use hyphen rather than underscore in the constants for pre- + authentication data to be consistent with RFC 4120. + Add a ticket-checksum to the finished message + Remove redundant KEY_USAGE_FAST_ARMOR. + Add protocol constants section for non-IANA registrations and + flesh out IANA section. + Clarify that kdc-req-body checksums should always use the outer + body even for mechanisms like PKINIT that include their own (now + redundant) checksum. + Remove mechanism for encapsulating typed data in padata; just + reflect the value. + +B.7. Changes since 07 + + Propose replacement of authenticated timestamp with encrypted + challenge. The desire to avoid clients needing time + synchronization and to simply the factor. + Add a requirement that any FAST armor scheme must provide a fresh + key for each conversation. This allows us to assume that anything + encrypted/integrity protected in the right key is fresh and not + subject to cross-conversation cut and paste. + Removed heartbeat padata. The KDC will double up messages if it + needs to; the client simply sends its message and waits for the + next response. + Define PA-auth-SET-SELECTED + Clarify a KDC cannot ignore padata is has claimed to support + +B.8. Changes since 06 + + Note that even for replace reply key it is likely that the side + using the mechanism will know that the other side supports it. + Since it is reasonably unlikely we'll need a container mechanism + other than FAST itself, we don't need to optimize for that case. + So, we want to optimize for implementation simplicity. Thus if + you do have such a container mechanism interacting with + authentication sets we'll assume that the hint need to describe + hints for all contained mechanisms. This closes out a long- + standing issue. + Write up what Sam believes is the consensus on UI and prompts in + the authentication set: clients MAY assume that they have all the + UI information they need. + + +Appendix C. ASN.1 module + + KerberosPreauthFramework { + iso(1) identified-organization(3) dod(6) internet(1) + security(5) kerberosV5(2) modules(4) preauth-framework(3) + + + +Hartman & Zhu Expires February 13, 2010 [Page 47] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + } DEFINITIONS EXPLICIT TAGS ::= BEGIN + + IMPORTS + KerberosTime, PrincipalName, Realm, EncryptionKey, Checksum, + Int32, EncryptedData, PA-ENC-TS-ENC, PA-DATA, KDC-REQ-BODY, + Microseconds, KerberosFlags + FROM KerberosV5Spec2 { iso(1) identified-organization(3) + dod(6) internet(1) security(5) kerberosV5(2) + modules(4) krb5spec2(2) }; + -- as defined in RFC 4120. + + + PA-AUTHENTICATION-SET ::= SEQUENCE OF PA-AUTHENTICATION-SET-ELEM + + PA-AUTHENTICATION-SET-ELEM ::= SEQUENCE { + pa-type [0] Int32, + -- same as padata-type. + pa-hint [1] OCTET STRING OPTIONAL, + pa-value [2] OCTET STRING OPTIONAL, + ... + } + + KrbFastArmor ::= SEQUENCE { + armor-type [0] Int32, + -- Type of the armor. + armor-value [1] OCTET STRING, + -- Value of the armor. + ... + } + + PA-FX-FAST-REQUEST ::= CHOICE { + armored-data [0] KrbFastArmoredReq, + ... + } + + KrbFastArmoredReq ::= SEQUENCE { + armor [0] KrbFastArmor OPTIONAL, + -- Contains the armor that identifies the armor key. + -- MUST be present in AS-REQ. + req-checksum [1] Checksum, + -- For AS, contains the checksum performed over the type + -- KDC-REQ-BODY for the req-body field of the KDC-REQ + -- structure; + -- For TGS, contains the checksum performed over the type + -- AP-REQ in the PA-TGS-REQ padata. + -- The checksum key is the armor key, the checksum + -- type is the required checksum type for the enctype of + -- the armor key, and the key usage number is + + + +Hartman & Zhu Expires February 13, 2010 [Page 48] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + -- KEY_USAGE_FAST_REQ_CHKSUM. + enc-fast-req [2] EncryptedData, -- KrbFastReq -- + -- The encryption key is the armor key, and the key usage + -- number is KEY_USAGE_FAST_ENC. + ... + } + + KrbFastReq ::= SEQUENCE { + fast-options [0] FastOptions, + -- Additional options. + padata [1] SEQUENCE OF PA-DATA, + -- padata typed holes. + req-body [2] KDC-REQ-BODY, + -- Contains the KDC request body as defined in Section + -- 5.4.1 of [RFC4120]. + -- This req-body field is preferred over the outer field + -- in the KDC request. + ... + } + + FastOptions ::= KerberosFlags + -- reserved(0), + -- hide-client-names(1), + -- kdc-follow-referrals(16) + + PA-FX-FAST-REPLY ::= CHOICE { + armored-data [0] KrbFastArmoredRep, + ... + } + + KrbFastArmoredRep ::= SEQUENCE { + enc-fast-rep [0] EncryptedData, -- KrbFastResponse -- + -- The encryption key is the armor key in the request, and + -- the key usage number is KEY_USAGE_FAST_REP. + ... + } + + KrbFastResponse ::= SEQUENCE { + padata [0] SEQUENCE OF PA-DATA, + -- padata typed holes. + strengthen-key [1] EncryptionKey OPTIONAL, + -- This, if present, strengthens the reply key for AS and + -- TGS. MUST be present for TGS + -- MUST be absent in KRB-ERROR. + finished [2] KrbFastFinished OPTIONAL, + -- Present in AS or TGS reply; absent otherwise. + nonce [3] UInt32, + -- Nonce from the client request. + + + +Hartman & Zhu Expires February 13, 2010 [Page 49] + +Internet-Draft Kerberos Preauth Framework August 2009 + + + ... + } + + KrbFastFinished ::= SEQUENCE { + timestamp [0] KerberosTime, + usec [1] Microseconds, + -- timestamp and usec represent the time on the KDC when + -- the reply was generated. + crealm [2] Realm, + cname [3] PrincipalName, + -- Contains the client realm and the client name. + ticket-checksum [4] Checksum, + -- checksum of the ticket in the KDC-REP using the armor + -- and the key usage is KEY_USAGE_FAST_FINISH. + -- The checksum type is the required checksum type + -- of the armor key. + ... + } + + EncryptedChallenge ::= EncryptedData + -- Encrypted PA-ENC-TS-ENC, encrypted in the challenge key + -- using key usage KEY_USAGE_ENC_CHALLENGE_CLIENT for the + -- client and KEY_USAGE_ENC_CHALLENGE_KDC for the KDC. + END + + +Authors' Addresses + + Sam hartman + Painless Security + + Email: hartmans-ietf@mit.edu + + + Larry Zhu + Microsoft Corporation + One Microsoft Way + Redmond, WA 98052 + US + + Email: lzhu@microsoft.com + + + + + + + + + + +Hartman & Zhu Expires February 13, 2010 [Page 50] + + diff --git a/doc/standardisation/draft-perez-krb-wg-gss-preauth-02.txt b/doc/standardisation/draft-perez-krb-wg-gss-preauth-02.txt new file mode 100644 index 000000000..dd8834931 --- /dev/null +++ b/doc/standardisation/draft-perez-krb-wg-gss-preauth-02.txt @@ -0,0 +1,616 @@ + + + +Kerberos Working Group A. Perez-Mendez +Internet-Draft R. Marin-Lopez +Intended status: Experimental F. Pereniguez-Garcia +Expires: March 5, 2013 G. Lopez-Millan + University of Murcia + Sep 2012 + + + GSS-API pre-authentication for Kerberos + draft-perez-krb-wg-gss-preauth-02 + +Abstract + + This document describes a pre-authentication mechanism for Kerberos + based on the Generic Security Service Application Program Interface + (GSS-API), which allows a Key Distribution Center (KDC) to + authenticate clients by using a GSS mechanism. + +Status of this Memo + + This Internet-Draft is submitted in full conformance with the + provisions of BCP 78 and BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF). Note that other groups may also distribute + working documents as Internet-Drafts. The list of current Internet- + Drafts is at http://datatracker.ietf.org/drafts/current/. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + This Internet-Draft will expire on March 5, 2013. + +Copyright Notice + + Copyright (c) 2012 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + + + +Perez-Mendez, et al. Expires March 5, 2013 [Page 1] + +Internet-Draft GSS preauth Sep 2012 + + + described in the Simplified BSD License. + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 1.1. Requirements Language . . . . . . . . . . . . . . . . . . 4 + 2. Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . 4 + 3. Definition of the Kerberos GSS padata . . . . . . . . . . . . 4 + 4. GSS Pre-authentication Operation . . . . . . . . . . . . . . . 5 + 4.1. Generation of GSS preauth requests . . . . . . . . . . . . 5 + 4.2. Processing of GSS preauth requests . . . . . . . . . . . . 6 + 4.3. Generation of GSS preauth responses . . . . . . . . . . . 6 + 4.4. Processing of GSS preauth responses . . . . . . . . . . . 7 + 5. Data in the KDC_ERR_PREAUTH_REQUIRED . . . . . . . . . . . . . 7 + 6. Derivation of the reply key from the GSS context . . . . . . . 7 + 7. KDC state management . . . . . . . . . . . . . . . . . . . . . 8 + 8. Support for federated users . . . . . . . . . . . . . . . . . 8 + 9. GSS channel bindings . . . . . . . . . . . . . . . . . . . . . 9 + 10. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 9 + 11. Security Considerations . . . . . . . . . . . . . . . . . . . 9 + 12. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 9 + 13. Normative References . . . . . . . . . . . . . . . . . . . . . 9 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 10 + + + + + + + + + + + + + + + + + + + + + + + + + + + +Perez-Mendez, et al. Expires March 5, 2013 [Page 2] + +Internet-Draft GSS preauth Sep 2012 + + +1. Introduction + + The GSS-API (Generic Security Service Application Programming + Interface) [RFC2743] provides a generic toolset of functions that + allow applications to establish security contexts in order to protect + their communications through security services such as + authentication, confidentiality and integrity protection. Thanks to + the GSS-API, applications remain independent from the specific + underlying mechanism used to establish the context and provide + security. + + On the other hand, Kerberos [RFC4120] defines a process called pre- + authentication. This feature is intended to avoid the security risk + of providing tickets encrypted with the user's long-term key to + attackers, by requiring clients to proof their knowledge over these + credentials. The execution of a pre-authentication mechanism may + require the exchange of several KRB_AS_REQ/KRB_ERROR messages before + the KDC delivers the TGT requested by the client within a KRB_AS_REP. + These messages transport authentication information by means of pre- + authentication elements. + + There exists a variety of pre-authentication mechanisms, like PKINIT + [RFC4556] and encrypted time-stamp [RFC4120]. Furthermore, + [I-D.ietf-krb-wg-preauth-framework] provides a generic framework for + Kerberos pre-authentication, which aims to describe the features that + a pre-authentication mechanism may provide (e.g. mutual + authentication, replace reply key, etc.). Additionally, in order to + simplify the definition of new pre-authentication mechanisms, it + defines a mechanism called FAST (Flexible Authentication Secure + Tunneling), which provides a generic and secure transport for pre- + authentication elements. More specifically, FAST establishes a + secure tunnel providing confidentiality and integrity protection + between the client and the KDC prior to the exchange of any specific + pre-authentication data. Within this tunnel, different pre- + authentication methods can be executed. This inner mechanism is + called a FAST factor. It is important to note that FAST factors + cannot usually be used outside the FAST pre-authentication method + since they assume the underlying security layer provided by FAST. + + The aim of this draft is to define a new pre-authentication + mechanism, following the recommendations of + [I-D.ietf-krb-wg-preauth-framework], that relies on the GSS-API + security services to pre-authenticate clients. This pre- + authentication mechanism will allow the KDC to authenticate clients + making use of any current or future GSS mechanism, as long as they + satisfy the minimum security requirements described in this + specification. The Kerberos client will play the role of the GSS + initiator, while the Authentication Server (AS) in the KDC will play + + + +Perez-Mendez, et al. Expires March 5, 2013 [Page 3] + +Internet-Draft GSS preauth Sep 2012 + + + the role of the GSS acceptor. + +1.1. Requirements Language + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC 2119 [RFC2119]. + + +2. Motivation + + This work is mainly motivated by the necessity of a way to allow the + KDC to make use of the technologies defined in the ABFAB WG to + perform the access control of federated users. Specifically, the + ABFAB architecture requires relying parties to make use of the GSS- + EAP mechanism to perform authentication. + [I-D.perez-abfab-eap-gss-preauth] defines how GSS-EAP is transported + on top of the GSS pre-authentication mechanism defined in this + document. + + +3. Definition of the Kerberos GSS padata + + To establish the security context, the GSS-API defines the exchange + of GSS tokens between the initiator and the acceptor. These tokens, + which contain mechanism-specific information, are completely opaque + to the application. However, how these tokens are transported + between the initiator and the responder depends on the specific + application. Since GSS-API is defined as independent of the + underlying communications service, its use does not require to + implement any specific security feature for the transport. For + instance, tokens could just be sent by means of plain UDP datagrams. + For this reason, security and ordered delivery of information must be + implemented by each specific GSS mechanism (if required). + + Therefore, GSS tokens are the atomic piece of information from the + application point of view when using GSS-API, which require a proper + transport between the initiator (Kerberos client) and the acceptor + (AS). In particular, the proposed GSS-based pre-authentication + mechanism defines a new pre-authentication element (hereafter padata) + called PA-GSS, to transport a generic GSS token from the Kerberos + client to the AS and vice-versa. This padata also transport state + information required to maintain the KDC stateless (see section + Section 7. + + PA-GSS To be defined (TBD) + + A PA-GSS padata element contains the ASN.1 DER encoding of the PA-GSS + + + +Perez-Mendez, et al. Expires March 5, 2013 [Page 4] + +Internet-Draft GSS preauth Sep 2012 + + + structure: + + PA-GSS ::= SEQUENCE { + sec-ctx-token [0] OCTET STRING, + state [1] EncryptedData OPTIONAL -- contains PA-GSS-STATE + } + + PA-GSS-STATE ::= SEQUENCE { + timestamp [0] KerberosTime, + exported-sec-ctx-token [1] OCTET STRING, + ... + } + + The sec-ctx-token element of the PA-GSS structure contains the + output_token token returned by either, the GSS_Init_sec_context and + the GSS_Accept_sec_context calls. The state element of the PA-GSS + structure is optional, and will be absent in the first AS_REQ message + from the client to the KDC and in the last AS_REP message from the + KDC to the client. It contains a PA-GSS-STATE structure encrypted + with the first krbtgt key and a key usage in the 512-1023 range (to + be defined TBD). The state element is generated by the KDC, while + the client just copy it from the previously received PA-GSS structure + (if present). + + The PA-GSS-STATE contains a timestamp element, meant to detect + possible replay situations, and a exported-sec-ctx-token element, + representing the whole GSS security context state corresponding to + the current authentication process. This value is generated by the + KDC by calling to the GSS_Export_sec_context, when the + GSS_Accept_sec_context returns GSS_S_CONTINUE_NEEDED. + + +4. GSS Pre-authentication Operation + +4.1. Generation of GSS preauth requests + + The Kerberos client (initiator) starts by calling to the + GSS_Init_sec_context function. In the first call to this function, + the client provides GSS_C_NO_CTX as the value of the context_handle + and NULL as the input_token, given that no context has been initiated + yet. When using multi round-trip GSS mechanisms, in subsequent calls + to this routine the client will use both, the context_handle value + obtained after the first call, and the input_token received from the + KDC. The mutual_req_flag, replay_det_req_flag and sequence_req_flag + MUST be set, as the GSS token is meant to be tranported over + cleartext channels. + + The GSS_Init_sec_context returns a context_handle, an output_token + + + +Perez-Mendez, et al. Expires March 5, 2013 [Page 5] + +Internet-Draft GSS preauth Sep 2012 + + + and a status value. In this first call, the only acceptable status + value is GSS_S_CONTINUE_NEEDED, as the KDC is expected to provide a + token in order to continue with the context establishment process. + The Kerberos client creates a new PA-GSS padata, with the obtained + output_token as the sec-ctx-token element, and with the state element + absent. The PA-GSS padata is sent to the KDC through a KRB_AS_REQ + message. + +4.2. Processing of GSS preauth requests + + When the KDC (GSS acceptor) receives a KRB_AS_REQ message containing + a PA-GSS padata, but a state element (see Section 7) is not included, + the KDC assumes that this is the first message of a context + establishment, and thus GSS_C_NO_CTX is used as context_handle to + invoke the GSS_Accept_sec_context routine. Conversely, if a state + element is included, the KDC assumes that this message is part an + ongoing authentication and the value of the state element is + decrypted and used to recover the state of the authentication (see + Section 7). In both cases, after receiving the message, the KDC + calls to the GSS_Accept_sec_context function, using the adequate + context_handle value and using the received token in the PA-GSS + padata as input_token. + + Once the execution of the GSS_Accept_sec_context function is + completed, the KDC obtains a context_handle, an output_token that + MUST be sent to the initiator in order to continue with the + authentication process, and a status value. If the obtained status + is GSS_S_COMPLETE, the client is considered authenticated. If the + status is GSS_S_CONTINUE_NEEDED, further information is required to + complete the process. + +4.3. Generation of GSS preauth responses + + Once the KDC has processed the input_token provided by the client (as + described in Section 4.2), two main different situations may occur + depending on the status value. If the client is successfully + authenticated (GSS_S_COMPLETE), the KDC will reply to the client with + a KRB_AS_REP message. This message will transport the final + output_token in a PA-GSS padata type. This PA-GSS padata will not + contain the state element. The reply key used to encrypt the enc- + part field of the KRB_AS_REP message is derived from the GSS security + context cryptographic material. Section 6 provides further details + regarding this derivation. At this moment, the KDC also verifies + that the cname provided in the AS_REQ matches the src_name obtained + through the final GSS_Accept_sec_ctx call (except when WELLKNOWN/ + FEDERATED is used as cname Section 8). + + On the contrary, if further data is required to complete the + + + +Perez-Mendez, et al. Expires March 5, 2013 [Page 6] + +Internet-Draft GSS preauth Sep 2012 + + + establishment process (GSS_S_CONTINUE_NEEDED), the KDC will reply to + the client with a KDC_ERR_MORE_PREAUTH_DATA_REQUIRED error message + [I-D.ietf-krb-wg-preauth-framework]. In the e-data field of the + message, the KDC will include the PA-GSS padata, containing both, the + GSS token (sec-ctx-token) and the exported GSS security context + (state) (see Section 7). + +4.4. Processing of GSS preauth responses + + When the client receives a KDC_ERR_MORE_PREAUTH_DATA_REQUIRED error, + it extracts the token from the PA-GSS element and invokes the + GSS_Init_sec_context function, as described in section Section 4.1. + If present, the state element of the PA-GSS padata is treated as an + opaque element, and it is simply copied and included into the + generated PA-GSS element without further processing. + + On the other hand, when the client receives a KRB_AS_REP, it knows + the context establishment has finalized successfully. The client + invokes the GSS_Init_sec_context function using the transported GSS + token. Note that, to be consistent, this call MUST return + GSS_S_COMPLETE and not generate any output_token, since the KDC does + not expect further data from the client. + + If the context establishment is completed correctly, the client MUST + use the same key derivation process followed by the KDC (Section 4.3) + to obtain the reply key to decrypt the enc-part of the KRB_AS_REP. + + +5. Data in the KDC_ERR_PREAUTH_REQUIRED + + When the KDC sends a KDC_ERR_PREAUTH_REQUIRED error to the client, it + includes a sequence of padata, each corresponding to an acceptable + pre-authentication method. Optionally, these padata elements contain + data valuable for the client to configure the selected mechanism. + The data to be included in the padata for this message is described + in this section. + + TBD. (For example, list of the OIDs of the GSS mechanisms supported + by the KDC) + + +6. Derivation of the reply key from the GSS context + + The GSS pre-authentication mechanism proposed in this draft provides + the "Replacing-reply-key" facility + [I-D.ietf-krb-wg-preauth-framework]. + + After a successful authentication, client and KDC may decide to + + + +Perez-Mendez, et al. Expires March 5, 2013 [Page 7] + +Internet-Draft GSS preauth Sep 2012 + + + completely replace the reply key used to encrypt the KRB_AS_REP by a + new one that is cryptographically independent from the client's + password stored in client password on the Kerberos users database. + This additional keying material can be obtained by means of calls to + the GSS_Pseudo_random [RFC4401] function, using "KRB-GSS" as the + prf_in parameter. + + +7. KDC state management + + The Kerberos standard [RFC4120] defines the KDC as a stateless + entity. This means that, if the GSS mechanism requires more than one + round-trip, the client MUST provide enough data to the KDC in the + following interactions to allow recovering the complete state of the + ongoing authentication. This is specially relevant when the client + switches from one KDC to different one (within the same realm) during + a pre-authentication process. This second KDC must be able to + continue with the process in a seamless way. + + The GSS-API manages the so-called security contexts. They represent + the whole context of an authentication, including all the state and + relevant data of the ongoing security context. Thus, this + information MUST be serialized and sent to the client in order to + ensure that the KDC receiving it will be able to reconstruct the + associated state. In order to prevent attacks, this information must + be confidentiality and integrity protected using a key shared amongst + all the KDCs deployed in the realm, and must be sent along with a + timestamp to prevent replay attacks. How this information is encoded + is described in section Section 3. + + To generate the serialized security context information, the + GSS_Export_sec_ctx() call is used. The main drawback of this + approach is that the current GSS-API specifications does not allow + the exportation of a security context which has not been completely + established. Nevertheless, some GSS mechanisms do allow the + exportation of partially established context (e.g. + [I-D.ietf-abfab-gss-eap]), and we expect that other GSS mechanisms + will do the same in the future. + + +8. Support for federated users + + This draft supports the authentication of users belonging to a + different domain than the authenticating KDC. This is achieved by + letting the GSS-API to provide both, the client name and the reply + key to be used. That means that the requested username may not be + present in the KDC's database. To avoid the generation of an error + of type KDC_ERR_C_PRINCIPAL_UNKNOWN, when the Kerberos client knows + + + +Perez-Mendez, et al. Expires March 5, 2013 [Page 8] + +Internet-Draft GSS preauth Sep 2012 + + + it is operating in a federated environment, it MUST set the value of + the cname field of the KRB_AS_REQ message to a new wellknown value, + WELLKNOWN/FEDERATED, following the model proposed in [RFC6111]. In + this way, the KDC will be completely authenticated by the GSS-API + calls, and thus no local verification of credentials should be done. + + +9. GSS channel bindings + + In order to link the GSS authentication with the actual Kerberos + exchange transporting GSS tokens, the DER-encoded KDC-REQ-BODY from + the AS-REQ is used as channel bindings. + + +10. Acknowledgements + + This work is supported by the project MULTIGIGABIT EUROPEAN ACADEMIC + NETWORK (FP7-INFRASTRUCTURES-2009-1). It is also funded by a Seneca + Foundation grant from the Human Resources Researching Training + Program 2007. Authors finally thank the Funding Program for Research + Groups of Excellence with code 04552/GERM/06 granted by the Fundacion + Seneca. + + +11. Security Considerations + + Protection of Request/Responses with FAST, restriction on GSS + mechanism, etc. TBD. + + +12. IANA Considerations + + This document has no actions for IANA. + + +13. Normative References + + [I-D.ietf-abfab-gss-eap] + Hartman, S. and J. Howlett, "A GSS-API Mechanism for the + Extensible Authentication Protocol", + draft-ietf-abfab-gss-eap-09 (work in progress), + August 2012. + + [I-D.ietf-krb-wg-preauth-framework] + Hartman, S. and L. Zhu, "A Generalized Framework for + Kerberos Pre-Authentication", + draft-ietf-krb-wg-preauth-framework-17 (work in progress), + June 2010. + + + +Perez-Mendez, et al. Expires March 5, 2013 [Page 9] + +Internet-Draft GSS preauth Sep 2012 + + + [I-D.perez-abfab-eap-gss-preauth] + Perez-Mendez, A., Lopez, R., Pereniguez-Garcia, F., and G. + Lopez-Millan, "GSS-EAP pre-authentication for Kerberos", + draft-perez-abfab-eap-gss-preauth-01 (work in progress), + March 2012. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2743] Linn, J., "Generic Security Service Application Program + Interface Version 2, Update 1", RFC 2743, January 2000. + + [RFC4120] Neuman, C., Yu, T., Hartman, S., and K. Raeburn, "The + Kerberos Network Authentication Service (V5)", RFC 4120, + July 2005. + + [RFC4401] Williams, N., "A Pseudo-Random Function (PRF) API + Extension for the Generic Security Service Application + Program Interface (GSS-API)", RFC 4401, February 2006. + + [RFC4556] Zhu, L. and B. Tung, "Public Key Cryptography for Initial + Authentication in Kerberos (PKINIT)", RFC 4556, June 2006. + + [RFC6111] Zhu, L., "Additional Kerberos Naming Constraints", + RFC 6111, April 2011. + + +Authors' Addresses + + Alejandro Perez-Mendez (Ed.) + University of Murcia + Campus de Espinardo S/N, Faculty of Computer Science + Murcia, 30100 + Spain + + Phone: +34 868 88 46 44 + Email: alex@um.es + + + Rafa Marin-Lopez + University of Murcia + Campus de Espinardo S/N, Faculty of Computer Science + Murcia, 30100 + Spain + + Phone: +34 868 88 85 01 + Email: rafa@um.es + + + + +Perez-Mendez, et al. Expires March 5, 2013 [Page 10] + +Internet-Draft GSS preauth Sep 2012 + + + Fernando Pereniguez-Garcia + University of Murcia + Campus de Espinardo S/N, Faculty of Computer Science + Murcia, 30100 + Spain + + Phone: +34 868 88 78 82 + Email: pereniguez@um.es + + + Gabriel Lopez-Millan + University of Murcia + Campus de Espinardo S/N, Faculty of Computer Science + Murcia, 30100 + Spain + + Phone: +34 868 88 85 04 + Email: gabilm@um.es + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Perez-Mendez, et al. Expires March 5, 2013 [Page 11] + diff --git a/doc/standardisation/draft-perez-krb-wg-gss-preauth-03.txt b/doc/standardisation/draft-perez-krb-wg-gss-preauth-03.txt new file mode 100644 index 000000000..e4c07b1db --- /dev/null +++ b/doc/standardisation/draft-perez-krb-wg-gss-preauth-03.txt @@ -0,0 +1,616 @@ + + + + +Kerberos Working Group A. Perez-Mendez +Internet-Draft Jisc +Intended status: Experimental R. Marin-Lopez +Expires: 27 March 2022 University of Murcia + F. Pereniguez-Garcia + University Defense Center + G. Lopez-Millan + University of Murcia + L. Howard-Bentata + PADL Software Pty Ltd + September 2021 + + + GSS-API pre-authentication for Kerberos + draft-perez-krb-wg-gss-preauth-03 + +Abstract + + This document describes a pre-authentication mechanism for Kerberos + based on the Generic Security Service Application Program Interface + (GSS-API), which allows a Key Distribution Center (KDC) to + authenticate clients by using a GSS mechanism. + +Status of This Memo + + This Internet-Draft is submitted in full conformance with the + provisions of BCP 78 and BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF). Note that other groups may also distribute + working documents as Internet-Drafts. The list of current Internet- + Drafts is at https://datatracker.ietf.org/drafts/current/. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + This Internet-Draft will expire on 5 March 2022. + +Copyright Notice + + Copyright (c) 2021 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents (https://trustee.ietf.org/ + license-info) in effect on the date of publication of this document. + + + +Perez-Mendez, et al. Expires 27 March 2022 [Page 1] + +Internet-Draft GSS-API pre-auth September 2021 + + + Please review these documents carefully, as they describe your rights + and restrictions with respect to this document. Code Components + extracted from this document must include Simplified BSD License text + as described in Section 4.e of the Trust Legal Provisions and are + provided without warranty as described in the Simplified BSD License. + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2 + 1.1. Requirements Language . . . . . . . . . . . . . . . . . . 3 + 2. Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . 3 + 2.1. Cookie Support . . . . . . . . . . . . . . . . . . . . . 3 + 2.2. More Pre-Authentication Data Required . . . . . . . . . . 3 + 2.3. Support for Exporting Partially Established Contexts . . 4 + 2.4. Processing of Channel Bindings in Single Round-Trip . . . 4 + 3. Definition of the GSS padata . . . . . . . . . . . . . . . . 4 + 4. GSS-API Pre-authentication Operation . . . . . . . . . . . . 4 + 4.1. Kerberos client (GSS-API initiator) . . . . . . . . . . . 4 + 4.2. KDC (GSS-API acceptor) . . . . . . . . . . . . . . . . . 5 + 5. Indication of Supported Mechanisms . . . . . . . . . . . . . 6 + 6. Reply Key Derivation . . . . . . . . . . . . . . . . . . . . 7 + 7. Naming . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 + 8. Anonymous Authentication . . . . . . . . . . . . . . . . . . 8 + 9. Security Considerations . . . . . . . . . . . . . . . . . . . 8 + 10. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 9 + 11. Normative References . . . . . . . . . . . . . . . . . . . . 9 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 10 + +1. Introduction + + The Generic Security Service Application Programming Interface (GSS- + API) [RFC2743] provides a framework for authentication and message + protection services through a common programming interface, allowing + applications to remain agnostic from the selected mechanism. + + Kerberos [RFC4120] is an authentication service based on the Needham- + Schroeder symmetric key protocol. It includes a facility called pre- + authentication designed to ensure clients prove knowledge of their + long-term key before the Key Distribution Center (KDC) issues a + ticket. Typical pre-authentication mechanisms include encrypted + timestamp [RFC4120] and public key certificates [RFC4556]. Pre- + authentication data in these messages provides a typed hole for + exchanging information used to authenticate the client. + + [RFC6113] specifies a framework for pre-authentication in Kerberos, + describing the features such a pre-authentication mechanism may + provide such as authenticating the client and/or KDC and + strengthening or replacing the reply key in the AS-REP. FAST + + + +Perez-Mendez, et al. Expires 27 March 2022 [Page 2] + +Internet-Draft GSS-API pre-auth September 2021 + + + (Flexible Authentication Secure Tunneling) provides a generic and + secure transport for pre-authentication elements prior to the + exchange of any pre-authentication data. The inner pre- + authentication mechanism is called a FAST factor. FAST factors can + generally not be used outside FAST as they assume the underlying + security layer provided by FAST. + + This document defines a new pre-authentication method that relies on + GSS-API security services to pre-authenticate Kerberos clients. This + method allows the KDC to authenticate clients using any current or + future GSS-API mechanism, as long as they satisfy the minimum + security requirements described in this specification. The Kerberos + client assumes the role of the GSS-API initiator, and the + Authentication Service (AS) the role of the GSS-API acceptor. It may + be used as a FAST factor or without FAST. + + This work was originally motivated by the desire to allow Kerberos to + use the protocols defined in [RFC7055] to authenticate federated + users with EAP. + +1.1. Requirements Language + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC2119]. + +2. Prerequisites + +2.1. Cookie Support + + KDCs which support GSS-API pre-authentication with mechanisms that + require more than one round-trip to establish a security context MUST + have a secure mechanism for retaining state between AS-REQs. For + stateless KDC implementations, this will typically be a digest of the + initial KDC-REQ-BODY concatenated with a GSS_Export_sec_context() + token, encrypted in a key known only to the KDC and protected from + replay attacks (see Section 5.2 of [RFC6113]). The format of the PA- + FX-COOKIE is implementation defined. + + Clients that support GSS-API pre-authentication with mechanisms that + require more than one round-trip MUST echo the received PA-FX-COOKIE + in the next AS-REQ (within a given conversation). + +2.2. More Pre-Authentication Data Required + + Both KDCs and clients which implement GSS-API pre-authentication MUST + support the use of KDC_ERR_MORE_PREAUTH_DATA_REQUIRED, as decribed in + Section 5.2 of [RFC6113]. + + + +Perez-Mendez, et al. Expires 27 March 2022 [Page 3] + +Internet-Draft GSS-API pre-auth September 2021 + + +2.3. Support for Exporting Partially Established Contexts + + KDC implementations that use exported context tokens to maintain + state will call GSS_Export_sec_context() and GSS_Import_sec_context() + on partially established acceptor contexts. This may require + modifications to the mechanism implementation, as [RFC2743] only + requires these functions succeed on fully established contexts. + +2.4. Processing of Channel Bindings in Single Round-Trip + + The client's KDC request is bound to the GSS-API context + establishment through the use of channel bindings. GSS-API + mechanisms that require more than one round-trip do not expose at + which point in the exchange the channel bindings are validated, and + assume they are constant for all context establishment calls. In + this specification, the channel bindings contain the encoded client + request body, which may vary for each round-trip if a fresh nonce is + used on each request. + + To accommodate this, and to avoid re-encoding the request body + without the nonce, this specification imposes the additional + requirement that the GSS-API mechanism processes channel bindings in + a single round-trip within the pre-authentication conversation. + +3. Definition of the GSS padata + + The GSS-API defines an exchange of opaque tokens between the + initiator (client) and acceptor (service) in order to authenticate + each party. GSS-API does not define the transport over which these + tokens are carried. This specification defines a Kerberos pre- + authentication type, PA-GSS, which carries a GSS-API context token + from the Kerberos client to the AS and vice versa. + + PA-GSS 633 + -- output_token from GSS_Init_sec_context() + -- or GSS_Accept_sec_context() + +4. GSS-API Pre-authentication Operation + +4.1. Kerberos client (GSS-API initiator) + + The Kerberos client begins by calling GSS_Init_sec_context() with the + desired credential handle and the target name of the TGS, including + the instance and realm. If the underlying mechanism supports + Kerberos names, the TGS name MUST be imported as a + GSS_KRB5_NT_PRINCIPAL_NAME; otherwise, it SHALL be imported as a + GSS_C_NT_HOSTBASED_SERVICE with "krbtgt" as the "service" element and + the TGS realm as the "hostname" element (see [RFC2743] Section 4.1). + + + +Perez-Mendez, et al. Expires 27 March 2022 [Page 4] + +Internet-Draft GSS-API pre-auth September 2021 + + + In the first call to GSS_Init_sec_context(), input_context_handle is + GSS_C_NO_CONTEXT and input_token is empty. In subsequent calls the + client uses the context_handle value obtained after the first call, + and the input_token received from the KDC. The mutual_req_flag MUST + be set. + + In order to bind the GSS-API and Kerberos message exchanges, the DER- + encoded KDC-REQ-BODY from the AS-REQ is passed as channel binding + application data. As the nonce may differ between requests (see + [RFC6113] Section 5.4.3), this requires the GSS-API mechanism to + process the channel binding information in a single round-trip. To + avoid this potential interoperability issue, clients MAY use a single + nonce for all messages in a conversation once GSS-API pre- + authentication has commenced. + + If GSS_Init_sec_context() returns GSS_S_CONTINUE_NEEDED, the + output_token is sent to the KDC in the PA-GSS pre-authentication data + and the client expects either a KRB-ERROR containing another context + token, or an AS-REP optionally containing a final context token. + + Once GSS_Init_sec_context() returns GSS_S_COMPLETE, the context is + ready for use. The AS-REP is decrypted using the reply key (see + Section 6) and the Kerberos client name MAY be replaced by the AS-REP + cname (see Section 7). The client MUST fail if the mutual_state flag + is not set when fully established, unless the KDC was authenticated + by some other means such as a FAST armor. + + The response received from the KDC must agree with the expected + status from GSS_Init_sec_context(). It is a state violation to + receive an AS-REP from the KDC when the initiator still has + additional tokens to send to the KDC (GSS_S_CONTINUE_NEEDED), or + conversely to receive KDC_ERR_MORE_PREAUTH_DATA_REQUIRED if the + context from the initiator's perspective was already open + (GSS_S_COMPLETE). + + When receiving a KDC_ERR_MORE_PREAUTH_DATA_REQUIRED error from the + KDC, an PA-FX-COOKIE from the KDC MUST be present and copied into the + subsequent AS-REQ. + +4.2. KDC (GSS-API acceptor) + + When the KDC receives an AS-REQ message containing PA-GSS pre- + authentication data, it first looks for an PA-FX-COOKIE and if + present retrieves the context handle associated with the cookie, + typically by passing the context token from the decrypted cookie to + GSS_Import_sec_context(). The absence of an PA-FX-COOKIE indicates a + new conversation and the client sending an initial context token. + + + + +Perez-Mendez, et al. Expires 27 March 2022 [Page 5] + +Internet-Draft GSS-API pre-auth September 2021 + + + The KDC SHALL associate the KDC-REQ-BODY of the initial request with + the pre-authentication conversation. On subsequent requests, the KDC + MUST abort the conversation and return an error if the KDC-REQ-BODY + differs from the initial request. The nonce is excluded from this + comparison. This extends the protection afforded by the channel + binding to all requests in the conversation, not just the request + where the mechanism validated the channel bindings. (No specific + implementation is required, but one approach would be for the KDC to + include a digest of the KDC-REQ-BODY with the nonce set to zero in + the PA-FX-COOKIE contents.) + + If no PA-GSS pre-authentication data is present, the KDC cannot + continue with GSS-API pre-authentication and will continue with other + pre-authentication methods or return an error as determined by local + policy. If PA-GSS pre-authentication data is present but empty, the + KDC SHALL return a KDC_ERR_PREAUTH_FAILED error. Otherwise, + GSS_Accept_sec_context() is called with the acceptor credential + handle, the token provided in the PA-GSS pre-authentication data, and + channel binding application data containing the DER-encoded KDC-REQ- + BODY. + + If GSS_Accept_sec_context() returns GSS_S_CONTINUE_NEEDED, the KDC + returns a KDC_ERR_MORE_PREAUTH_DATA_REQUIRED error with the output + token included as PA-GSS pre-authentication data. The acceptor state + is encoded, typically by calling GSS_Export_sec_context(), and the + encrypted result is placed in an PA-FX-COOKIE. + + If GSS_Accept_sec_context() returns GSS_S_COMPLETE, the context is + ready for use and an AS-REP is returned using the reply key specified + in Section 6. Otherwise, an appropriate error such as + KDC_ERR_PREAUTH_FAILED is returned to the client and the conversation + is aborted. If the mechanism emitted an error token on failure, it + SHOULD be returned to the client. + + If the GSS-API mechanism requires an odd number of messages to + establish a security context, the KDC MUST include an empty GSS-PA + pre-authentication data in the last message of a successful + conversation. + +5. Indication of Supported Mechanisms + + When the KDC sends a KDC_ERR_PREAUTH_REQUIRED error to the client, it + MAY include a pre-authentication data element indicating the set of + supported mechanisms. The pre-authentication data comprises of a + SPNEGO server initiated initial context token as defined in [MS-SPNG] + 3.2.5.2, containing the list of mechanisms supported by the acceptor. + Context state is discarded and as such the first PA-GSS from the + client is always an InitialContextToken ([RFC2743] Section 3.1). + + + +Perez-Mendez, et al. Expires 27 March 2022 [Page 6] + +Internet-Draft GSS-API pre-auth September 2021 + + +6. Reply Key Derivation + + The GSS-API pre-authentication mechanism proposed in this draft + provides the Replace Reply Key facility [RFC6113]. + + After authentication is complete, the client and KDC replace the AS- + REP reply key with the output of calling GSS_Pseudo_random() + [RFC4401] with the following parameters: + + context The initiator or acceptor context handle + + prf_key GSS_C_PRF_KEY_FULL + + prf_in KRB-GSS || 0x00 || AS-REQ nonce + + desired_output_len The length in bytes of original reply key + + The nonce is the nonce of the final AS-REQ in the conversation, and + is encoded as the little-endian binary representation of 4 bytes. + The new reply key has the same key type as the original key. If FAST + is used, the new reply key SHOULD be strengthened by including a + strengthen key in the KrbFastResponse. + +7. Naming + + This specification permits Kerberos clients to authenticate without + knowing how the KDC will map their GSS-API initiator name to a + Kerberos principal. In such cases the client SHALL set the value of + the cname field in the AS-REQ to the well-known [RFC6111] value + WELLKNOWN/FEDERATED, replacing it after a successful conversation + with the client name returned in the AS-REP. + + When the initiator knows the Kerberos client name it wishes to + authenticate as, and the mechanism supports Kerberos names, the name + MUST be imported using the GSS_KRB5_NT_PRINCIPAL_NAME name type. + Otherwise, GSS_C_NT_USER_NAME SHOULD be used when importing NT- + PRINCIPAL names in the local realm, or NT-ENTERPRISE [RFC6806] names. + GSS_C_NT_HOSTBASED_SERVICE SHOULD be used when importing NT-SRV-HOST + or NT-SRV-INST names with a single instance. + + This specification does not mandate a specific mapping of GSS-API + initiator names to Kerberos principal names. KDCs MAY use the NT- + ENTERPRISE principal name type to avoid conflating any domain- or + realm-like components of initiator names with Kerberos realms. + + The KDC MAY include an AD-GSS-COMPOSITE-NAME authorization data + element, containing name attribute information. Its value is the + exp_composite_name octet string resulting from a successful call to + + + +Perez-Mendez, et al. Expires 27 March 2022 [Page 7] + +Internet-Draft GSS-API pre-auth September 2021 + + + GSS_Export_name_composite() [RFC6680]. It SHOULD be enclosed in a + AD-IF-RELEVANT container. The format of composite name tokens is + implementation dependent; services that cannot parse the name token + MUST fail if the authorization data element was not enclosed in AD- + IF-RELEVANT. + +8. Anonymous Authentication + + If the client wishes to authenticate anonymously using GSS-API pre- + authentication, it MUST specify both the request-anonymous flag in + the AS-REQ and anon_req_flag in the call to GSS_Init_sec_context(). + If GSS_Accept_sec_context() set anon_state and returned an initiator + name of type GSS_C_NT_ANONYMOUS, the KDC MUST map the user to the + well-known anonymous PKINIT principal and realm defined in [RFC8062]. + + If GSS_Accept_sec_context() set anon_state but did not return an + initiator name of type GSS_C_NT_ANONYMOUS, then the KDC MUST return + the well-known anonymous principal but it MAY include the realm of + the initiator. + +9. Security Considerations + + The client SHOULD use FAST armor to protect the pre-authentication + conversation. + + The KDC MUST maintain confidentiality and integrity of the PA-FX- + COOKIE contents, typically by encrypting it using a key known only to + itself. Cookie values SHOULD be protected from replay attacks by + limiting their validity period and binding their contents to the + client name in the AS-REQ. + + The establishment of a GSS-API security context is bound to the + client's AS-REQ through the inclusion of the encoded KDC-REQ-BODY as + channel bindings (see Section 4.1), and the nonce as input to the key + derivation function (see Section 6). By asserting the KDC-REQ-BODY + does not change during the conversation (nonce notwithstanding), the + channel bindings protect all request bodies in the conversation. + + The KDC MAY wish to restrict the set of GSS-API mechanisms it will + accept requests from. When using SPNEGO [RFC4178] with GSS-API pre- + authentication, the client should take care not to select a mechanism + with weaker security properties than a different non-GSS-API pre- + authentication type that could have been used. + + If mutual_state is false after GSS_Init_sec_context() completes, the + client MUST ensure that the KDC was authenticated by some other + means. + + + + +Perez-Mendez, et al. Expires 27 March 2022 [Page 8] + +Internet-Draft GSS-API pre-auth September 2021 + + +10. IANA Considerations + + Assign PA-GSS value in Pre-authentication and Typed Data, Kerberos + Parameters registry (preference for 633). + + The ad-type number 633 (TBD) is assigned for AD-GSS-COMPOSITE-NAME, + updating the table in Section 7.5.4 of [RFC4120]. + +11. Normative References + + [MS-SPNG] "Simple and Protected GSS-API Negotiation Mechanism + (SPNEGO) Extension", . + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, + DOI 10.17487/RFC2119, March 1997, + . + + [RFC2743] Linn, J., "Generic Security Service Application Program + Interface Version 2, Update 1", RFC 2743, + DOI 10.17487/RFC2743, January 2000, + . + + [RFC4120] Neuman, C., Yu, T., Hartman, S., and K. Raeburn, "The + Kerberos Network Authentication Service (V5)", RFC 4120, + DOI 10.17487/RFC4120, July 2005, + . + + [RFC4178] Zhu, L., Leach, P., Jaganathan, K., and W. Ingersoll, "The + Simple and Protected Generic Security Service Application + Program Interface (GSS-API) Negotiation Mechanism", + RFC 4178, DOI 10.17487/RFC4178, October 2005, + . + + [RFC4401] Williams, N., "A Pseudo-Random Function (PRF) API + Extension for the Generic Security Service Application + Program Interface (GSS-API)", RFC 4401, + DOI 10.17487/RFC4401, February 2006, + . + + [RFC4556] Zhu, L. and B. Tung, "Public Key Cryptography for Initial + Authentication in Kerberos (PKINIT)", RFC 4556, + DOI 10.17487/RFC4556, June 2006, + . + + + + + +Perez-Mendez, et al. Expires 27 March 2022 [Page 9] + +Internet-Draft GSS-API pre-auth September 2021 + + + [RFC6111] Zhu, L., "Additional Kerberos Naming Constraints", + RFC 6111, DOI 10.17487/RFC6111, April 2011, + . + + [RFC6113] Hartman, S. and L. Zhu, "A Generalized Framework for + Kerberos Pre-Authentication", RFC 6113, + DOI 10.17487/RFC6113, April 2011, + . + + [RFC6680] Williams, N., Johansson, L., Hartman, S., and S. + Josefsson, "Generic Security Service Application + Programming Interface (GSS-API) Naming Extensions", + RFC 6680, DOI 10.17487/RFC6680, August 2012, + . + + [RFC6806] Hartman, S., Ed., Raeburn, K., and L. Zhu, "Kerberos + Principal Name Canonicalization and Cross-Realm + Referrals", RFC 6806, DOI 10.17487/RFC6806, November 2012, + . + + [RFC7055] Hartman, S., Ed. and J. Howlett, "A GSS-API Mechanism for + the Extensible Authentication Protocol", RFC 7055, + DOI 10.17487/RFC7055, December 2013, + . + + [RFC8062] Zhu, L., Leach, P., Hartman, S., and S. Emery, Ed., + "Anonymity Support for Kerberos", RFC 8062, + DOI 10.17487/RFC8062, February 2017, + . + +Authors' Addresses + + Alejandro Perez-Mendez + Jisc + 4 Portwall Lane + Bristol + BS1 6NB + United Kingdom + + Email: alex.perez-mendez@jisc.ac.uk + + + Rafa Marin-Lopez + University of Murcia + Campus de Espinardo S/N, Faculty of Computer Science + 30100 Murcia Murcia + Spain + + + + +Perez-Mendez, et al. Expires 27 March 2022 [Page 10] + +Internet-Draft GSS-API pre-auth September 2021 + + + Phone: +34 868 88 85 01 + Email: rafa@um.es + + + Fernando Pereniguez-Garcia + University Defense Center + Spanish Air Force Academy + 30720 San Javier Murcia + Spain + + Phone: +34 968 18 99 46 + Email: fernando.pereniguez@cud.upct.es + + + Gabriel Lopez-Millan + University of Murcia + Campus de Espinardo S/N, Faculty of Computer Science + 30100 Murcia Murcia + Spain + + Phone: +34 868 88 85 04 + Email: gabilm@um.es + + + Luke Howard-Bentata + PADL Software Pty Ltd + PO Box 59 + Central Park Victoria 3145 + Australia + + Email: lukeh@padl.com + + + + + + + + + + + + + + + + + + + + +Perez-Mendez, et al. Expires 27 March 2022 [Page 11] diff --git a/doc/standardisation/draft-zhu-negoex-04.txt b/doc/standardisation/draft-zhu-negoex-04.txt new file mode 100644 index 000000000..17f189fa6 --- /dev/null +++ b/doc/standardisation/draft-zhu-negoex-04.txt @@ -0,0 +1,1345 @@ + + + +NETWORK WORKING GROUP M. Short +Internet-Draft L. Zhu +Updates: 4178 (if approved) K. Damour +Intended status: Standards Track D. McPherson +Expires: July 7, 2011 Microsoft Corporation + January 3, 2011 + + + SPNEGO Extended Negotiation (NEGOEX) Security Mechanism + draft-zhu-negoex-04 + +Abstract + + This document defines the SPNEGO Extended Negotiation (NEGOEX) + Security Mechanism. NEGOEX enhances the capabilities of SPNEGO by + providing a security mechanism which can be negotiated by the SPNEGO + protocol as defined in RFC4178. + + The NEGOEX protocol itself is a security mechanism negotiated by + SPNEGO. When the NEGOEX security mechanism is selected by SPNEGO, + NEGOEX provides a method allowing selection of a common + authentication protocol based on factors beyond just the fact that + both client and server support a given security mechanism. NEGOEX + OPTIONALLY adds a pair of meta-data messages for each negotiated + security mechanism. The meta-data exchange allows security + mechanisms to exchange auxiliary information such as trust + configurations, thus NEGOEX provides more flexibility than just + exchanging security mechanism OIDs in SPNEGO. + + NEGOEX preserves the optimistic token semantics of SPNEGO and applies + that recursively. Consequently a context establishment mechanism + token can be included in the initial NEGOEX message, and NEGOEX does + not require an extra round-trip when the initiator's optimistic token + is accepted by the target. + + Similar to SPNEGO, NEGOEX defines a few new GSS-API extensions that a + security mechanism MUST support in order to be negotiated by NEGOEX. + This document defines these GSS-API extensions. + + Unlike SPNEGO however, NEGOEX defines its own way for signing the + protocol messages in order to protect the protocol negotiation. The + NEGOEX message signing or verification can occur before the security + context for the negotiated real security mechanism is fully + established. + +Status of this Memo + + This Internet-Draft is submitted in full conformance with the + + + +Short, et al. Expires July 7, 2011 [Page 1] + +Internet-Draft NEGOEX January 2011 + + + provisions of BCP 78 and BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF). Note that other groups may also distribute + working documents as Internet-Drafts. The list of current Internet- + Drafts is at http://datatracker.ietf.org/drafts/current/. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + This Internet-Draft will expire on July 7, 2011. + +Copyright Notice + + Copyright (c) 2011 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + + + + + + + + + + + + + + + + + + + + + + + +Short, et al. Expires July 7, 2011 [Page 2] + +Internet-Draft NEGOEX January 2011 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 4 + 2. Requirements Terminology . . . . . . . . . . . . . . . . . . . 6 + 3. Presentation Language and Primitive Data Types . . . . . . . . 7 + 3.1. Basic Block Size . . . . . . . . . . . . . . . . . . . . . 7 + 3.2. Miscellaneous . . . . . . . . . . . . . . . . . . . . . . 7 + 3.3. Constants . . . . . . . . . . . . . . . . . . . . . . . . 7 + 3.4. Numbers . . . . . . . . . . . . . . . . . . . . . . . . . 7 + 3.5. Enum Types . . . . . . . . . . . . . . . . . . . . . . . . 7 + 3.6. Typedef Declarations . . . . . . . . . . . . . . . . . . . 8 + 3.7. Array Types . . . . . . . . . . . . . . . . . . . . . . . 8 + 3.8. Constructed Types . . . . . . . . . . . . . . . . . . . . 8 + 4. Vector Types . . . . . . . . . . . . . . . . . . . . . . . . . 10 + 5. NEGOEX Messages . . . . . . . . . . . . . . . . . . . . . . . 11 + 6. Cryptographic Computations . . . . . . . . . . . . . . . . . . 12 + 7. The NEGOEX Protocol . . . . . . . . . . . . . . . . . . . . . 12 + 7.1. High-level NEGOEX Message Flow . . . . . . . . . . . . . . 12 + 7.2. NEGOEX Supported Security Mechanisms . . . . . . . . . . . 13 + 7.3. ConversationID . . . . . . . . . . . . . . . . . . . . . . 13 + 7.4. Generation of the Initiator Initial Token . . . . . . . . 13 + 7.5. Receipt of the Initial Initiator Token and Generation + of the Initial Acceptor Response . . . . . . . . . . . . . 15 + 7.6. Receipt of the Acceptor Initial Response and + Completion of Authentication after the Negotiation + Phrase . . . . . . . . . . . . . . . . . . . . . . . . . . 16 + 7.7. Finalizing Negotiation . . . . . . . . . . . . . . . . . . 16 + 8. Supporting GSS-API Extensions . . . . . . . . . . . . . . . . 17 + 8.1. GSS_Query_meta_data . . . . . . . . . . . . . . . . . . . 17 + 8.2. GSS_Exchange_meta_data . . . . . . . . . . . . . . . . . . 18 + 8.3. GSS_Query_mechanism_info . . . . . . . . . . . . . . . . . 19 + 8.4. GSS_Inquire_context . . . . . . . . . . . . . . . . . . . 19 + 9. Security Considerations . . . . . . . . . . . . . . . . . . . 19 + 10. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 20 + 11. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 20 + 12. Normative References . . . . . . . . . . . . . . . . . . . . . 20 + Appendix A. Protocol Data Structures and Constant Values . . . . 20 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 24 + + + + + + + + + + + + + +Short, et al. Expires July 7, 2011 [Page 3] + +Internet-Draft NEGOEX January 2011 + + +1. Introduction + + If more than one GSS-API mechanism is shared between the initator and + the acceptor, the Simple and Protected (GSS-API) Negotiation + Mechanism (SPNEGO) as defined in [RFC4178] can be deployed to choose + a mutually preferred one. This pseudo mechanism does well in the + most basic scenarios but suffers from a couple of drawbacks, notably: + + o Since the SPNEGO negotiation is based on purely on exchanging + security mechanism OIDs, security mechanisms can be selected which + cannot successfully authenticate the initator. Just because an + initator and acceptor support the same security mechanism does not + mean that they have a mutually trusted authentication authority. + In such cases, the authentication will fail with the preferred + security mechanism, but might succeed with another common + mechanism. + + o Secondly, the SPNEGO negotiation model is inadequate when the + choice cannot be made by the acceptor in the initial response. In + SPNEGO, the negotiation information is sent one-way from the + initiator for the acceptor to make a choice, and the acceptor must + choose one when it makes the initial response. This negotiation + model is counter intuitive. The selection of a security mechanism + is typically the result of selecting one type of credentials from + the available set, and the initiator typically does not wish to + reveal credentials information often associated with user + identities. In practice, in order to operate in this model, the + Kerberos GSS-API mechanism [RFC4121] must acquire the context + establishment token in the initial call to GSS_Init_sec_context(). + If the initiator fails to acquire the initial Kerberos GSS-API + context token, it must not offer Kerberos; otherwise the SPNEGO + context negotiation will fail without being able to select the + next available mechanism that could work. Obtaining the initial + Kerberos GSS-API context token may require multiple round-trips of + network calls and the cost of the operation can be substantial. + It is suboptimal when multiple GSS-API mechanisms have to add the + extra cost that would not exist if the negotiated security + mechanism were selected based on configuration. + + The SPNEGO Extended Negotiation (NEGOEX) Security Mechanism is + designed to address these concerns. NEGOEX is a security mechanism + that is negotiated by SPNEGO, and when negotiated, it can recursively + negotiate other security mechanisms. + + Any security mechanism negotiated by NEGOEX MUST support integrity + protection and addition GSS-API interfaces specified in Section 8. + + The basic form of NEGOEX works as follows: + + + +Short, et al. Expires July 7, 2011 [Page 4] + +Internet-Draft NEGOEX January 2011 + + + 1. The initiator proposes a list of mechanisms in decreasing + preference order. For each of these mechanism, NEGOEX OPTIONALLY + includes a mechanism specific meta-data token. GSS-API + extensions are defined later in this document for NEGOEX to query + the meta-data token for inclusion in the NEGOEX message. + + 2. The acceptor then passes the meta-data token from the initiator + to the intended security mechanism. A meta-data token for a + security mechanism not supported on the acceptor side is ignored. + New GSS-API extensions are defined later in this document for a + security mechanism to consume the meta-data token. When + processing the received meta-data tokens, a security mechanism + that reports a failure is removed from the set of mutually + supported mechanisms. The acceptor then responds with the list + of mutually supported mechanisms in decreasing preference order. + For each of these mechanism, NEGOEX again OPTIONALLY supplies a + mechanism specific meta-data token in the response which it + obtains from each remaining supported mechanism via the new GSS- + API extensions described in the initial step. + + 3. The initiator then passes the meta-data tokens to the intended + security mechanisms by invoking the new GSS-API extensions. When + processing the received meta-data token, a security mechanism + that reports a failure is removed from the set of mutually + supported mechanisms for this negotiation context. The initiator + then selects one from the set of mutually-supported mechanisms. + If more than one security mechanism is available, unless + otherwise specified, the highest one in the acceptor's preference + order SHOULD be selected. Later when the common security + mechanism is identified, the security mechanism may also + negotiate mechanism-specific options during its context + establishments. This will be inside the mechanism tokens, and + invisible to the NEGOEX protocol during step 5. + + 4. The selected security mechanism provides keying materials to + NEGOEX via new GSS-API extensions which defined later in this + document. NEGOEX signs and verifies the negotiation NEGOEX + messages to protect the negotiation. + + 5. The initiator and the acceptor proceed to exchange tokens until + the GSS-API context for selected security mechanism is + established. Once the security context is established, the per- + message tokens are generated and verified in accordance with the + selected security mechanism. + + NEGOEX does not work outside of SPNEGO. When negotiated by SPNEGO, + NEGOEX uses the concepts developed in the GSS-API specification + [RFC2743]. The negotiation data is encapsulated in context-level + + + +Short, et al. Expires July 7, 2011 [Page 5] + +Internet-Draft NEGOEX January 2011 + + + tokens. Therefore, callers of the GSS-API do not need to be aware of + the existence of the negotiation tokens but only of the SPNEGO + pseudo-security mechanism. + + In its basic form NEGOEX requires at least one extra round-trip. + Network connection setup is a critical performance characteristic of + any network infrastructure and extra round trips over WAN links, + packet radio networks, etc. really make a difference. In order to + avoid such an extra round trip the initial security token of the + preferred mechanism for the initiator may be embedded in the initial + NEGOEX token. The optimistic mechanism token may be accompanied by + the meta-data tokens and the optimistic mechanism token MUST be that + of the first mechanism in the list of the mechanisms proposed by the + initiator. The NEGOEX MESSAGE_TYPE_INITIATOR_NEGO message that + contains signatures for protecting the NEGOEX negotiation may also + accompany the optimistic mechanism token. If the target preferred + mechanism matches the initiator's preferred mechanism, and when the + NEGOEX negotiation protection messages are included along with the + mechanism token, no additional round trips are incurred by using the + NEGOEX protocol with SPNEGO. + + NEGOEX does not update the ASN.1 structures of SPNEGO [RFC4178] + because a widely deployed SPNEGO implementation does not have the + ASN.1 extensibility marker in the message definition. There is no + change to the SPNEGO messages. + + NEGOEX uses a C-like definition language to describe message formats. + + The rest of the document is organized as follows: + + o Section 3 defines the encoding of NEGOEX data structures and all + the primitive data types. + o Section 6 describes the cryptographic framework required by the + NEGOEX for protecting the NEGOEX negotiation. + o Section 7 defines the NEGOEX messages and the NEGOEX protocol. + o Section 8 defines the new GSS-API extensions that a security + mechanism MUST support in order to be negotiated by NEGOEX. + o Section 9 contains the security considerations for NEGOEX. + o Appendix A contains all the protocol constructs and constants. + + +2. Requirements Terminology + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC2119]. + + + + + +Short, et al. Expires July 7, 2011 [Page 6] + +Internet-Draft NEGOEX January 2011 + + +3. Presentation Language and Primitive Data Types + + The following very basic and somewhat casually defined presentation + syntax will be used in all NEGOEX messages. Although it resembles + the programming language "C" in its syntax, it would be risky to draw + too many parallels. The purpose of this presentation language is to + document NEGOEX only; it has no general application beyond that + particular goal. + + This section also defines all the primitive data types. The + semantics of the data types is explained in the next section. + +3.1. Basic Block Size + + The representation of all data items is explicitly specified. The + basic data block size is one octet. Multiple octet data items are + concatenations of octets, from left to right, from top to bottom + Unless otherwise specific a multi-octet numeric is in little endian + order with the least significant octet first. + +3.2. Miscellaneous + + Comments start with "//"' and continue until the end of the line. + +3.3. Constants + + Constants are denoted using "#define" followed by the symbolic name + and then the constant value. + +3.4. Numbers + + UCHAR is the data type for a one-octet number. + + ULONG is the data type for a 4-octet number encoded in little endian. + + USHORT is the data type for a 2-octet number encoded in little + endian. + + ULONG64 is the data type for a 8-octet number encoded in little + endian. + + GUID is the data type for a 16-octet number encoded in little endian. + +3.5. Enum Types + + An enum type is the data type for a number with a small number of + permissible values. An instance of an enum type is a 4-octet number + encoded in little endian. + + + +Short, et al. Expires July 7, 2011 [Page 7] + +Internet-Draft NEGOEX January 2011 + + + The definition of an enum type follows the simple "C" convention. + + MESSAGE_TYPE is an enum type defined as follows: + + enum + { + MESSAGE_TYPE_INITIATOR_NEGO = 0, + MESSAGE_TYPE_ACCEPTOR_NEGO, + MESSAGE_TYPE_INITIATOR_META_DATA, + MESSAGE_TYPE_ACCEPTOR_META_DATA, + MESSAGE_TYPE_CHALLENGE, + // an exchange message from the acceptor + MESSAGE_TYPE_AP_REQUEST, + // an exchange message from the initiator + MESSAGE_TYPE_VERIFY, + MESSAGE_TYPE_ALERT, + } MESSAGE_TYPE; + + MESSAGE_TYPE_INITIATOR_NEGO has the value 0, and MESSAGE_TYPE_ALERT + has the value 7. + +3.6. Typedef Declarations + + A typedef creates a synonym for the type. This is used to create + more meaningful names for existing types. + + The following two type synonyms are defined. + + typedef GUID AUTH_SCHEME; + typedef GUID CONVERSATION_ID; + +3.7. Array Types + + Arrays are a data structure which holds multiple variables of the + same data type consecutively and the number of elements is fixed. An + array is declared using "C" convention. The following defines an + array of 32 octets. + + UCHAR Random[32]; + +3.8. Constructed Types + + Structure types may be constructed from primitive types for + convenience. Each specification declares a new, unique type. The + syntax for definition is much like that of C. + + + + + + +Short, et al. Expires July 7, 2011 [Page 8] + +Internet-Draft NEGOEX January 2011 + + + struct { + T1 f1; + T2 f2; + ... + Tn fn; + } T; + + + Structure definitions may be embedded. + + The following types are defined as constructed types: + + struct + { + ULONG ExtensionType; // negative extensions are critical + BYTE_VECTOR ExtensionValue; + } EXTENSION; + + An extension has two fields. The ExtensionType field indicates how + the extension data should be interpreted. The ExtensionValue field + contains the extension data. + + // + // schemes defined for the checksum in the VERIFY message + // + + struct + { + ULONG cbHeaderLength; + ULONG ChecksumScheme; + ULONG ChecksumType; // in the case of RFC3961 scheme, this is + // the RFC3961 checksum type + BYTE_VECTOR ChecksumValue; + } CHECKSUM; + + The CHECKSUM structure contains 4 fields. The cbHeaderLength length + contains the length of the structure defintion in octets, and this + field has a value of 20. + + The ChecksumScheme field describes how checksum is computed and + verified. Currently only one value is defined. + + #define CHECKSUM_SCHEME_RFC3961 1 + + When the value of the ChecksumScheme field is 1 + (CHECKSUM_SCHEME_RFC3961), the ChecksumValue field contains a + sequence of octets computed according to [RFC3961] and the + ChecksumType field contains the checksum type value defined according + + + +Short, et al. Expires July 7, 2011 [Page 9] + +Internet-Draft NEGOEX January 2011 + + + to [RFC3961]. + + +4. Vector Types + + Vectors are a data structure which holds multiple variables of the + same data type consecutively and the number of elements is not fixed. + A vector contains a fixed length header followed by a variable length + payload. The header of a vector structure contains the count of + elements and the offset to the payload. In this document all the + offset fields are relative to the beginning of the containing NEGOEX + message. The size of each element is specified by the vector type + definition. + + The following vector types are defined. + + struct + { + ULONG ByteArrayOffset; // each element contains an octet/byte + ULONG ByteArrayLength; + } BYTE_VECTOR; + + BYTE_VECTOR encapsulates a variable length array of octets (or bytes) + that are stored consecutively. Each element in is a byte (8 bits). + + struct + { + ULONG AuthSchemeArrayOffset; + // each element contains an AUTH_SCHEME + USHORT AuthSchemeCount; + } AUTH_SCHEME_VECTOR; + + AUTH_SCHEME_VECTOR encapsulates a variable length array of + AUTH_SCHEMEs that are stored consecutively. Each element is a + structure of the type AUTH_SCHEME. + + struct + { + ULONG ExtensionArrayOffset; + // each element contains an EXTENSION + USHORT ExtensionCount; + } EXTENSION_VECTOR; + + EXTENSION_VECTOR encapsulates a variable length array of EXTENSIONs + that are stored consecutively. Each element is a structure of the + type EXTENSION. + + + + + +Short, et al. Expires July 7, 2011 [Page 10] + +Internet-Draft NEGOEX January 2011 + + +5. NEGOEX Messages + + The following structure is the MESSAGE_HEADER: + + struct + { + ULONG64 Signature; // contains MESSAGE_SIGNATURE + MESSAGE_TYPE MessageType; + ULONG SequenceNum; // the message sequence number of this, + // conversation, starting with 0 and sequentially + // incremented + ULONG cbHeaderLength; // the header length of this message, + // including the message specific header, excluding the + // payload + ULONG cbMessageLength; // the length of this message + CONVERSATION_ID ConversationId; + } MESSAGE_HEADER; + + The following structure is the NEGO_MESSAGE: + + struct + { + MESSAGE_HEADER Header; + // MESSAGE_TYPE_INITIATOR_NEGO for the initiator, + // MESSAGE_TYPE_ACCEPTOR_NEGO for the acceptor + UCHAR Random[32]; + ULONG64 ProtocolVersion; + // version of the protocol, this contains 0 + AUTH_SCHEME_VECTOR AuthSchemes; + EXTENSION_VECTOR Extensions; + } NEGO_MESSAGE; + + The following structure is the EXCHANGE_MESSAGE: + + struct + { + MESSAGE_HEADER Header; + // MESSAGE_TYPE_CHALLENGE for the acceptor, + // or MESSAGE_TYPE_AP_REQUEST for the initiator + // MESSAGE_TYPE_INITIATOR_META_DATA for + // the initiator metadata + // MESSAGE_TYPE_ACCEPTOR_META_DATA for + // the acceptor metadata + AUTH_SCHEME AuthScheme; + BYTE_VECTOR Exchange; + // contains the opaque handshake message for the + // authentication scheme + } EXCHANGE_MESSAGE; + + + +Short, et al. Expires July 7, 2011 [Page 11] + +Internet-Draft NEGOEX January 2011 + + +6. Cryptographic Computations + + The message signing and verification in NEGOEX is based on [RFC3961]. + [RFC3961] is used here as a generic framework and this application is + not Kerberos specific. + + A security mechanism MUST support [RFC3961] in order to be negotiated + by NEGOEX. + + +7. The NEGOEX Protocol + + This section describes the NEGOEX protocol and it defines NEGOEX + messages in the order that the messages can appear on the wire. The + enum type MESSAGE_TYPE defined in Section 3.5 lists all NEGOEX + message types. A GSS-API context token for NEGOEX consists of one or + more NEGOEX messages. If there is more than one NEGOEX message, + these messages are concatenated together. The smallest data unit for + NEGOEX to compute the checksum for negotiation protection is s NEGOEX + message. Note that NEGOEX is not a GSS-API mechanism itself and the + initial NEGOEX context establishment token does not follow the + mechanism-independent token format defined in Section 3.1 of + [RFC2743]. + + The object identifier of the NEGOEX within SPNEGO is iso(1) + identified-organization(3) dod(6) internet(1) private(4) + enterprise(1) microsoft (311) security(2) mechanisms(2) negoex(30). + +7.1. High-level NEGOEX Message Flow + + The following text art summarizes the protocol message flow: + + + + + + + + + + + + + + + + + + + + +Short, et al. Expires July 7, 2011 [Page 12] + +Internet-Draft NEGOEX January 2011 + + + Initiator Acceptor + + INITIATOR_NEGO + +*INITIATOR_META_DATA + *AP_REQUEST + ---------> + ACCEPTOR_NEGO + ACCEPTOR_META_DATA*+ + <--------- CHALLENGE* + + . + . + + *AP_REQUEST ---------> + <--------- CHALLENGE* + + . + . + *AP_REQUEST + VERIFY ---------> + CHALLENGE* + <--------- VERIFY + * Indicates optional or situation-dependent messages that are + not always sent. + + Indicates there can be more than one instance. + + +7.2. NEGOEX Supported Security Mechanisms + + NEGOEX maintains an ordered list of supported security mechanisms + names to determine priority of security mechanisms. A security + mechanism negotiable by NEGOEX is identified by a unique identifier + of data type AUTH_SCHEME defined in Section 3.5. Supported security + mechanisms are referenced by their corresponding authentication + scheme IDs. The authentication scheme ID of a security mechanism is + returned to NEGOEX by calling GSS_Query_mechanism_info() with the + name of the security mechnism as defined in Section 8.3. + +7.3. ConversationID + + Both initiator and acceptor must keep protocol state in the form of a + GUID, which will be referred to hereafter as the ConversationID. + +7.4. Generation of the Initiator Initial Token + + The GSS-API initiator makes the first call to GSS_Init_sec_context() + with no input token, and the output token will be a NEGO_MESSAGE + message with the MESSAGE_TYPE_INITIATOR_NEGO message followed by zero + + + +Short, et al. Expires July 7, 2011 [Page 13] + +Internet-Draft NEGOEX January 2011 + + + or more EXCHANGE_MESSAGE messages containing meta-data tokens, + followed by zero or one AP_REQUEST messages containing an optimistic + initial context token. + + The initiator generates a cryptographic strength random 16 byte + value, stores it as the ConversationID, then sets the MESSAGE_HEADER + header field with the same name to that value. The ConversationID in + subsequent NEGOEX messages MUST remain the same. The initiator also + fills the Random field using a secure random number generator. The + initiator fills the AuthSchemes with available security mechanisms + supported by the initiator in decreasing preference order. + + The extensions field contains NEGOEX extensions for future + extensibility. There are no extensions defined in this document. + All negative extension types (the highest bit is set to 1) are + critical. If the receiver does not understand a critical extension, + the authentication attempt must be rejected. + + The initiator can OPTIONALLY include a meta-data token, one for each + available security mechanism. + + A meta-data token is returned to NEGOEX for a security mechanism + using GSS_Query_meta_data() extension as defined in Section 8.1. If + a non-empty meta-data token is returned, then the meta-data token is + encapsulated in an EXCHANGE message with the message type + MESSAGE_TYPE_INITIATOR_META_DATA. On GSS_Query_meta_data call + failure, NEGOEX SHOULD remove the security mechanism from the set of + authentication schemes to be negotiated. + + The AuthScheme field signifies the security mechanism for which the + EXCHANGE message is targeted. If a security mechanism fails to + produce the metadata token, it should be removed from the list of + supported security mechanism for this negotiation context. + + If there is more than one exchange message, the order in which the + exchange message is included bears no significance. In other words, + the exchange messages are in an unordered set. The NEGO_MESSAGE MAY + be followed by a set of MESSAGE_TYPE_INITIATOR_META_DATA messages as + described above, in which case all the NEGOEX messages concatenated + are returned as a single output token. + + The first mechanism in the initiator proposed list can OPTIONALLY + include its initial context token in an AP_REQUEST message. + + Both an AP_REQUEST(short for MESSAGE_TYPE_AP_REQUEST) message and a + INITIATOR_META_DATA(short for MESSAGE_TYPE_INITIATOR_META_DATA) + message are instances of the EXCHANGE_MESSAGE structure with + different message type values. An AP_REQUEST message contains the + + + +Short, et al. Expires July 7, 2011 [Page 14] + +Internet-Draft NEGOEX January 2011 + + + type MESSAGE_TYPE_AP_REQUEST while an INITIATOR_META_DATA message + contains the type MESSAGE_TYPE_INITIATOR_META_DATA. + +7.5. Receipt of the Initial Initiator Token and Generation of the + Initial Acceptor Response + + Upon receipt of the NEGO_MESSAGE from the initiator, the acceptor + verifies the NEGO_MESSAGE to make sure it is well-formed. The + acceptor extracts the ConversationID from the NEGO_MESSAGE and stores + it as the ConversationID for the context handle. The acceptor then + computes the list of authentication schemes that are mutually + supported by examining the set of security mechanisms proposed by the + initiator and the meta-data tokens from the initiator. The meta-data + tokens are passed to the security mechanism via + GSS_Exchange_meta_data() as defined in Section 8.2. On + GSS_Exchange_meta_data call failure, NEGOEX SHOULD remove the + security mechanism from the set of authentication schemes to be + negotiated. + + The acceptor MUST examine the NEGOEX extensions in the NEGO_MESSAGE. + If there is an unknown critical extension, the authentication must be + rejected. + + The acceptor's output token is a NEGO_MESSAGE but with the the + Header.MessageType set to MESSAGE_TYPE_ACCEPTOR_NEGO followed by zero + or more EXCHANGE_MESSAGE containing meta-data tokens. The + AuthSchemes field contains the list of mutually supported security + mechanism in decreasing preference order of the acceptor. The + acceptor does not need to honor the preference order proposed by the + initiator when computing its preference list. + + As with the initiator, the acceptor can OPTIONALLY include a meta- + data token, one for each available security mechanism. + + A meta-data token is obtained by NEGOEX for a security mechanism + using GSS_Query_meta_data() extension as defined in Section 8.1. If + a non-empty meta-data token is returned, then the meta-data token is + encapsulated in an EXCHANGE message with the message type + MESSAGE_TYPE_ACCEPTOR_META_DATA. For a given security mechanism if a + meta-token is received from the initiator, GSS_Query_meta_data() MUST + be invoked on the acceptor side for that security mechanism, and the + output meta-data token, if present, MUST be included in the NEGOEX + reply. On GSS_Query_meta_data call failure, NEGOEX SHOULD remove the + security mechanism from the set of authentication schemes to be + negotiated. + + + + + + +Short, et al. Expires July 7, 2011 [Page 15] + +Internet-Draft NEGOEX January 2011 + + +7.6. Receipt of the Acceptor Initial Response and Completion of + Authentication after the Negotiation Phrase + + Upon receipt of the initial response token from the acceptor, the + application calls GSS_Init_sec_context with the response token. The + initiator verifies the NEGOEX message received to make sure it is + well-formed. The initiator ensures the correct context handle by + verifying that the ConversationID of the context handle matches the + conversation ID in the NEGOEX message received. The initiator then + computes the list of authentication schemes that are mutually + supported by examining the set of security mechanisms returned by the + acceptor and the meta-data tokens from the acceptor The meta-data + tokens are passed to the security mechanism via + GSS_Exchange_meta_data() as defined in Section 8.2. On + GSS_Exchange_meta_data call failure, NEGOEX SHOULD remove the + security mechanism from the set of authentication schemes to be + negotiated. + + The initiator MUST examine the NEGOEX extensions in the NEGO_MESSAGE. + If there is an unknown critical extension, the authentication must be + rejected. + + After the initial exchange of NEGO_MESSAGE messages, the initiator + MUST choose the negotiated security mechanism. The negotiated + security mechanism cannot be changed once it is selected. + + The initiator and the acceptor can then proceed to exchange handshake + messages by returning GSS_S_CONTINUE_NEEDED to the calling + application as determined by the negotiated security mechanism until + its authentication context is established. The context tokens of the + negotiated security mechanism are encapsulated in an + EXCHANGE_MESSAGE. If the context token is from the initiator, the + EXCHANGE_MESSAGE message has the message type + MESSAGE_TYPE_AP_REQUEST; otherwise, the message type is + MESSAGE_TYPE_CHALLENGE. + +7.7. Finalizing Negotiation + + After the security mechanism has been selected, the initiator and + acceptor can use GSS_Inquire_context to obtain the Negoex_Verify_key + as defined in Section 8.4 to determine if there is a shared key for + the VERIFY message. When there is a shared key established returned + by GSS_Inquire_context as defined in Section 8.4, a VERIFY message is + produced using the required checksum mechanism per RFC 3961 and + included in the output token. The returned protocol key is used as + the base key in the parlance of RFC3961 to sign all the NEGOEX + messages in the negotiation context. + + + + +Short, et al. Expires July 7, 2011 [Page 16] + +Internet-Draft NEGOEX January 2011 + + + A VERIFY message is a VERIFY_MESSAGE structure. The AuthScheme field + signifies from which security mechanism the protocol key was + obtained. The checksum is computed based on RFC3961 and the key + usage number is 23 for the message signed by the initiator, 25 + otherwise. The checksum is performed over all the previous NEGOEX + messages in the context negotiation. + + struct + { + MESSAGE_HEADER Header; // MESSAGE_TYPE_VERIFY + AUTH_SCHEME AuthScheme; + CHECKSUM Checksum; + // contains the checksum of all the previously + // exchanged messages in the order they were sent. + } VERIFY_MESSAGE; + + Note that the VERIFY_MESSAGE message can be included before the + security context for the negotiated security mechanism is fully + established. + + +8. Supporting GSS-API Extensions + + This section defined all the required GSS-API extensions required by + NEGOEX which must be supported by security mechanisms usable with + NEGOEX. + +8.1. GSS_Query_meta_data + + Inputs: + + o input_context_handle CONTEXT HANDLE + o targ_name INTERNAL NAME, optional + o deleg_req_flag BOOLEAN, + o mutual_req_flag BOOLEAN, + o replay_det_req_flag BOOLEAN, + o sequence_req_flag BOOLEAN, + o conf_req_flag BOOLEAN, + o integ_req_flag BOOLEAN, + + Outputs: + + o metadata OCTET STRING, + o output_context_handle CONTEXT HANDLE + + Return major_status codes: + + + + + +Short, et al. Expires July 7, 2011 [Page 17] + +Internet-Draft NEGOEX January 2011 + + + o GSS_S_COMPLETE indicates that the context referenced by the + input_context_handle argument is valid, and that the output + metadata value represents the security mechanism's provided + metadata. A security mechanism may return empty metadata. + o GSS_S_NO_CONTEXT indicates that no valid context was recognized + for the input context_handle provided. Return values other than + major_status and minor_status are undefined. + o GSS_S_NO_CRED indicates that no metadata could be returned about + the referenced credentials either because the input cred_handle + was invalid or the caller lacks authorization to access the + referenced credentials. + o GSS_S_UNAVAILABLE indicates that the authentication security + service does not support this operation. + o GSS_S_FAILURE indicates that the requested operation failed for + reasons unspecified at the GSS-API level. Return values other + than major_status and minor_status are undefined. + + GSS_Query_meta_data is used to retrieve a security mechanism's + metadata. + +8.2. GSS_Exchange_meta_data + + Inputs: + + o input_context_handle CONTEXT HANDLE + o cred_handle CREDENTIAL HANDLE, optional + o targ_name INTERNAL NAME, optional + o deleg_req_flag BOOLEAN, + o mutual_req_flag BOOLEAN, + o replay_det_req_flag BOOLEAN, + o sequence_req_flag BOOLEAN, + o conf_req_flag BOOLEAN, + o integ_req_flag BOOLEAN, + o metadata OCTET STRING, + + Outputs: + + o output_context_handle CONTEXT HANDLE + + Return major_status codes: + + o GSS_S_COMPLETE indicates that the metadata was provided to the + security mechanism. + o GSS_S_NO_CONTEXT indicates that no valid context was recognized + for the input context_handle provided. Return values other than + major_status and minor_status are undefined. + + + + + +Short, et al. Expires July 7, 2011 [Page 18] + +Internet-Draft NEGOEX January 2011 + + + o GSS_S_NO_CRED indicates that the metadata passed requested + credentials not available via this credential handle. + o GSS_S_UNAVAILABLE indicates that the security mechanism does not + support this operation. + o GSS_S_FAILURE indicates that the requested operation failed for + reasons unspecified at the GSS-API level. Return values other + than major_status and minor_status are undefined. + + GSS_Exchange_meta_data is used to provide the metadata to each + security mechanism. + +8.3. GSS_Query_mechanism_info + + Inputs: + + o SecMechName STRING, + + Outputs: + + o AuthScheme AUTH_SCHEME + + Return major_status codes: + + o GSS_S_COMPLETE indicates that the authentication scheme value + represents the security mechanism's AUTH_SCHEME. + o GSS_S_FAILURE indicates that the security mechanism does not + support NEGOEX. Return values other than major_status and + minor_status are undefined. + + GSS_Query_mechanism_info returns a security mechanism's + authentication scheme value. + +8.4. GSS_Inquire_context + + The following output is added to GSS_Inquire_context as defined in + [RFC2743]. + + Outputs: + + o Negoex_Verify_key OCTET STRING + + This new output is the key to be used by NEGOEX for the VERIFY + message. + + +9. Security Considerations + + Security mechanism SHOULD support providing VERIFY key material. + + + +Short, et al. Expires July 7, 2011 [Page 19] + +Internet-Draft NEGOEX January 2011 + + + This ensures that VERIFY messages are generated to make NEGOEX safe + from downgrade attacks. + + +10. Acknowledgements + + TBD. + + +11. IANA Considerations + + There is no action required for IANA. + + +12. Normative References + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2743] Linn, J., "Generic Security Service Application Program + Interface Version 2, Update 1", RFC 2743, January 2000. + + [RFC3961] Raeburn, K., "Encryption and Checksum Specifications for + Kerberos 5", RFC 3961, February 2005. + + [RFC4120] Neuman, C., Yu, T., Hartman, S., and K. Raeburn, "The + Kerberos Network Authentication Service (V5)", RFC 4120, + July 2005. + + [RFC4121] Zhu, L., Jaganathan, K., and S. Hartman, "The Kerberos + Version 5 Generic Security Service Application Program + Interface (GSS-API) Mechanism: Version 2", RFC 4121, + July 2005. + + [RFC4178] Zhu, L., Leach, P., Jaganathan, K., and W. Ingersoll, "The + Simple and Protected Generic Security Service Application + Program Interface (GSS-API) Negotiation Mechanism", + RFC 4178, October 2005. + + +Appendix A. Protocol Data Structures and Constant Values + + This section compiles all the protocol data structures and constant + values. + + #define MESSAGE_SIGNATURE 0x535458454f47454ei64 + // "NEGOEXTS" + + + + +Short, et al. Expires July 7, 2011 [Page 20] + +Internet-Draft NEGOEX January 2011 + + + struct + { + ULONG ByteArrayOffset; // each element contains a byte + ULONG ByteArrayLength; + } BYTE_VECTOR; + + struct + { + ULONG AuthSchemeArrayOffset; + // each element contains an AUTH_SCHEME + USHORT AuthSchemeCount; + } AUTH_SCHEME_VECTOR; + + struct + { + ULONG ExtensionArrayOffset; + // each element contains an EXTENSION + USHORT ExtensionCount; + } EXTENSION_VECTOR; + + struct + { + ULONG ExtensionType; // negative extensions are critical + BYTE_VECTOR ExtensionValue; + } EXTENSION; + + // + // schemes defined for the checksum in the VERIFY message + // + + #define CHECKSUM_SCHEME_RFC3961 1 + + struct + { + ULONG cbHeaderLength; + ULONG ChecksumScheme; + ULONG ChecksumType; // in the case of RFC3961 scheme, this is + // the RFC3961 checksum type + BYTE_VECTOR ChecksumValue; + } CHECKSUM; + + typedef GUID AUTH_SCHEME; + typedef GUID CONVERSATION_ID; + + enum + { + MESSAGE_TYPE_INITIATOR_NEGO = 0, + MESSAGE_TYPE_ACCEPTOR_NEGO, + + + +Short, et al. Expires July 7, 2011 [Page 21] + +Internet-Draft NEGOEX January 2011 + + + MESSAGE_TYPE_INITIATOR_META_DATA, + MESSAGE_TYPE_ACCEPTOR_META_DATA, + MESSAGE_TYPE_CHALLENGE, + // an exchange message from the acceptor + MESSAGE_TYPE_AP_REQUEST, + // an exchange message from the initiator + MESSAGE_TYPE_VERIFY, + MESSAGE_TYPE_ALERT, + } MESSAGE_TYPE; + + struct + { + ULONG64 Signature; // contains MESSAGE_SIGNATURE + MESSAGE_TYPE MessageType; + ULONG SequenceNum; // the message sequence number of this, + // conversation, starting with 0 and sequentially + // incremented + ULONG cbHeaderLength; // the header length of this message, + // including the message specific header, excluding the + // payload + ULONG cbMessageLength; // the length of this message + CONVERSATION_ID ConversationId; + } MESSAGE_HEADER; + + struct + { + MESSAGE_HEADER Header; + // MESSAGE_TYPE_INITIATOR_NEGO for the initiator, + // MESSAGE_TYPE_ACCEPTOR_NEGO for the acceptor + UCHAR Random[32]; + ULONG64 ProtocolVersion; + // version of the protocol, this contains 0 + AUTH_SCHEME_VECTOR AuthSchemes; + EXTENSION_VECTOR Extensions; + } NEGO_MESSAGE; + + struct + { + MESSAGE_HEADER Header; + // MESSAGE_TYPE_CHALLENGE for the acceptor, + // or MESSAGE_TYPE_AP_REQUEST for the initiator + // MESSAGE_TYPE_INITiATOR_META_DATA for + // the initiator metadata + // MESSAGE_TYPE_ACCEPTOR_META_DATA for + // the acceptor metadata + AUTH_SCHEME AuthScheme; + BYTE_VECTOR Exchange; + // contains the opaque handshake message for the + + + +Short, et al. Expires July 7, 2011 [Page 22] + +Internet-Draft NEGOEX January 2011 + + + // authentication scheme + } EXCHANGE_MESSAGE; + + struct + { + MESSAGE_HEADER Header; // MESSAGE_TYPE_VERIFY + AUTH_SCHEME AuthScheme; + CHECKSUM Checksum; + // contains the checksum of all the previously + // exchanged messages in the order they were sent. + } VERIFY_MESSAGE; + + struct + { + ULONG AlertType; + BYTE_VECTOR AlertValue; + } ALERT; + + // + // alert types + // + + #define ALERT_TYPE_PULSE 1 + + // + // reason codes for the heartbeat message + // + + #define ALERT_VERIFY_NO_KEY 1 + + struct + { + ULONG cbHeaderLength; + ULONG Reason; + } ALERT_PULSE; + + struct + { + ULONG AlertArrayOffset; // the element is an ALERT + USHORT AlertCount; // contains the number of alerts + } ALERT_VECTOR; + + struct + { + MESSAGE_HEADER Header; + AUTH_SCHEME AuthScheme; + ULONG ErrorCode; // an NTSTATUS code + ALERT_VECTOR Alerts; + + + +Short, et al. Expires July 7, 2011 [Page 23] + +Internet-Draft NEGOEX January 2011 + + + } ALERT_MESSAGE; + + +Authors' Addresses + + Michiko Short + Microsoft Corporation + One Microsoft Way + Redmond, WA 98052 + US + + Email: michikos@microsoft.com + + + Larry Zhu + Microsoft Corporation + One Microsoft Way + Redmond, WA 98052 + US + + Email: lzhu@microsoft.com + + + Kevin Damour + Microsoft Corporation + One Microsoft Way + Redmond, WA 98052 + US + + Email: kdamour@microsoft.com + + + Dave McPherson + Microsoft Corporation + One Microsoft Way + Redmond, WA 98052 + US + + Email: davemm@microsoft.com + + + + + + + + + + + + +Short, et al. Expires July 7, 2011 [Page 24] + + diff --git a/doc/standardisation/draft-zhu-ws-kerb-03.txt b/doc/standardisation/draft-zhu-ws-kerb-03.txt new file mode 100644 index 000000000..7b091af41 --- /dev/null +++ b/doc/standardisation/draft-zhu-ws-kerb-03.txt @@ -0,0 +1,616 @@ + + +NETWORK WORKING GROUP L. Zhu +Internet-Draft Microsoft Corporation +Updates: 4120 (if approved) J. Altman +Intended status: Standards Track Secure Endpoints +Expires: January 10, 2008 July 9, 2007 + + + Initial and Pass Through Authentication Using Kerberos V5 and the GSS- + API (IAKERB) + draft-zhu-ws-kerb-03 + +Status of this Memo + + By submitting this Internet-Draft, each author represents that any + applicable patent or other IPR claims of which he or she is aware + have been or will be disclosed, and any of which he or she becomes + aware will be disclosed, in accordance with Section 6 of BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF), its areas, and its working groups. Note that + other groups may also distribute working documents as Internet- + Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on January 10, 2008. + +Copyright Notice + + Copyright (C) The IETF Trust (2007). + +Abstract + + This document defines extensions to the Kerberos protocol and the + GSS-API Kerberos mechanism that enable a GSS-API Kerberos client to + exchange messages with the KDC using the GSS-API acceptor as the + proxy, by encapsulating the Kerberos messages inside GSS-API tokens. + With these extensions a client can obtain Kerberos tickets for + services where the KDC is not accessible to the client, but is + + + +Zhu & Altman Expires January 10, 2008 [Page 1] + +Internet-Draft IAKERB July 2007 + + + accessible to the application server. + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. Conventions Used in This Document . . . . . . . . . . . . . . 3 + 3. GSS-API Encapsulation . . . . . . . . . . . . . . . . . . . . 3 + 4. Addresses in Tickets . . . . . . . . . . . . . . . . . . . . . 7 + 5. Security Considerations . . . . . . . . . . . . . . . . . . . 7 + 6. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 8 + 7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 8 + 8. References . . . . . . . . . . . . . . . . . . . . . . . . . . 8 + 8.1. Normative References . . . . . . . . . . . . . . . . . . . 8 + 8.2. Informative references . . . . . . . . . . . . . . . . . . 9 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 9 + Intellectual Property and Copyright Statements . . . . . . . . . . 11 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Zhu & Altman Expires January 10, 2008 [Page 2] + +Internet-Draft IAKERB July 2007 + + +1. Introduction + + When authenticating using Kerberos V5, clients obtain tickets from a + KDC and present them to services. This model of operation cannot + work if the client does not have access to the KDC. For example, in + remote access scenarios, the client must initially authenticate to an + access point in order to gain full access to the network. Here the + client may be unable to directly contact the KDC either because it + does not have an IP address, or the access point packet filter does + not allow the client to send packets to the Internet before it + authenticates to the access point. + + Recent advancements in extending Kerberos permit Kerberos + authentication to complete with the assistance of a proxy. The + Kerberos [RFC4120] pre-authentication framework [KRB-PAFW] prevents + the exposure of weak client keys over the open network. The Kerberos + support of anonymity [KRB-ANON] provides for privacy and further + complicates traffic analysis. The kdc-referrals option defined in + [KRB-PAFW] may reduce the number of messages exchanged while + obtaining a ticket to exactly two even in cross-realm + authentications. + + Building upon these Kerberos extensions, this document extends + [RFC4120] and [RFC4121] such that the client can communicate with the + KDC using a Generic Security Service Application Program Interface + (GSS-API) [RFC2743] acceptor as the proxy. The GSS-API acceptor + relays the KDC request and reply messages between the client and the + KDC. The GSS-API acceptor, when relaying the Kerberos messages, is + called an IAKERB proxy. Consequently, IAKERB as defined in this + document requires the use of GSS-API. + + +2. Conventions Used in This Document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC2119]. + + +3. GSS-API Encapsulation + + The mechanism Objection Identifier (OID) for GSS-API IAKERB, in + accordance with the mechanism proposed by [RFC4178] for negotiating + protocol variations, is id-kerberos-iakerb: + + id-kerberos-iakerb ::= + { iso(1) org(3) dod(6) internet(1) security(5) kerberosV5(2) + iakerb(5) } + + + +Zhu & Altman Expires January 10, 2008 [Page 3] + +Internet-Draft IAKERB July 2007 + + + The initial context establishment token of IAKERB MUST have the + generic token framing described in section 3.1 of [RFC2743] with the + mechanism OID being id-kerberos-iakerb, and any subsequent IAKERB + context establishment token MUST NOT have this token framing. + + The client starts by constructing the ticket request, and if the + ticket request is being made to the KDC, the client, instead of + contacting the KDC directly, encapsulates the request message into + the output token of the GSS_Init_security_context() call and returns + GSS_S_CONTINUE_NEEDED [RFC2743] indicating that at least one more + token is required in order to establish the context. The output + token is then passed for use as the input token to the + GSS_Accept_sec_context() call in accordance with GSS-API. The GSS- + API acceptor extracts the Kerberos request in the input token, + locates the target KDC, and sends the request on behalf of the + client. After receiving the KDC reply, the GSS-API acceptor then + encapsulates the reply message into the output token of + GSS_Accept_sec_context(). The GSS-API acceptor returns + GSS_S_CONTINUE_NEEDED [RFC2743] indicating that at least one more + token is required in order to establish the context. The output + token is passed to the initiator in accordance with GSS-API. + + Client <---------> IAKERB proxy <---------> KDC + + The innerToken described in section 3.1 of [RFC2743] and subsequent + GSS-API mechanism tokens have the following formats: it starts with a + two-octet token-identifier (TOK_ID), followed by an IAKERB message or + a Kerberos message. + + Only one IAKERB specific message, namely the IAKERB_PROXY message, is + defined in this document. The TOK_ID values for Kerberos messages + are the same as defined in [RFC4121]. + + Token TOK_ID Value in Hex + -------------------------------------- + IAKERB_PROXY 05 01 + + The content of the IAKERB_PROXY message is defined as an IAKERB- + HEADER structure immediately followed by a Kerberos message. The + Kerberos message can be an AS-REQ, an AS-REP, a TGS-REQ, a TGS-REP, + or a KRB-ERROR as defined in [RFC4120]. + + + + + + + + + + +Zhu & Altman Expires January 10, 2008 [Page 4] + +Internet-Draft IAKERB July 2007 + + + IAKERB-HEADER ::= SEQUENCE { + target-realm [1] UTF8String, + -- The name of the target realm. + cookie [2] OCTET STRING OPTIONAL, + -- Opaque data, if sent by the server, + -- MUST be copied by the client verbatim into + -- the next IAKRB_PROXY message. + ... + } + + The IAKERB-HEADER structure and all the Kerberos messages MUST be + encoded using Abstract Syntax Notation One (ASN.1) Distinguished + Encoding Rules (DER) [X680] [X690]. + + The IAKERB client fills out the IAKERB-HEADER structure as follows: + the target-realm contains the realm name the ticket request is + addressed to. In the initial message from the client, the cookie + field is absent. The client MUST specify a target-realm. If the + client does not know the realm of the client's true principal name + [REFERALS], it MUST specify a realm it knows. This can be the realm + of the client's host. + + Upon receipt of the IAKERB_PROXY message, the GSS-API acceptor + inspects the target-realm field in the IAKERB_HEADER, and locates a + KDC of that realm, and sends the ticket request to that KDC. + + When the GSS-API acceptor is unable to obtain an IP address for a KDC + in the client's realm, it sends a KRB_ERROR message with the code + KRB_AP_ERR_IAKERB_KDC_NOT_FOUND to the client and the context fails + to establish. There is no accompanying error data defined in this + document for this error code. + + KRB_AP_ERR_IAKERB_KDC_NOT_FOUND 85 + -- The IAKERB proxy could not find a KDC. + + When the GSS-API acceptor has an IP address for a KDC in the client + realm, but does not receive a response from any KDC in the realm + (including in response to retries), it sends a KRB_ERROR message with + the code KRB_AP_ERR_IAKERB_KDC_NO_RESPONSE to the client and the + context fails to establish. There is no accompanying error data + defined in this document for this error code. + + KRB_AP_ERR_IAKERB_KDC_NO_RESPONSE 86 + -- The KDC did not respond to the IAKERB proxy. + + The IAKERB proxy can send opaque data in the cookie field of the + IAKERB-HEADER structure in the server reply to the client, in order + to, for example, minimize the amount of state information kept by the + + + +Zhu & Altman Expires January 10, 2008 [Page 5] + +Internet-Draft IAKERB July 2007 + + + GSS-API acceptor. The content and the encoding of the cookie field + is a local matter of the IAKERB proxy. The client MUST copy the + cookie verbatim from the previous server response whenever the cookie + is present into the subsequent tokens that contains an IAKERB_PROXY + message. + + When the client obtained a service ticket, the client sends a + KRB_AP_REQ message to the server, and performs the client-server + application exchange as defined in [RFC4120] and [RFC4121]. + + For implementations comforming to this specification, the + authenticator subkey in the AP-REQ MUST alway be present, and the + Exts field in the GSS-API authenticator [GSS-EXTS] MUST contain an + extension of the type GSS_EXTS_IAKERB_FINISHED and the extension data + contains the ASN.1 DER encoding of the structure IAKERB-FINISHED. + + GSS_EXTS_IAKERB_FINISHED TBD + --- Data type for the IAKERB checksum. + + IAKERB-FINISHED ::= { + iakerb-messages [1] Checksum, + -- Contains the checksum of the GSS-API tokens + -- exchanged between the initiator and the acceptor, + -- and prior to the containing AP_REQ GSS-API token. + -- The checksum is performed over the GSS-API tokens + -- in the order that the tokens were sent. + ... + } + + The iakerb-messages field in the IAKERB-FINISHED structure contains a + checksum of all the GSS-API tokens exchanged between the initiator + and the acceptor, and prior to the GSS-API token containing the + AP_REQ. This checksum is performed over these GSS-API tokens in the + order that the tokens were sent. In the parlance of [RFC3961], the + checksum type is the required checksum type for the enctype of the + subkey in the authenticator, the protocol key for the checksum + operation is the authenticator subkey, and the key usage number is + KEY_USAGE_IAKERB_FINISHED. + + KEY_USAGE_IAKERB_FINISHED 42 + + The GSS-API acceptor MUST then verify the checksum contained in the + GSS_EXTS_IAKERB_FINISHED extension. This checksum provides integrity + protection for the messages exchanged including the unauthenticated + clear texts in the IAKERB-HEADER structure. + + If the pre-authentication data is encrypted in the long-term + password-based key of the principal, the risk of security exposures + + + +Zhu & Altman Expires January 10, 2008 [Page 6] + +Internet-Draft IAKERB July 2007 + + + is significant. Implementations SHOULD provide the AS_REQ armoring + as defined in [KRB-PAFW] unless an alternative protection is + deployed. In addition, the anonymous Kerberos FAST option is + RECOMMENDED for the client to complicate traffic analysis. + + +4. Addresses in Tickets + + In IAKERB, the machine sending requests to the KDC is the GSS-API + acceptor and not the client. As a result, the client should not + include its addresses in any KDC requests for two reasons. First, + the KDC may reject the forwarded request as being from the wrong + client. Second, in the case of initial authentication for a dial-up + client, the client machine may not yet possess a network address. + Hence, as allowed by [RFC4120], the addresses field of the AS-REQ and + TGS-REQ requests SHOULD be blank and the caddr field of the ticket + SHOULD similarly be left blank. + + +5. Security Considerations + + A typical IAKERB client sends the AS_REQ with pre-authentication data + encrypted in the long-term keys of the user before the server is + authenticated. This enables offline attacks by un-trusted servers. + To mitigate this threat, the client SHOULD use Kerberos + FAST[KRB-PAFW] and require KDC authentication to protect the user's + credentials. + + The client name is in clear text in the authentication exchange + messages and ticket granting service exchanges according to [RFC4120] + whereas the client name is encrypted in client- server application + exchange messages. By using the IAKERB proxy to relay the ticket + requests and responses, the client's identity could be revealed in + the client-server traffic where the same identity could have been + concealed if IAKERB were not used. Hence, to complicate traffic + analysis and provide privacy for the IAKERB client, the IAKERB client + SHOULD request the anonymous Kerberos FAST option [KRB-PAFW]. + + Similar to other network access protocols, IAKERB allows an + unauthenticated client (possibly outside the security perimeter of an + organization) to send messages that are proxied to interior servers. + + In a scenario where DNS SRV RR's are being used to locate the KDC, + IAKERB is being used, and an external attacker can modify DNS + responses to the IAKERB proxy, there are several countermeasures to + prevent arbitrary messages from being sent to internal servers: + + + + + +Zhu & Altman Expires January 10, 2008 [Page 7] + +Internet-Draft IAKERB July 2007 + + + 1. KDC port numbers can be statically configured on the IAKERB + proxy. In this case, the messages will always be sent to KDC's. + For an organization that runs KDC's on a static port (usually + port 88) and does not run any other servers on the same port, + this countermeasure would be easy to administer and should be + effective. + + 2. The proxy can do application level sanity checking and filtering. + This countermeasure should eliminate many of the above attacks. + + 3. DNS security can be deployed. This countermeasure is probably + overkill for this particular problem, but if an organization has + already deployed DNS security for other reasons, then it might + make sense to leverage it here. Note that Kerberos could be used + to protect the DNS exchanges. The initial DNS SRV KDC lookup by + the proxy will be unprotected, but an attack here is at most a + denial of service (the initial lookup will be for the proxy's KDC + to facilitate Kerberos protection of subsequent DNS exchanges + between itself and the DNS server). + + +6. Acknowledgements + + Jonathan Trostle, Michael Swift, Bernard Aboba and Glen Zorn wrote + earlier revision of this document. + + The hallway conversations between Larry Zhu and Nicolas Williams + formed the basis of this document. + + +7. IANA Considerations + + There is no IANA action required for this document. + + +8. References + +8.1. Normative References + + [GSS-EXTS] + Emery, S., "Kerberos Version 5 GSS-API Channel Binding + Hash Agility", + draft-ietf-krb-wg-gss-cb-hash-agility-03.txt (work in + progress), 2007. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + + + +Zhu & Altman Expires January 10, 2008 [Page 8] + +Internet-Draft IAKERB July 2007 + + + [RFC2743] Linn, J., "Generic Security Service Application Program + Interface Version 2, Update 1", RFC 2743, January 2000. + + [RFC3961] Raeburn, K., "Encryption and Checksum Specifications for + Kerberos 5", RFC 3961, February 2005. + + [RFC4120] Neuman, C., Yu, T., Hartman, S., and K. Raeburn, "The + Kerberos Network Authentication Service (V5)", RFC 4120, + July 2005. + + [RFC4121] Zhu, L., Jaganathan, K., and S. Hartman, "The Kerberos + Version 5 Generic Security Service Application Program + Interface (GSS-API) Mechanism: Version 2", RFC 4121, + July 2005. + + [RFC4178] Zhu, L., Leach, P., Jaganathan, K., and W. Ingersoll, "The + Simple and Protected Generic Security Service Application + Program Interface (GSS-API) Negotiation Mechanism", + RFC 4178, October 2005. + +8.2. Informative references + + [KRB-ANON] + Zhu, L. and P. Leach, "Kerberos Anonymity Support", + draft-ietf-krb-wg-anon-04.txt (work in progress), 2007. + + [KRB-PAFW] + Zhu, L. and S. Hartman, "A Generalized Framework for + Kerberos Pre-Authentication", + draft-ietf-krb-wg-preauth-framework-06.txt (work in + progress), 2007. + + +Authors' Addresses + + Larry Zhu + Microsoft Corporation + One Microsoft Way + Redmond, WA 98052 + US + + Email: lzhu@microsoft.com + + + + + + + + + +Zhu & Altman Expires January 10, 2008 [Page 9] + +Internet-Draft IAKERB July 2007 + + + Jeffery Altman + Secure Endpoints + 255 W 94th St + New York, NY 10025 + US + + Email: jaltman@secure-endpoints.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Zhu & Altman Expires January 10, 2008 [Page 10] + +Internet-Draft IAKERB July 2007 + + +Full Copyright Statement + + Copyright (C) The IETF Trust (2007). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND + THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at + ietf-ipr@ietf.org. + + +Acknowledgment + + Funding for the RFC Editor function is provided by the IETF + Administrative Support Activity (IASA). + + + + + +Zhu & Altman Expires January 10, 2008 [Page 11] + + diff --git a/doc/standardisation/rfc4043.txt b/doc/standardisation/rfc4043.txt new file mode 100644 index 000000000..c31b30d88 --- /dev/null +++ b/doc/standardisation/rfc4043.txt @@ -0,0 +1,843 @@ + + + + + + +Network Working Group D. Pinkas +Request for Comments: 4043 Bull +Category: Standards Track T. Gindin + IBM + May 2005 + + + Internet X.509 Public Key Infrastructure + Permanent Identifier + +Status of This Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2005). + +Abstract + + This document defines a new form of name, called permanent + identifier, that may be included in the subjectAltName extension of a + public key certificate issued to an entity. + + The permanent identifier is an optional feature that may be used by a + CA to indicate that two or more certificates relate to the same + entity, even if they contain different subject name (DNs) or + different names in the subjectAltName extension, or if the name or + the affiliation of that entity stored in the subject or another name + form in the subjectAltName extension has changed. + + The subject name, carried in the subject field, is only unique for + each subject entity certified by the one CA as defined by the issuer + name field. However, the new name form can carry a name that is + unique for each subject entity certified by a CA. + + + + + + + + + + + + +Pinkas & Gindin Standards Track [Page 1] + +RFC 4043 Permanent Identifier May 2005 + + +Table of Contents + + 1. Introduction.................................................. 2 + 2. Definition of a Permanent Identifier.......................... 3 + 3. IANA Considerations........................................... 6 + 4. Security Considerations....................................... 6 + 5. References.................................................... 7 + 5.1. Normative References.................................... 7 + 5.2. Informative References.................................. 8 + Appendix A. ASN.1 Syntax.......................................... 9 + A.1. 1988 ASN.1 Module....................................... 9 + A.2. 1993 ASN.1 Module....................................... 10 + Appendix B. OID's for organizations............................... 11 + B.1. Using IANA (Internet Assigned Numbers Authority)........ 11 + B.2. Using an ISO Member Body................................ 12 + B.3. Using an ICD (International Code Designator) From + British Standards Institution to Specify a New or + an Existing Identification Scheme....................... 12 + Authors' Addresses................................................ 14 + Full Copyright Statement.......................................... 15 + +1. Introduction + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC2119]. + + This specification is based on [RFC3280], which defines underlying + certificate formats and semantics needed for a full implementation of + this standard. + + The subject field of a public key certificate identifies the entity + associated with the public key stored in the subject public key + field. Names and identities of a subject may be carried in the + subject field and/or the subjectAltName extension. Where subject + field is non-empty, it MUST contain an X.500 distinguished name (DN). + The DN MUST be unique for each subject entity certified by a single + CA as defined by the issuer name field. + + The subject name changes whenever any of the components of that name + gets changed. There are several reasons for such a change to happen. + + For employees of a company or organization, the person may get a + different position within the same company and thus will move from + one organization unit to another one. Including the organization + unit in the name may however be very useful to allow the relying + parties (RP's) using that certificate to identify the right + individual. + + + +Pinkas & Gindin Standards Track [Page 2] + +RFC 4043 Permanent Identifier May 2005 + + + For citizens, an individual may change their name by legal + processes, especially as a result of marriage. + + Any certificate subject identified by geographical location may + relocate and change at least some of the location attributes + (e.g., country name, state or province, locality, or street). + + A permanent identifier consists of an identifier value assigned + within a given naming space by the organization which is + authoritative for that naming space. The organization assigning the + identifier value may be the CA that has issued the certificate or a + different organization called an Assigner Authority. + + An Assigner Authority may be a government, a government agency, a + corporation, or any other sort of organization. It MUST have a + unique identifier to distinguish it from any other such authority. + In this standard, that identifier MUST be an object identifier. + + A permanent identifier may be useful in three contexts: access + control, non-repudiation and audit records. + + For access control, the permanent identifier may be used in an ACL + (Access Control List) instead of the DN or any other form of name + and would not need to be changed, even if the subject name of the + entity changes. For non-repudiation, the permanent identifier may + be used to link different transactions to the same entity, even + when the subject name of the entity changes. + + For audit records, the permanent identifier may be used to link + different audit records to the same entity, even when the subject + name of the entity changes. + + For two certificates which have been both verified to be valid + according to a given validation policy and which contain a permanent + identifier, those certificates relate to the same entity if their + permanent identifiers match, whatever the content of the DN or other + subjectAltName components may be. + + Since the use of permanent identifiers may conflict with privacy, CAs + SHOULD advertise to purchasers of certificates the use of permanent + identifiers in certificates. + +2. Definition of a Permanent Identifier + + This Permanent Identifier is a name defined as a form of otherName + from the GeneralName structure in SubjectAltName, as defined in + [X.509] and [RFC3280]. + + + + +Pinkas & Gindin Standards Track [Page 3] + +RFC 4043 Permanent Identifier May 2005 + + + A CA which includes a permanent identifier in a certificate is + certifying that any public key certificate containing the same values + for that identifier refers to the same entity. + + The use of a permanent identifier is OPTIONAL. The permanent + identifier is defined as follows: + + id-on-permanentIdentifier OBJECT IDENTIFIER ::= { id-on 3 } + PermanentIdentifier ::= SEQUENCE { + identifierValue UTF8String OPTIONAL, + -- if absent, use a serialNumber attribute, + -- if there is such an attribute present + -- in the subject DN + assigner OBJECT IDENTIFIER OPTIONAL + -- if absent, the assigner is + -- the certificate issuer + } + + The identifierValue field is optional. + + When the identifierValue field is present, then the + identifierValue supports one syntax: UTF8String. + + When the identifierValue field is absent, then the value of the + serialNumber attribute (as defined in section 5.2.9 of [X.520]) + from the deepest RDN of the subject DN is the value to be taken + for the identifierValue. In such a case, there MUST be at least + one serialNumber attribute in the subject DN, otherwise the + PermanentIdentifier SHALL NOT be used. + + The assigner field is optional. + + When the assigner field is present, then it is an OID which + identifies a naming space, i.e., both an Assigner Authority and + the type of that field. Characteristically, the prefix of the OID + identifies the Assigner Authority, and a suffix is used to + identify the type of permanent identifier. + + When the assigner field is absent, then the permanent identifier + is locally unique to the CA. + + The various combinations are detailed below: + + 1. Both the assigner and the identifierValue fields are present: + + The identifierValue is the value for that type of identifier. The + assigner field identifies the Assigner Authority and the type of + permanent identifier being identified. + + + +Pinkas & Gindin Standards Track [Page 4] + +RFC 4043 Permanent Identifier May 2005 + + + The permanent identifier is globally unique among all CAs. In + such a case, two permanent identifiers of this type match if and + only if their assigner fields match and the contents of the + identifierValue field in the two permanent identifiers consist of + the same Unicode code points presented in the same order. + + 2. The assigner field is absent and the identifierValue field is + present: + + The Assigner Authority is the CA that has issued the certificate. + The identifierValue is given by the CA and the permanent + identifier is only local to the CA that has issued the + certificate. + + In such a case, two permanent identifiers of this type match if + and only if the issuer DN's in the certificates which contain them + match using the distinguishedNameMatch rule, as defined in X.501, + and the two values of the identifierValue field consist of the + same Unicode code points presented in the same order. + + 3. Both the assigner and the identifierValue fields are absent: + + If there are one or more RDNs containing a serialNumber attribute + (alone or accompanied by other attributes), then the value + contained in the serialNumber of the deepest such RDN SHALL be + used as the identifierValue; otherwise, the Permanent Identifier + definition is invalid and the Permanent Identifier SHALL NOT be + used. + + The permanent identifier is only local to the CA that has issued + the certificate. In such a case, two permanent identifiers of + this type match if and only if the issuer DN's in the certificates + which contain them match and the serialNumber attributes within + the subject DN's of those same certificates also match using the + caseIgnoreMatch rule. + + 4. The assigner field is present and the identifierValue field is + absent: + + If there are one or more RDNs containing a serialNumber attribute + (alone or accompanied by other attributes), then the value + contained in the serialNumber of the deepest such RDN SHALL be + used as the identifierValue; otherwise, the Permanent Identifier + definition is invalid and the Permanent Identifier SHALL NOT be + used. + + The assigner field identifies the Assigner Authority and the type + of permanent identifier being identified. + + + +Pinkas & Gindin Standards Track [Page 5] + +RFC 4043 Permanent Identifier May 2005 + + + The permanent identifier is globally unique among all CAs. In + such a case, two permanent identifiers of this type match if and + only if their assigner fields match and the contents of the + serialNumber attributes within the subject DN's of those same + certificates match using the caseIgnoreMatch rule. + + Note: The full arc of the object identifier used to identify the + permanent identifier name form is derived using: + + id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) + dod(6) internet(1) security(5) mechanisms(5) pkix(7) } + + id-on OBJECT IDENTIFIER ::= { id-pkix 8 } -- other name forms + +3. IANA Considerations + + No IANA actions are necessary. However, a Private Enterprise Number + may be used to construct an OID for the assigner field (see Annex + B.1.). + +4. Security Considerations + + A given entity may have at an instant of time or at different + instants of time multiple forms of identities. If the permanent + identifier is locally unique to the CA (i.e., the assigner field is + not present), then two certificates from the same CA can be compared. + + When two certificates contain identical permanent identifiers, then a + relying party may determine that they refer to the same entity. + + If the permanent identifier is globally unique among all CAs (i.e., + the assigner field is present), then two certificates from different + CAs can be compared. When they contain two identical permanent + identifiers, then a relying party may determine that they refer to + the same entity. It is the responsibility of the CA to verify that + the permanent identifier being included in the certificate refers to + the subject being certified. + + The permanent identifier identifies the entity, irrespective of any + attribute extension. When a public key certificate contains + attribute extensions, the permanent identifier, if present, should + not be used for access control purposes but only for audit purposes. + The reason is that since these attributes may change, access could be + granted on attributes that were originally present in a certificate + issued to that entity but are no longer present in the current + certificate. + + + + + +Pinkas & Gindin Standards Track [Page 6] + +RFC 4043 Permanent Identifier May 2005 + + + Subject names in certificates are chosen by the issuing CA and are + mandated to be unique for each CA; so there can be no name collision + between subject names from the same CA. Such a name may be an end- + entity name when the certificate is a leaf certificate, or a CA name, + when it is a CA certificate. + + Since a name is only unique towards its superior CA, unless some + naming constraints are being used, a name would only be guaranteed to + be globally unique when considered to include a sequence of all the + names of the superior CAs. Thus, two certificates that are issued + under the same issuer DN and which contain the same permanent + identifier extension without an assigner field do not necessarily + refer to the same entity. + + Additional checks need to be done, e.g., to check if the public key + values of the two CAs which have issued the certificates to be + compared are identical or if the sequence of CA names in the + certification path from the trust anchor to the CA are identical. + + When the above checks fail, the permanent identifiers may still match + if there has been a CA key rollover. In such a case the checking is + more complicated. + + The certification of different CAs with the same DN by different CAs + has other negative consequences in various parts of the PKI, notably + rendering the IssuerAndSerialNumber structure in [RFC3852] section + 10.2.4 ambiguous. + + The permanent identifier allows organizations to create links between + different certificates associated with an entity issued with or + without overlapping validity periods. This ability to link different + certificates may conflict with privacy. It is therefore important + that a CA clearly disclose any plans to issue certificates which + include a permanent identifier to potential subjects of those + certificates. + +5. References + +5.1. Normative References + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC3280] Housley, R., Polk, W., Ford, W., and D. Solo, "Internet + X.509 Public Key Infrastructure Certificate and + Certificate Revocation List (CRL) Profile", RFC 3280, + April 2002. + + + + +Pinkas & Gindin Standards Track [Page 7] + +RFC 4043 Permanent Identifier May 2005 + + + [UTF-8] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", STD 63, RFC 3629, November 2003. + + [X.501] ITU-T Rec X.501 | ISO 9594-2: 2001: Information technology + - Open Systems Interconnection - The Directory: Models, + February 2001. + +5.2. Informative References + + [RFC3852] Housley, R., "Cryptographic Message Syntax (CMS)", RFC + 3852, July 2004. + + [X.509] ITU-T Recommendation X.509 (1997 E): Information + Technology - Open Systems Interconnection - The Directory: + Authentication Framework, June 1997. + + [X.520] ITU-T Recommendation X.520: Information Technology - Open + Systems Interconnection - The Directory: Selected + Attribute Types, June 1997. + + [X.660] ITU-T Recommendation X.660: Information Technology - Open + Systems Interconnection - Procedures for the Operation of + OSI Registration Authorities: General Procedures, 1992. + + [X.680] ITU-T Recommendation X.680: Information Technology - + Abstract Syntax Notation One, 1997. + + + + + + + + + + + + + + + + + + + + + + + + + +Pinkas & Gindin Standards Track [Page 8] + +RFC 4043 Permanent Identifier May 2005 + + +Appendix A. ASN.1 Syntax + + As in RFC 2459, ASN.1 modules are supplied in two different variants + of the ASN.1 syntax. + + This section describes data objects used by conforming PKI components + in an "ASN.1-like" syntax. This syntax is a hybrid of the 1988 and + 1993 ASN.1 syntaxes. The 1988 ASN.1 syntax is augmented with 1993 + the UNIVERSAL Type UTF8String. + + The ASN.1 syntax does not permit the inclusion of type statements in + the ASN.1 module, and the 1993 ASN.1 standard does not permit use of + the new UNIVERSAL types in modules using the 1988 syntax. As a + result, this module does not conform to either version of the ASN.1 + standard. + + Appendix A.1 may be parsed by an 1988 ASN.1-parser by replacing the + definitions for the UNIVERSAL Types with the 1988 catch-all "ANY". + + Appendix A.2 may be parsed "as is" by an 1997-compliant ASN.1 parser. + + In case of discrepancies between these modules, the 1988 module is + the normative one. + +Appendix A.1. 1988 ASN.1 Module + + PKIXpermanentidentifier88 {iso(1) identified-organization(3) dod(6) + internet(1) security(5) mechanisms(5) pkix(7) id-mod(0) + id-mod-perm-id-88(28) } + + DEFINITIONS EXPLICIT TAGS ::= + + BEGIN + + -- EXPORTS ALL -- + + IMPORTS + + -- UTF8String, / move hyphens before slash if UTF8String does not + -- resolve with your compiler + -- The content of this type conforms to [UTF-8]. + + id-pkix + FROM PKIX1Explicit88 { iso(1) identified-organization(3) + dod(6) internet(1) security(5) mechanisms(5) pkix(7) + id-mod(0) id-pkix1-explicit(18) } ; + -- from [RFC3280] + + + + +Pinkas & Gindin Standards Track [Page 9] + +RFC 4043 Permanent Identifier May 2005 + + + -- Permanent identifier Object Identifier and Syntax + + id-on OBJECT IDENTIFIER ::= { id-pkix 8 } + + id-on-permanentIdentifier OBJECT IDENTIFIER ::= { id-on 3 } + + PermanentIdentifier ::= SEQUENCE { + identifierValue UTF8String OPTIONAL, + -- if absent, use the serialNumber attribute + -- if there is a single such attribute present + -- in the subject DN + assigner OBJECT IDENTIFIER OPTIONAL + -- if absent, the assigner is + -- the certificate issuer + } + + END + +Appendix A.2. 1993 ASN.1 Module + +PKIXpermanentidentifier93 {iso(1) identified-organization(3) dod(6) + internet(1) security(5) mechanisms(5) pkix(7) id-mod(0) + id-mod-perm-id-93(29) } + + DEFINITIONS EXPLICIT TAGS ::= + + BEGIN + + -- EXPORTS ALL -- + + IMPORTS + + id-pkix + FROM PKIX1Explicit88 { iso(1) identified-organization(3) + dod(6) internet(1) security(5) mechanisms(5) pkix(7) + id-mod(0) id-pkix1-explicit(18) } + -- from [RFC3280] + + ATTRIBUTE + FROM InformationFramework {joint-iso-itu-t ds(5) module(1) + informationFramework(1) 4}; + -- from [X.501] + + -- Permanent identifier Object Identifiers + + id-on OBJECT IDENTIFIER ::= { id-pkix 8 } + + id-on-permanentIdentifier OBJECT IDENTIFIER ::= { id-on 3 } + + + +Pinkas & Gindin Standards Track [Page 10] + +RFC 4043 Permanent Identifier May 2005 + + + -- Permanent Identifier + + permanentIdentifier ATTRIBUTE ::= { + WITH SYNTAX PermanentIdentifier + ID id-on-permanentIdentifier } + + PermanentIdentifier ::= SEQUENCE { + identifierValue UTF8String OPTIONAL, + -- if absent, use the serialNumber attribute + -- if there is a single such attribute present + -- in the subject DN + assigner OBJECT IDENTIFIER OPTIONAL + -- if absent, the assigner is + -- the certificate issuer +} + +END + +Appendix B. OID's for Organizations + + In order to construct an OID for the assigner field, organizations + need first to have a registered OID for themselves. Such an OID must + be obtained from a registration authority following [X.660]. In some + cases, OID's are provided for free. In other cases a one-time fee is + required. The main difference lies in the nature of the information + that is collected at the time of registration and how this + information is verified for its accuracy. + +Appendix B.1. Using IANA (Internet Assigned Numbers Authority) + + The application form for a Private Enterprise Number in the IANA's + OID list is: http://www.iana.org/cgi-bin/enterprise.pl. + + Currently, IANA assigns numbers for free. The IANA-registered + Private Enterprises prefix is: + iso.org.dod.internet.private.enterprise (1.3.6.1.4.1) + + These numbers are used, among other things, for defining private SNMP + MIBs. + + The official assignments under this OID are stored in the IANA file + "enterprise-numbers" available at: + http://www.iana.org/assignments/enterprise-numbers + + + + + + + + +Pinkas & Gindin Standards Track [Page 11] + +RFC 4043 Permanent Identifier May 2005 + + +Appendix B.2. Using an ISO Member Body + + ISO has defined the OID structure in a such a way so that every ISO + member-body has its own unique OID. Then every ISO member-body is + free to allocate its own arc space below. + + Organizations and enterprises may contact the ISO member-body where + their organization or enterprise is established to obtain an + organization/enterprise OID. + + Currently, ISO members do not assign organization/enterprise OID's + for free. + + Most of them do not publish registries of such OID's which they have + assigned, sometimes restricting the access to registered + organizations or preferring to charge inquirers for the assignee of + an OID on a per-inquiry basis. The use of OID's from an ISO member + organization which does not publish such a registry may impose extra + costs on the CA that needs to make sure that the OID corresponds to + the registered organization. + + As an example, AFNOR (Association Francaise de Normalisation - the + French organization that is a member of ISO) has defined an arc to + allocate OID's for companies: + + {iso (1) member-body (2) fr (250) type-org (1) organisation (n)} + +Appendix B.3. Using an ICD (International Code Designator) From British + Standards Institution to Specify a New or an Existing + Identification Scheme + + The International Code Designator (ICD) is used to uniquely identify + an ISO 6523 compliant organization identification scheme. ISO 6523 + is a standard that defines the proper structure of an identifier and + the registration procedure for an ICD. The conjunction of the ICD + with an identifier issued by the registration authority is worldwide + unique. + + The basic structure of the code contains the following components: + + - the ICD value: The International Code Designator issued to the + identification scheme makes the identifier worldwide unique (up to + 4 digits), + + - the Organization, usually a company or governmental body (up to 35 + characters), + + + + + +Pinkas & Gindin Standards Track [Page 12] + +RFC 4043 Permanent Identifier May 2005 + + + - an Organization Part (OPI - Organization Part Identifier). An + identifier allocated to a particular Organization Part (optional, + up to 35 characters) + + The ICD is also equivalent to an object identifier (OID) under the + arc {1(iso). 3(identified organization)}. + + On behalf of ISO, British Standards Institution (BSI) is the + Registration Authority for organizations under the arc {iso (1) + org(3)}. This means BSI registers code issuing authorities + (organizations) by ICD values which are equivalent to OIDs of the + form {iso (1) org(3) icd(xxxx)}. The corresponding IdentifierValue + is the code value of the scheme identified by icd(xxxx). + + As an example, the ICD 0012 was allocated to European Computer + Manufacturers Association: ECMA. Thus the OID for ECMA is {iso(1) + org(3) ecma(12)}. + + For registration with BSI, a "Sponsoring Authority" has to vouch for + the Applying organization. Registration is not free. Recognized + "Sponsoring Authorities" are: ISO Technical Committees or + (Sub)Committees, Member Bodies of ISO or International Organizations + having a liaison status with ISO or with any of its Technical + (Sub)Committees. + + An example of a Sponsoring Authority is the EDIRA Association (EDI/EC + Registration Authority, web: http://www.edira.org, + email:info@edira.org). + + The numerical list of all ICDs that have been issued is posted on its + webpage: http://www.edira.org/documents.htm#icd-List + + Note: IANA owns ICD code 0090, but (presumably) it isn't intending to + use it for the present purpose. + + + + + + + + + + + + + + + + + +Pinkas & Gindin Standards Track [Page 13] + +RFC 4043 Permanent Identifier May 2005 + + +Authors' Addresses + + Denis Pinkas + Bull + Rue Jean-Jaures BP 68 + 78340 Les Clayes-sous-Bois + FRANCE + + EMail: Denis.Pinkas@bull.net + + + Thomas Gindin + IBM Corporation + 6710 Rockledge Drive + Bethesda, MD 20817 + USA + + EMail: tgindin@us.ibm.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Pinkas & Gindin Standards Track [Page 14] + +RFC 4043 Permanent Identifier May 2005 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2005). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE + INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at ietf- + ipr@ietf.org. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + +Pinkas & Gindin Standards Track [Page 15] + diff --git a/doc/standardisation/rfc4108.txt b/doc/standardisation/rfc4108.txt new file mode 100644 index 000000000..8119548a9 --- /dev/null +++ b/doc/standardisation/rfc4108.txt @@ -0,0 +1,3419 @@ + + + + + + +Network Working Group R. Housley +Request for Comments: 4108 Vigil Security +Category: Standards Track August 2005 + + + Using Cryptographic Message Syntax (CMS) to Protect Firmware Packages + +Status of This Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2005). + +Abstract + + This document describes the use of the Cryptographic Message Syntax + (CMS) to protect firmware packages, which provide object code for one + or more hardware module components. CMS is specified in RFC 3852. A + digital signature is used to protect the firmware package from + undetected modification and to provide data origin authentication. + Encryption is optionally used to protect the firmware package from + disclosure, and compression is optionally used to reduce the size of + the protected firmware package. A firmware package loading receipt + can optionally be generated to acknowledge the successful loading of + a firmware package. Similarly, a firmware package load error report + can optionally be generated to convey the failure to load a firmware + package. + + + + + + + + + + + + + + + + + + +Housley Standards Track [Page 1] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + +Table of Contents + + 1. Introduction ....................................................3 + 1.1. Terminology ................................................5 + 1.2. Architectural Elements .....................................5 + 1.2.1. Hardware Module Requirements ........................7 + 1.2.2. Firmware Package Requirements .......................8 + 1.2.3. Bootstrap Loader Requirements .......................9 + 1.2.3.1. Legacy Stale Version Processing ...........11 + 1.2.3.2. Preferred Stale Version Processing ........12 + 1.2.4. Trust Anchors ......................................12 + 1.2.5. Cryptographic and Compression Algorithm + Requirements .......................................13 + 1.3. Hardware Module Security Architecture .....................14 + 1.4. ASN.1 Encoding ............................................14 + 1.5. Protected Firmware Package Loading ........................15 + 2. Firmware Package Protection ....................................15 + 2.1. Firmware Package Protection CMS Content Type Profile ......18 + 2.1.1. ContentInfo ........................................18 + 2.1.2. SignedData .........................................18 + 2.1.2.1. SignerInfo ................................19 + 2.1.2.2. EncapsulatedContentInfo ...................20 + 2.1.3. EncryptedData ......................................20 + 2.1.3.1. EncryptedContentInfo ......................21 + 2.1.4. CompressedData .....................................21 + 2.1.4.1. EncapsulatedContentInfo ...................22 + 2.1.5. FirmwarePkgData ....................................22 + 2.2. Signed Attributes .........................................22 + 2.2.1. Content Type .......................................23 + 2.2.2. Message Digest .....................................24 + 2.2.3. Firmware Package Identifier ........................24 + 2.2.4. Target Hardware Module Identifiers .................25 + 2.2.5. Decrypt Key Identifier .............................26 + 2.2.6. Implemented Crypto Algorithms ......................26 + 2.2.7. Implemented Compression Algorithms .................27 + 2.2.8. Community Identifiers ..............................27 + 2.2.9. Firmware Package Information .......................29 + 2.2.10. Firmware Package Message Digest ...................30 + 2.2.11. Signing Time ......................................30 + 2.2.12. Content Hints .....................................31 + 2.2.13. Signing Certificate ...............................31 + 2.3. Unsigned Attributes .......................................32 + 2.3.1. Wrapped Firmware Decryption Key ....................33 + 3. Firmware Package Load Receipt ..................................34 + 3.1. Firmware Package Load Receipt CMS Content Type Profile ....36 + 3.1.1. ContentInfo ........................................36 + + + + + +Housley Standards Track [Page 2] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + 3.1.2. SignedData .........................................36 + 3.1.2.1. SignerInfo ................................37 + 3.1.2.2. EncapsulatedContentInfo ...................38 + 3.1.3. FirmwarePackageLoadReceipt .........................38 + 3.2. Signed Attributes .........................................40 + 3.2.1. Content Type .......................................40 + 3.2.2. Message Digest .....................................40 + 3.2.3. Signing Time .......................................40 + 4. Firmware Package Load Error ....................................41 + 4.1. Firmware Package Load Error CMS Content Type Profile ......42 + 4.1.1. ContentInfo ........................................42 + 4.1.2. SignedData .........................................43 + 4.1.2.1. SignerInfo ................................43 + 4.1.2.2. EncapsulatedContentInfo ...................43 + 4.1.3. FirmwarePackageLoadError ...........................43 + 4.2. Signed Attributes .........................................49 + 4.2.1. Content Type .......................................49 + 4.2.2. Message Digest .....................................49 + 4.2.3. Signing Time .......................................50 + 5. Hardware Module Name ...........................................50 + 6. Security Considerations ........................................51 + 6.1. Cryptographic Keys and Algorithms .........................51 + 6.2. Random Number Generation ..................................51 + 6.3. Stale Firmware Package Version Number .....................52 + 6.4. Community Identifiers .....................................53 + 7. References .....................................................54 + 7.1. Normative References ......................................54 + 7.2. Informative References ....................................54 + Appendix A: ASN.1 Module ..........................................56 + +1. Introduction + + This document describes the use of the Cryptographic Message Syntax + (CMS) [CMS] to protect firmware packages. This document also + describes the use of CMS for receipts and error reports for firmware + package loading. The CMS is a data protection encapsulation syntax + that makes use of ASN.1 [X.208-88, X.209-88]. The protected firmware + package can be associated with any particular hardware module; + however, this specification was written with the requirements of + cryptographic hardware modules in mind, as these modules have strong + security requirements. + + The firmware package contains object code for one or more + programmable components that make up the hardware module. The + firmware package, which is treated as an opaque binary object, is + digitally signed. Optional encryption and compression are also + supported. When all three are used, the firmware package is + compressed, then encrypted, and then signed. Compression simply + + + +Housley Standards Track [Page 3] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + reduces the size of the firmware package, allowing more efficient + processing and transmission. Encryption protects the firmware + package from disclosure, which allows transmission of sensitive + firmware packages over insecure links. The encryption algorithm and + mode employed may also provide integrity, protecting the firmware + package from undetected modification. The encryption protects + proprietary algorithms, classified algorithms, trade secrets, and + implementation techniques. The digital signature protects the + firmware package from undetected modification and provides data + origin authentication. The digital signature allows the hardware + module to confirm that the firmware package comes from an acceptable + source. + + If encryption is used, the firmware-decryption key must be made + available to the hardware module via a secure path. The key might be + delivered via physical media or via an independent electronic path. + One optional mechanism for distributing the firmware-decryption key + is specified in Section 2.3.1, but any secure key distribution + mechanism is acceptable. + + The signature verification public key must be made available to the + hardware module in a manner that preserves its integrity and confirms + its source. CMS supports the transfer of certificates, and this + facility can be used to transfer a certificate that contains the + signature verification public key (a firmware-signing certificate). + However, use of this facility introduces a level of indirection. + Ultimately, a trust anchor public key must be made available to the + hardware module. Section 1.2 establishes a requirement that the + hardware module store one or more trust anchors. + + Hardware modules may not be capable of accessing certificate + repositories or delegated path discovery (DPD) servers [DPD&DPV] to + acquire certificates needed to complete a certification path. Thus, + it is the responsibility of the firmware package signer to include + sufficient certificates to enable each module to validate the + firmware-signer certificate (see Section 2.1.2). Similarly, hardware + modules may not be capable of accessing a certificate revocation list + (CRL) repository, an OCSP responder [OCSP], or a delegated path + validation (DPV) server [DPD&DPV] to acquire revocation status + information. Thus, if the firmware package signature cannot be + validated solely with the trust anchor public key and the hardware + module is not capable of performing full certification path + validation, then it is the responsibility of the entity loading a + package into a hardware module to validate the firmware-signer + certification path prior to loading the package into a hardware + module. The means by which this external certificate revocation + status checking is performed is beyond the scope of this + specification. + + + +Housley Standards Track [Page 4] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + Hardware modules will only accept firmware packages with a valid + digital signature. The signature is either validated directly using + the trust anchor public key or using a firmware-signer certification + path that is validated to the trust anchor public key. Thus, the + trust anchors define the set of entities that can create firmware + packages for the hardware module. + + The disposition of a previously loaded firmware package after the + successful validation of another firmware package is beyond the scope + of this specification. The amount of memory available to the + hardware module will determine the range of alternatives. + + In some cases, hardware modules can generate receipts to acknowledge + the loading of a particular firmware package. Such receipts can be + used to determine which hardware modules need to receive an updated + firmware package whenever a flaw in an earlier firmware package is + discovered. Hardware modules can also generate error reports to + indicate the unsuccessful firmware package loading. To implement + either receipt or error report generation, the hardware module is + required to have a unique permanent serial number. Receipts and + error reports can be either signed or unsigned. To generate + digitally signed receipts or error reports, a hardware module MUST be + issued its own private signature key and a certificate that contains + the corresponding signature validation public key. In order to save + memory with the hardware module, the hardware module might store a + certificate designator instead of the certificate itself. The + private signature key requires secure storage. + +1.1. Terminology + + In this document, the key words MUST, MUST NOT, REQUIRED, SHOULD, + SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL are to be interpreted as + described in [STDWORDS]. + +1.2. Architectural Elements + + The architecture includes the hardware module, the firmware package, + and a bootstrap loader. The bootstrap loader MUST have access to one + or more trusted public keys, called trust anchors, to validate the + signature on the firmware package. If a signed firmware package load + receipt or error report is created on behalf of the hardware module, + then the bootstrap loader MUST have access to a private signature key + to generate the signature and the signer identifier for the + corresponding signature validation certificate or its designator. A + signature validation certificate MAY be included to aid signature + validation. To implement this optional capability, the hardware + module MUST have a unique serial number and a private signature key; + the hardware module MAY also include a certificate that contains the + + + +Housley Standards Track [Page 5] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + corresponding signature validation public key. These items MUST be + installed in the hardware module before it is deployed. The private + key and certificate can be generated and installed as part of the + hardware module manufacture process. Figure 1 illustrates these + architectural elements. + + ASN.1 object identifiers are the preferred means of naming the + architectural elements. + + Details of managing the trust anchors are beyond the scope of this + specification. However, one or more trust anchors MUST be installed + in the hardware module using a secure process before it is deployed. + These trust anchors provide a means of controlling the acceptable + sources of firmware packages. The hardware module vendor can include + provisions for secure, remote management of trust anchors. One + approach is to include trust anchors in the firmware packages + themselves. This approach is analogous to the optional capability + described later for updating the bootstrap loader. + + In a cryptographic hardware module, the firmware package might + implement many different cryptographic algorithms. + + When the firmware package is encrypted, the firmware-decryption key + and the firmware package MUST both be provided to the hardware + module. The firmware-decryption key is necessary to use the + associated firmware package. Generally, separate distribution + mechanisms will be employed for the firmware-decryption key and the + firmware package. An optional mechanism for securely distributing + the firmware-decryption key with the firmware package is specified in + Section 2.3.1. + + + + + + + + + + + + + + + + + + + + + +Housley Standards Track [Page 6] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + +------------------------------------------------------+ + | Hardware Module | + | | + | +---------------+ +--------------------------+ | + | | Bootstrap | | Firmware Package | | + | | Loader | | | | + | +---------------+ | +------------------+ | | + | | : Firmware Package : | | + | +---------------+ | : Identifier and : | | + | | Trust | | : Version Number : | | + | | Anchor(s) | | +------------------+ | | + | +---------------+ | | | + | | +-------------+ | | + | +---------------+ | : Algorithm 1 : | | + | | Serial Num. | | +-+-----------+-+ | | + | +---------------+ | : Algorithm 2 : | | + | | +-+-----------+-+ | | + | +---------------+ | : Algorithm n : | | + | | Hardware | | +-------------+ | | + | | Module Type | | | | + | +---------------+ +--------------------------+ | + | | + | +------------------------------------+ | + | | Optional Private Signature Key & | | + | | Signature Validation Certificate | | + | | or the Certificate Designator | | + | +------------------------------------+ | + | | + +------------------------------------------------------+ + + Figure 1. Architectural Elements + +1.2.1. Hardware Module Requirements + + Many different vendors develop hardware modules, and each vendor + typically identifies its modules by product type (family) and + revision level. A unique object identifier MUST name each hardware + module type and revision. + + Each hardware module within a hardware module family SHOULD have a + unique permanent serial number. However, if the optional receipt or + error report generation capability is implemented, then the hardware + module MUST have a unique permanent serial number. If the optional + receipt or error report signature capability is implemented, then the + hardware module MUST have a private signature key and a certificate + containing the corresponding public signature validation key or its + designator. If a serial number is present, the bootstrap loader uses + + + + +Housley Standards Track [Page 7] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + it for authorization decisions (see Section 2.2.8), receipt + generation (see Section 3), and error report generation (see + Section 4). + + When the hardware module includes more than one firmware-programmable + component, the bootstrap loader distributes components of the package + to the appropriate components within the hardware module after the + firmware package is validated. The bootstrap loader is discussed + further in Section 1.2.3. + +1.2.2. Firmware Package Requirements + + Two approaches to naming firmware packages are supported: legacy and + preferred. Firmware package names are placed in a CMS signed + attribute, not in the firmware package itself. + + Legacy firmware package names are simply octet strings, and no + structure is assumed. This firmware package name form is supported + in order to facilitate existing configuration management systems. We + assume that the firmware signer and the bootstrap loader will + understand any internal structure to the octet string. In + particular, given two legacy firmware package names, we assume that + the firmware signer and the bootstrap loader will be able to + determine which one represents the newer version of the firmware + package. This capability is necessary to implement the stale version + feature. If a firmware package with a disastrous flaw is released, + subsequent firmware package versions MAY designate a stale legacy + firmware package name in order to prevent subsequent rollback to the + stale version or versions earlier than the stale version. + + Preferred firmware package names are a combination of the firmware + package object identifier and a version number. A unique object + identifier MUST identify the collection of features that characterize + the firmware package. For example, firmware packages for a cable + modem and a wireless LAN network interface card warrant distinct + object identifiers. Similarly, firmware packages that implement + distinct suites of cryptographic algorithms and modes of operation, + or that emulate different (non-programmable) cryptographic devices + warrant distinct object identifiers. The version number MUST + identify a particular build or release of the firmware package. The + version number MUST be a monotonically increasing non-negative + integer. Generally, an earlier version is replaced with a later one. + If a firmware package with a disastrous flaw is released, subsequent + firmware package versions MAY designate a stale version number to + prevent subsequent rollback to the stale version or versions earlier + than the stale version. + + + + + +Housley Standards Track [Page 8] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + Firmware packages are developed to run on one or more hardware module + type. The firmware package digital signature MUST bind the list of + supported hardware module object identifiers to the firmware package. + + In many cases, the firmware package signature will be validated + directly with the trust anchor public key, avoiding the need to + construct certification paths. Alternatively, the trust anchor can + delegate firmware package signing to another public key through a + certification path. In the latter case, the firmware package SHOULD + contain the certificates needed to construct the certification path + that begins with a certificate issued by the trust anchors and ends + with a certificate issued to the firmware package signer. + + The firmware package MAY contain a list of community identifiers. + These identifiers name the hardware modules that are authorized to + load the firmware package. If the firmware package contains a list + of community identifiers, then the bootstrap loader MUST reject the + firmware package if the hardware module is not a member of one of the + identified communities. + + When a hardware module includes multiple programmable components, the + firmware package SHOULD contain executable code for all of the + components. Internal tagging within the firmware package MUST tell + the bootstrap loader which portion of the overall firmware package is + intended for each component; however, this tagging is expected to be + specific to each hardware module. Because this specification treats + the firmware package as an opaque binary object, the format of the + firmware package is beyond the scope of this specification. + +1.2.3. Bootstrap Loader Requirements + + The bootstrap loader MUST have access to a physical interface and any + related driver or protocol software necessary to obtain a firmware + package. The same interface SHOULD be used to deliver receipts and + error reports. Details of the physical interface as well as the + driver or protocol software are beyond the scope of this + specification. + + The bootstrap loader can be a permanent part of the hardware module, + or it can be replaced by loading a firmware package. In Figure 1, + the bootstrap loader is implemented as separate logic within the + hardware module. Not all hardware modules will include the ability + to replace or update the bootstrap loader, and this specification + does not mandate such support. + + If the bootstrap loader can be loaded by a firmware package, an + initial bootstrap loader MUST be installed in non-volatile memory + prior to deployment. All bootstrap loaders, including an initial + + + +Housley Standards Track [Page 9] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + bootstrap loader if one is employed, MUST meet the requirements in + this section. However, the firmware package containing the bootstrap + loader MAY also contain other routines. + + The bootstrap loader requires access to cryptographic routines. + These routines can be implemented specifically for the bootstrap + loader, or they can be shared with other hardware module features. + The bootstrap loader MUST have access to a one-way hash function and + digital signature verification routines to validate the digital + signature on the firmware package and to validate the certification + path for the firmware-signing certificate. + + If firmware packages are encrypted, the bootstrap loader MUST have + access to a decryption routine. Access to a corresponding encryption + function is not required, since hardware modules need not be capable + of generating firmware packages. Because some symmetric encryption + algorithm implementations (such as AES [AES]) employ separate logic + for encryption and decryption, some hardware module savings might + result. + + If firmware packages are compressed, the bootstrap loader MUST also + have access to a decompression function. This function can be + implemented specifically for the bootstrap loader, or it can be + shared with other hardware module features. Access to a + corresponding compression function is not required, since hardware + modules need not be capable of generating firmware packages. + + If the optional receipt generation or error report capability is + supported, the bootstrap loader MUST have access to the hardware + module serial number and the object identifier for the hardware + module type. If the optional signed receipt generation or signed + error report capability is supported, the bootstrap loader MUST also + have access to a one-way hash function and digital signature + routines, the hardware module private signing key, and the + corresponding signature validation certificate or its designator. + + The bootstrap loader requires access to one or more trusted public + keys, called trust anchors, to validate the firmware package digital + signature. One or more trust anchors MUST be installed in non- + volatile memory prior to deployment. The bootstrap loader MUST + reject a firmware package if it cannot validate the signature, which + MAY require the construction of a valid certification path from the + firmware-signing certificate to one of the trust anchors [PROFILE]. + However, in many cases, the firmware package signature will be + validated directly with the trust anchor public key, avoiding the + need to construct certification paths. + + + + + +Housley Standards Track [Page 10] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + The bootstrap loader MUST reject a firmware package if the list of + supported hardware module type identifiers within the firmware + package does not include the object identifier of the hardware + module. + + The bootstrap loader MUST reject a firmware package if the firmware + package includes a list of community identifiers and the hardware + module is not a member of one of the listed communities. The means + of determining community membership is beyond the scope of this + specification. + + The bootstrap loader MUST reject a firmware package if it cannot + successfully decrypt the firmware package using the firmware- + decryption key available to the hardware module. The firmware + package contains an identifier of the firmware-decryption key needed + for decryption. + + When an earlier version of a firmware package is replacing a later + one, the bootstrap loader SHOULD generate a warning. The manner in + which a warning is generated is highly dependent on the hardware + module and the environment in which it is being used. If a firmware + package with a disastrous flaw is released and subsequent firmware + package versions designate a stale version, the bootstrap loader + SHOULD prevent loading of the stale version and versions earlier than + the stale version. + +1.2.3.1. Legacy Stale Version Processing + + In case a firmware package with a disastrous flaw is released, + subsequent firmware package versions that employ the legacy firmware + package name form MAY include a stale legacy firmware package name to + prevent subsequent rollback to the stale version or versions earlier + than the stale version. As described in the Security Considerations + section of this document, the inclusion of a stale legacy firmware + package name in a firmware package cannot completely prevent + subsequent use of the stale firmware package. However, many hardware + modules are expected to have very few firmware packages written for + them, allowing the stale firmware package version feature to provide + important protections. + + Non-volatile storage for stale version numbers is needed. The number + of stale legacy firmware package names that can be stored depends on + the amount of storage that is available. When a firmware package is + loaded and it contains a stale legacy firmware package name, then it + SHOULD be added to a list kept in non-volatile storage. When + subsequent firmware packages are loaded, the legacy firmware package + + + + + +Housley Standards Track [Page 11] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + name of the new package is compared to the list in non-volatile + storage. If the legacy firmware package name represents the same + version or an older version of a member of the list, then the new + firmware packages SHOULD be rejected. + + The amount of non-volatile storage that needs to be dedicated to + saving legacy firmware package names and stale legacy firmware + packages names depends on the number of firmware packages that are + likely to be developed for the hardware module. + +1.2.3.2. Preferred Stale Version Processing + + If a firmware package with a disastrous flaw is released, subsequent + firmware package versions that employ preferred firmware package name + form MAY include a stale version number to prevent subsequent + rollback to the stale version or versions earlier than the stale + version. As described in the Security Considerations section of this + document, the inclusion of a stale version number in a firmware + package cannot completely prevent subsequent use of the stale + firmware package. However, many hardware modules are expected to + have very few firmware packages written for them, allowing the stale + firmware package version feature to provide important protections. + + Non-volatile storage for stale version numbers is needed. The number + of stale version numbers that can be stored depends on the amount of + storage that is available. When a firmware package is loaded and it + contains a stale version number, then the object identifier of the + firmware package and the stale version number SHOULD be added to a + list that is kept in non-volatile storage. When subsequent firmware + packages are loaded, the object identifier and version number of the + new package are compared to the list in non-volatile storage. If the + object identifier matches and the version number is less than or + equal to the stale version number, then the new firmware packages + SHOULD be rejected. + + The amount of non-volatile storage that needs to be dedicated to + saving firmware package identifiers and stale version numbers depends + on the number of firmware packages that are likely to be developed + for the hardware module. + +1.2.4. Trust Anchors + + A trust anchor MUST consist of a public key signature algorithm and + an associated public key, which MAY optionally include parameters. A + trust anchor MUST also include a public key identifier. A trust + anchor MAY also include an X.500 distinguished name. + + + + + +Housley Standards Track [Page 12] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + The trust anchor public key is used in conjunction with the signature + validation algorithm in two different ways. First, the trust anchor + public key is used directly to validate the firmware package + signature. Second, the trust anchor public key is used to validate + an X.509 certification path, and then the subject public key in the + final certificate in the certification path is used to validate the + firmware package signature. + + The public key names the trust anchor, and each public key has a + public key identifier. The public key identifier identifies the + trust anchor as the signer when it is used directly to validate + firmware package signatures. This key identifier can be stored with + the trust anchor, or it can be computed from the public key whenever + needed. + + The optional trusted X.500 distinguished name MUST be present in + order for the trust anchor public key to be used to validate an X.509 + certification path. Without an X.500 distinguished name, + certification path construction cannot use the trust anchor. + +1.2.5. Cryptographic and Compression Algorithm Requirements + + A firmware package for a cryptographic hardware module includes + cryptographic algorithm implementations. In addition, a firmware + package for a non-cryptographic hardware module will likely include + cryptographic algorithm implementations to support the bootstrap + loader in the validation of firmware packages. + + A unique algorithm object identifier MUST be assigned for each + cryptographic algorithm and mode implemented by a firmware package. + A unique algorithm object identifier MUST also be assigned for each + compression algorithm implemented by a firmware package. The + algorithm object identifiers can be used to determine whether a + particular firmware package satisfies the needs of a particular + application. To facilitate the development of algorithm-agile + applications, the cryptographic module interface SHOULD allow + applications to query the cryptographic module for the object + identifiers associated with each cryptographic algorithm contained in + the currently loaded firmware package. Applications SHOULD also be + able to query the cryptographic module to determine attributes + associated with each algorithm. Such attributes might include the + algorithm type (symmetric encryption, asymmetric encryption, key + agreement, one-way hash function, digital signature, and so on), the + algorithm block size or modulus size, and parameters for asymmetric + algorithms. This specification does not establish the conventions + for the retrieval of algorithm identifiers or algorithm attributes. + + + + + +Housley Standards Track [Page 13] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + +1.3. Hardware Module Security Architecture + + The bootstrap loader MAY be permanently stored in read-only memory or + separately loaded into non-volatile memory as discussed above. + + In most hardware module designs, the firmware package execution + environment offers a single address space. If it does, the firmware + package SHOULD contain a complete firmware package load for the + hardware module. In this situation, the firmware package does not + contain a partial or incremental set of functions. A complete + firmware package load will minimize complexity and avoid potential + security problems. From a complexity perspective, the incremental + loading of packages makes it necessary for each package to identify + any other packages that are required (its dependencies), and the + bootstrap loader needs to verify that all of the dependencies are + satisfied before attempting to execute the firmware package. When a + hardware module is based on a general purpose processor or a digital + signal processor, it is dangerous to allow arbitrary packages to be + loaded simultaneously unless there is a reference monitor to ensure + that independent portions of the code cannot interfere with one + another. Also, it is difficult to evaluate arbitrary combinations of + software modules [SECREQMTS]. For these reasons, a complete firmware + package load is RECOMMENDED; however, this specification allows the + firmware signer to identify dependencies between firmware packages in + order to handle all situations. + + The firmware packages MAY have dependencies on routines provided by + other firmware packages. To minimize the security evaluation + complexity of a hardware module employing such a design, the firmware + package MUST identify the package identifiers (and the minimum + version numbers when the preferred firmware package name form is + used) of the packages upon which it depends. The bootstrap loader + MUST reject a firmware package load if it contains a dependency on a + firmware package that is not available. + + Loading a firmware package can impact the satisfactory resolution of + dependencies of other firmware packages that are already part of the + hardware module configuration. For this reason, the bootstrap loader + MUST reject the loading of a firmware package if the dependencies of + any firmware package in the resulting configurations will be + unsatisfied. + +1.4. ASN.1 Encoding + + The CMS uses Abstract Syntax Notation One (ASN.1) [X.208-88, + X.209-88]. ASN.1 is a formal notation used for describing data + protocols, regardless of the programming language used by the + implementation. Encoding rules describe how the values defined in + + + +Housley Standards Track [Page 14] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + ASN.1 will be represented for transmission. The Basic Encoding Rules + (BER) are the most widely employed rule set, but they offer more than + one way to represent data structures. For example, definite length + encoding and indefinite length encoding are supported. This + flexibility is not desirable when digital signatures are used. As a + result, the Distinguished Encoding Rules (DER) [X.509-88] were + invented. DER is a subset of BER that ensures a single way to + represent a given value. For example, DER always employs definite + length encoding. + + In this specification, digitally signed structures MUST be encoded + with DER. Other structures do not require DER, but the use of + definite length encoding is strongly RECOMMENDED. By always using + definite length encoding, the bootstrap loader will have fewer + options to implement. In situations where there is very high + confidence that only definite length encoding will be used, support + for indefinite length decoding MAY be omitted. + +1.5. Protected Firmware Package Loading + + This document does not attempt to specify a physical interface, any + related driver software, or a protocol necessary for loading firmware + packages. Many different delivery mechanisms are envisioned, + including portable memory devices, file transfer, and web pages. + Section 2 of this specification defines the format that MUST be + presented to the hardware module regardless of the interface that is + used. This specification also specifies the format of the response + that MAY be generated by the hardware module. Section 3 of this + specification defines the format that MAY be returned by the hardware + module when a firmware package loads successfully. Section 4 of this + specification defines the format that MAY be returned by the hardware + module when a firmware package load is unsuccessful. The firmware + package load receipts and firmware package load error reports can be + either signed or unsigned. + +2. Firmware Package Protection + + The Cryptographic Message Syntax (CMS) is used to protect a firmware + package, which is treated as an opaque binary object. A digital + signature is used to protect the firmware package from undetected + modification and to provide data origin authentication. Encryption + is optionally used to protect the firmware package from disclosure, + and compression is optionally used to reduce the size of the + protected firmware package. The CMS ContentInfo content type MUST + always be present, and it MUST encapsulate the CMS SignedData content + type. If the firmware package is encrypted, then the CMS SignedData + content type MUST encapsulate the CMS EncryptedData content type. If + the firmware package is compressed, then either the CMS SignedData + + + +Housley Standards Track [Page 15] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + content type (when encryption is not used) or the CMS EncryptedData + content type (when encryption is used) MUST encapsulate the CMS + CompressedData content type. Finally, (1) the CMS SignedData content + type (when neither encryption nor compression is used), (2) the CMS + EncryptedData content type (when encryption is used, but compression + is not), or (3) the CMS CompressedData content type (when compression + is used) MUST encapsulate the simple firmware package using the + FirmwarePkgData content type defined in this specification (see + Section 2.1.5). + + The firmware package protection is summarized as follows (see [CMS] + for the full syntax): + + ContentInfo { + contentType id-signedData, -- (1.2.840.113549.1.7.2) + content SignedData + } + + SignedData { + version CMSVersion, -- always set to 3 + digestAlgorithms DigestAlgorithmIdentifiers, -- Only one + encapContentInfo EncapsulatedContentInfo, + certificates CertificateSet, -- Signer cert. path + crls CertificateRevocationLists, -- Optional + signerInfos SET OF SignerInfo -- Only one + } + + SignerInfo { + version CMSVersion, -- always set to 3 + sid SignerIdentifier, + digestAlgorithm DigestAlgorithmIdentifier, + signedAttrs SignedAttributes, -- Required + signatureAlgorithm SignatureAlgorithmIdentifier, + signature SignatureValue, + unsignedAttrs UnsignedAttributes -- Optional + } + + + + + + + + + + + + + + + +Housley Standards Track [Page 16] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + EncapsulatedContentInfo { + eContentType id-encryptedData, -- (1.2.840.113549.1.7.6) + -- OR -- + id-ct-compressedData, + -- (1.2.840.113549.1.9.16.1.9) + -- OR -- + id-ct-firmwarePackage, + -- (1.2.840.113549.1.9.16.1.16) + eContent OCTET STRING + } -- Contains EncryptedData OR + -- CompressedData OR + -- FirmwarePkgData + + EncryptedData { + version CMSVersion, -- Always set to 0 + encryptedContentInfo EncryptedContentInfo, + unprotectedAttrs UnprotectedAttributes -- Omit + } + + EncryptedContentInfo { + contentType id-ct-compressedData, + -- (1.2.840.113549.1.9.16.1.9) + -- OR -- + id-ct-firmwarePackage, + -- (1.2.840.113549.1.9.16.1.16) + contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, + encryptedContent OCTET STRING + } -- Contains CompressedData OR + -- FirmwarePkgData + + CompressedData { + version CMSVersion, -- Always set to 0 + compressionAlgorithm CompressionAlgorithmIdentifier, + encapContentInfo EncapsulatedContentInfo + } + + EncapsulatedContentInfo { + eContentType id-ct-firmwarePackage, + -- (1.2.840.113549.1.9.16.1.16) + eContent OCTET STRING -- Contains FirmwarePkgData + } + + FirmwarePkgData OCTET STRING -- Contains firmware package + + + + + + + + +Housley Standards Track [Page 17] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + +2.1. Firmware Package Protection CMS Content Type Profile + + This section specifies the conventions for using the CMS ContentInfo, + SignedData, EncryptedData, and CompressedData content types. It also + defines the FirmwarePkgData content type. + +2.1.1. ContentInfo + + The CMS requires that the outermost encapsulation be ContentInfo + [CMS]. The fields of ContentInfo are used as follows: + + contentType indicates the type of the associated content, and in + this case, the encapsulated type is always SignedData. The + id-signedData (1.2.840.113549.1.7.2) object identifier MUST be + present in this field. + + content holds the associated content, and in this case, the + content field MUST contain SignedData. + +2.1.2. SignedData + + The SignedData content type [CMS] contains the signed firmware + package (which might be compressed, encrypted, or compressed and then + encrypted prior to signature), the certificates needed to validate + the signature, and one digital signature value. The fields of + SignedData are used as follows: + + version is the syntax version number, and in this case, it MUST be + set to 3. + + digestAlgorithms is a collection of message digest algorithm + identifiers, and in this case, it MUST contain a single message + digest algorithm identifier. The message digest algorithm + employed by the firmware package signer MUST be present. + + encapContentInfo contains the signed content, consisting of a content + type identifier and the content itself. The use of the + EncapsulatedContentInfo type is discussed further in Section + 2.1.2.2. + + certificates is an optional collection of certificates. If the trust + anchor signed the firmware package directly, then certificates + SHOULD be omitted. If it did not, then certificates SHOULD + include the X.509 certificate of the firmware package signer. The + set of certificates SHOULD be sufficient for the bootstrap loader + to construct a certification path from the trust anchor to the + firmware-signer's certificate. PKCS#6 extended certificates + + + + +Housley Standards Track [Page 18] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + [PKCS#6] and attribute certificates (either version 1 or + version 2) [X.509-97, X.509-00, ACPROFILE] MUST NOT be included in + the set of certificates. + + crls is an optional collection of certificate revocation lists + (CRLs), and in this case, CRLs SHOULD NOT be included by the + firmware package signer. It is anticipated that firmware packages + may be generated, signed, and made available in repositories for + downloading into hardware modules. In such contexts, it would be + difficult for the firmware package signer to include timely CRLs + in the firmware package. However, because the CRLs are not + covered by the signature, timely CRLs MAY be inserted by some + other party before the firmware package is delivered to the + hardware module. + + signerInfos is a collection of per-signer information, and in this + case, the collection MUST contain exactly one SignerInfo. The use + of the SignerInfo type is discussed further in Section 2.1.2.1. + +2.1.2.1. SignerInfo + + The firmware package signer is represented in the SignerInfo type. + The fields of SignerInfo are used as follows: + + version is the syntax version number, and it MUST be 3. + + sid identifies the signer's public key. CMS supports two + alternatives: issuerAndSerialNumber and subjectKeyIdentifier. + However, the bootstrap loader MUST support the + subjectKeyIdentifier alternative, which identifies the signer's + public key directly. When this public key is contained in a + certificate, this identifier SHOULD appear in the X.509 + subjectKeyIdentifier extension. + + digestAlgorithm identifies the message digest algorithm, and any + associated parameters, used by the firmware package signer. It + MUST contain the message digest algorithms employed by the + firmware package signer. (Note that this message digest algorithm + identifier MUST be the same as the one carried in the + digestAlgorithms value in SignedData.) + + signedAttrs is an optional collection of attributes that are signed + along with the content. The signedAttrs are optional in the CMS, + but in this specification, signedAttrs are REQUIRED for the + firmware package; however, implementations MUST ignore + unrecognized signed attributes. The SET OF attributes MUST be DER + + + + + +Housley Standards Track [Page 19] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + encoded [X.509-88]. Section 2.2 of this document lists the + attributes that MUST be included in the collection; other + attributes MAY be included as well. + + signatureAlgorithm identifies the signature algorithm, and any + associated parameters, used by the firmware package signer to + generate the digital signature. + + signature is the digital signature value. + + unsignedAttrs is an optional SET of attributes that are not signed. + As described in Section 2.3, this set can only contain a single + instance of the wrapped-firmware-decryption-key attribute and no + others. + +2.1.2.2. EncapsulatedContentInfo + + The EncapsulatedContentInfo content type encapsulates the firmware + package, which might be compressed, encrypted, or compressed and then + encrypted prior to signature. The firmware package, in any of these + formats, is carried within the EncapsulatedContentInfo type. The + fields of EncapsulatedContentInfo are used as follows: + + eContentType is an object identifier that uniquely specifies the + content type, and in this case, the value MUST be id-encryptedData + (1.2.840.113549.1.7.6), id-ct-compressedData + (1.2.840.113549.1.9.16.1.9), or id-ct-firmwarePackage + (1.2.840.113549.1.9.16.1.16). When eContentType contains id- + encryptedData, the firmware package was encrypted prior to + signing, and may also have been compressed prior to encryption. + When it contains id-ct-compressedData, the firmware package was + compressed prior to signing, but was not encrypted. When it + contains id-ct-firmwarePackage, the firmware package was not + compressed or encrypted prior to signing. + + eContent contains the signed firmware package, which might also be + encrypted, compressed, or compressed and then encrypted, prior to + signing. The content is encoded as an octet string. The eContent + octet string need not be DER encoded. + +2.1.3. EncryptedData + + The EncryptedData content type [CMS] contains the encrypted firmware + package (which might be compressed prior to encryption). However, if + the firmware package was not encrypted, the EncryptedData content + type is not present. The fields of EncryptedData are used as + follows: + + + + +Housley Standards Track [Page 20] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + version is the syntax version number, and in this case, version MUST + be 0. + + encryptedContentInfo is the encrypted content information. The use + of the EncryptedContentInfo type is discussed further in Section + 2.1.3.1. + + unprotectedAttrs is an optional collection of unencrypted attributes, + and in this case, unprotectedAttrs MUST NOT be present. + +2.1.3.1. EncryptedContentInfo + + The encrypted firmware package, which might be compressed prior to + encryption, is encapsulated in the EncryptedContentInfo type. The + fields of EncryptedContentInfo are used as follows: + + contentType indicates the type of content, and in this case, it MUST + contain either id-ct-compressedData (1.2.840.113549.1.9.16.1.9) or + id-ct-firmwarePackage (1.2.840.113549.1.9.16.1.16). When it + contains id-ct-compressedData, then the firmware package was + compressed prior to encryption. When it contains id-ct- + firmwarePackage, then the firmware package was not compressed + prior to encryption. + + contentEncryptionAlgorithm identifies the firmware-encryption + algorithm, and any associated parameters, used to encrypt the + firmware package. + + encryptedContent is the result of encrypting the firmware package. + The field is optional; however, in this case, it MUST be present. + +2.1.4. CompressedData + + The CompressedData content type [COMPRESS] contains the compressed + firmware package. If the firmware package was not compressed, then + the CompressedData content type is not present. The fields of + CompressedData are used as follows: + + version is the syntax version number; in this case, it MUST be 0. + + compressionAlgorithm identifies the compression algorithm, and any + associated parameters, used to compress the firmware package. + + encapContentInfo is the compressed content, consisting of a content + type identifier and the content itself. The use of the + EncapsulatedContentInfo type is discussed further in Section + 2.1.4.1. + + + + +Housley Standards Track [Page 21] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + +2.1.4.1. EncapsulatedContentInfo + + The CompressedData content type encapsulates the compressed firmware + package, and it is carried within the EncapsulatedContentInfo type. + The fields of EncapsulatedContentInfo are used as follows: + + eContentType is an object identifier that uniquely specifies the + content type, and in this case, it MUST be the value of id-ct- + firmwarePackage (1.2.840.113549.1.9.16.1.16). + + eContent is the compressed firmware package, encoded as an octet + string. The eContent octet string need not be DER encoded. + +2.1.5. FirmwarePkgData + + The FirmwarePkgData content type contains the firmware package. It + is a straightforward encapsulation in an octet string, and it need + not be DER encoded. + + The FirmwarePkgData content type is identified by the id-ct- + firmwarePackage object identifier: + + id-ct-firmwarePackage OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) ct(1) 16 } + + The FirmwarePkgData content type is a simple octet string: + + FirmwarePkgData ::= OCTET STRING + +2.2. Signed Attributes + + The firmware package signer MUST digitally sign a collection of + attributes along with the firmware package. Each attribute in the + collection MUST be DER encoded [X.509-88]. The syntax for attributes + is defined in [CMS], but it is repeated here for convenience: + + Attribute ::= SEQUENCE { + attrType OBJECT IDENTIFIER, + attrValues SET OF AttributeValue } + + AttributeValue ::= ANY + + Each of the attributes used with this profile has a single attribute + value, even though the syntax is defined as a SET OF AttributeValue. + There MUST be exactly one instance of AttributeValue present. + + + + + +Housley Standards Track [Page 22] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + The SignedAttributes syntax within signerInfo is defined as a SET OF + Attribute. The SignedAttributes MUST include only one instance of + any particular attribute. + + The firmware package signer MUST include the following four + attributes: content-type, message-digest, firmware-package- + identifier, and target-hardware-module-identifiers. + + If the firmware package is encrypted, then the firmware package + signer MUST also include the decrypt-key-identifier attribute. + + If the firmware package implements cryptographic algorithms, then the + firmware package signer MAY also include the implemented-crypto- + algorithms attribute. Similarly, if the firmware package implements + compression algorithms, then the firmware package signer MAY also + include the implemented-compress-algorithms attribute. + + If the firmware package is intended for use only by specific + communities, then the firmware package signer MUST also include the + community-identifiers attribute. + + If the firmware package depends on the presence of one or more other + firmware packages to operate properly, then the firmware package + signer SHOULD also include the firmware-package-info attribute. For + example, the firmware-package-info attribute dependencies field might + indicate that the firmware package contains a dependency on a + particular bootstrap loader or separation kernel. + + The firmware package signer SHOULD also include the three following + attributes: firmware-package-message-digest, signing-time, and + content-hints. Additionally, if the firmware package signer has a + certificate (meaning that the firmware package signer is not always + configured as a trust anchor), then the firmware package signer + SHOULD also include the signing-certificate attribute. + + The firmware package signer MAY include any other attribute that it + deems appropriate. + +2.2.1. Content Type + + The firmware package signer MUST include a content-type attribute + with the value of id-encryptedData (1.2.840.113549.1.7.6), id-ct- + compressedData (1.2.840.113549.1.9.16.1.9), or id-ct-firmwarePackage + (1.2.840.113549.1.9.16.1.16). When it contains id-encryptedData, the + firmware package was encrypted prior to signing. When it contains + id-ct-compressedData, the firmware package was compressed prior to + signing, but was not encrypted. When it contains + + + + +Housley Standards Track [Page 23] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + id-ct-firmwarePackage, the firmware package was not compressed or + encrypted prior to signing. Section 11.1 of [CMS] defines the + content-type attribute. + +2.2.2. Message Digest + + The firmware package signer MUST include a message-digest attribute, + having as its value the message digest computed on the + encapContentInfo eContent octet string, as defined in Section + 2.1.2.2. This octet string contains the firmware package, and it MAY + be compressed, encrypted, or both compressed and encrypted. Section + 11.2 of [CMS] defines the message-digest attribute. + +2.2.3. Firmware Package Identifier + + The firmware-package-identifier attribute names the protected + firmware package. Two approaches to naming firmware packages are + supported: legacy and preferred. The firmware package signer MUST + include a firmware-package-identifier attribute using one of these + name forms. + + A legacy firmware package name is an octet string, and no structure + within the octet string is assumed. + + A preferred firmware package name is a combination of an object + identifier and a version number. The object identifier names a + collection of functions implemented by the firmware package, and the + version number is a non-negative integer that identifies a particular + build or release of the firmware package. + + If a firmware package with a disastrous flaw is released, the + firmware package that repairs the previously distributed flaw MAY + designate a stale firmware package version to prevent the reloading + of the flawed version. The hardware module bootstrap loader SHOULD + prevent subsequent rollback to the stale version or versions earlier + than the stale version. When the legacy firmware package name form + is used, the stale version is indicated by a stale legacy firmware + package name, which is an octet string. We assume that the firmware + package signer and the bootstrap loader can determine whether a given + legacy firmware package name represents a version that is more recent + than the stale one. When the preferred firmware package name form is + used, the stale version is indicated by a stale version number, which + is an integer. + + + + + + + + +Housley Standards Track [Page 24] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + The following object identifier identifies the firmware-package- + identifier attribute: + + id-aa-firmwarePackageID OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 35 } + + The firmware-package-identifier attribute values have ASN.1 type + FirmwarePackageIdentifier: + + FirmwarePackageIdentifier ::= SEQUENCE { + name PreferredOrLegacyPackageIdentifier, + stale PreferredOrLegacyStalePackageIdentifier OPTIONAL } + + PreferredOrLegacyPackageIdentifier ::= CHOICE { + preferred PreferredPackageIdentifier, + legacy OCTET STRING } + + PreferredPackageIdentifier ::= SEQUENCE { + fwPkgID OBJECT IDENTIFIER, + verNum INTEGER (0..MAX) } + + PreferredOrLegacyStalePackageIdentifier ::= CHOICE { + preferredStaleVerNum INTEGER (0..MAX), + legacyStaleVersion OCTET STRING } + +2.2.4. Target Hardware Module Identifiers + + The target-hardware-module-identifiers attribute names the types of + hardware modules that the firmware package supports. A unique object + identifier names each supported hardware model type and revision. + + The bootstrap loader MUST reject the firmware package if its own + hardware module type identifier is not listed in the target- + hardware-module-identifiers attribute. + + The following object identifier identifies the target-hardware- + module-identifiers attribute: + + id-aa-targetHardwareIDs OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 36 } + + The target-hardware-module-identifiers attribute values have ASN.1 + type TargetHardwareIdentifiers: + + TargetHardwareIdentifiers ::= SEQUENCE OF OBJECT IDENTIFIER + + + + +Housley Standards Track [Page 25] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + +2.2.5. Decrypt Key Identifier + + The decrypt-key-identifier attribute names the symmetric key needed + to decrypt the encapsulated firmware package. The CMS EncryptedData + content type is used when the firmware package is encrypted. The + decrypt-key-identifier signed attribute is carried in the SignedData + content type that encapsulates EncryptedData content type, naming the + symmetric key needed to decrypt the firmware package. No particular + structure is imposed on the key identifier. The means by which the + firmware-decryption key is securely distributed to all modules that + are authorized to use the associated firmware package is beyond the + scope of this specification; however, an optional mechanism for + securely distributing the firmware-decryption key with the firmware + package is specified in Section 2.3.1. + + The following object identifier identifies the decrypt-key-identifier + attribute: + + id-aa-decryptKeyID OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 37 } + + The decrypt-key-identifier attribute values have ASN.1 type + DecryptKeyIdentifier: + + DecryptKeyIdentifier ::= OCTET STRING + +2.2.6. Implemented Crypto Algorithms + + The implemented-crypto-algorithms attribute MAY be present in the + SignedAttributes, and it names the cryptographic algorithms that are + implemented by the firmware package and available to applications. + Only those algorithms that are made available at the interface of the + cryptographic module are listed. Any cryptographic algorithm that is + used internally and is not accessible via the cryptographic module + interface MUST NOT be listed. For example, if the firmware package + implements the decryption algorithm for future firmware package + installations and this algorithm is not made available for other + uses, then the firmware-decryption algorithm would not be listed. + + The object identifier portion of AlgorithmIdentifier identifies an + algorithm and its mode of use. No algorithm parameters are included. + Cryptographic algorithms include traffic-encryption algorithms, key- + encryption algorithms, key transport algorithms, key agreement + algorithms, one-way hash algorithms, and digital signature + algorithms. Cryptographic algorithms do not include compression + algorithms. + + + + +Housley Standards Track [Page 26] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + The following object identifier identifies the implemented-crypto- + algorithms attribute: + + id-aa-implCryptoAlgs OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 38 } + + The implemented-crypto-algorithms attribute values have ASN.1 type + ImplementedCryptoAlgorithms: + + ImplementedCryptoAlgorithms ::= SEQUENCE OF OBJECT IDENTIFIER + +2.2.7. Implemented Compression Algorithms + + The implemented-compress-algorithms attribute MAY be present in the + SignedAttributes, and it names the compression algorithms that are + implemented by the firmware package and available to applications. + Only those algorithms that are made available at the interface of the + hardware module are listed. Any compression algorithm that is used + internally and is not accessible via the hardware module interface + MUST NOT be listed. For example, if the firmware package implements + a decompression algorithm for future firmware package installations + and this algorithm is not made available for other uses, then the + firmware-decompression algorithm would not be listed. + + The object identifier portion of AlgorithmIdentifier identifies a + compression algorithm. No algorithm parameters are included. + + The following object identifier identifies the implemented-compress- + algorithms attribute: + + id-aa-implCompressAlgs OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 43 } + + The implemented-compress-algorithms attribute values have ASN.1 type + ImplementedCompressAlgorithms: + + ImplementedCompressAlgorithms ::= SEQUENCE OF OBJECT IDENTIFIER + +2.2.8. Community Identifiers + + If present in the SignedAttributes, the community-identifiers + attribute names the communities that are permitted to execute the + firmware package. The bootstrap loader MUST reject the firmware + package if the hardware module is not a member of one of the + identified communities. The means of assigning community membership + is beyond the scope of this specification. + + + +Housley Standards Track [Page 27] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + The community-identifiers attributes names the authorized communities + by a list of community object identifiers, by a list of specific + hardware modules, or by a combination of the two lists. A specific + hardware module is specified by the combination of the hardware + module identifier (as defined in Section 2.2.4) and a serial number. + To facilitate compact representation of serial numbers, a contiguous + block can be specified by the lowest authorized serial number and the + highest authorized serial number. Alternatively, all of the serial + numbers associated with a hardware module family identifier can be + specified with the NULL value. + + If the bootstrap loader does not have a mechanism for obtaining a + list of object identifiers that identify the communities to which the + hardware module is a member, then the bootstrap loader MUST behave as + though the list is empty. Similarly, if the bootstrap loader does + not have access to the hardware module serial number, then the + bootstrap loader MUST behave as though the hardware module is not + included on the list of authorized hardware modules. + + The following object identifier identifies the community-identifiers + attribute: + + id-aa-communityIdentifiers OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 40 } + + The community-identifiers attribute values have ASN.1 type + CommunityIdentifiers: + + CommunityIdentifiers ::= SEQUENCE OF CommunityIdentifier + + CommunityIdentifier ::= CHOICE { + communityOID OBJECT IDENTIFIER, + hwModuleList HardwareModules } + + HardwareModules ::= SEQUENCE { + hwType OBJECT IDENTIFIER, + hwSerialEntries SEQUENCE OF HardwareSerialEntry } + + HardwareSerialEntry ::= CHOICE { + all NULL, + single OCTET STRING, + block SEQUENCE { + low OCTET STRING, + high OCTET STRING } } + + + + + + +Housley Standards Track [Page 28] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + +2.2.9. Firmware Package Information + + If a hardware module supports more than one type of firmware package, + then the firmware package signer SHOULD include the firmware- + package-info attribute with a populated fwPkgType field to identify + the firmware package type. This value can aid the bootstrap loader + in the correct placement of the firmware package within the hardware + module. The firmware package type is an INTEGER, and the meaning of + the integer value is specific to each hardware module. For example, + a hardware module could assign different integer values for a + bootstrap loader, a separation kernel, and an application. + + Some hardware module architectures permit one firmware package to use + routines provided by another. If the firmware package contains a + dependency on another, then the firmware package signer SHOULD also + include the firmware-package-info attribute with a populated + dependencies field. If the firmware package does not depend on any + other firmware packages, then the firmware package signer MUST NOT + include the firmware-package-info attribute with a populated + dependencies field. + + Firmware package dependencies are identified by the firmware package + identifier or by information contained in the firmware package + itself, and in either case the bootstrap loader ensures that the + dependencies are met. The bootstrap loader MUST reject a firmware + package load if it identifies a dependency on a firmware package that + is not already loaded. Also, the bootstrap loader MUST reject a + firmware package load if the action will result in a configuration + where the dependencies of an already loaded firmware package will no + longer be satisfied. As described in Section 2.2.3, two approaches + to naming firmware packages are supported: legacy and preferred. + When the legacy firmware package name form is used, the dependency is + indicated by a legacy firmware package name. We assume that the + firmware package signer and the bootstrap loader can determine + whether a given legacy firmware package name represents the named + version of an acceptable newer version. When the preferred firmware + package name form is used, an object identifier and an integer are + provided. The object identifier MUST exactly match the object + identifier portion of a preferred firmware package name associated + with a firmware package that is already loaded, and the integer MUST + be less than or equal to the integer portion of the preferred + firmware package name associated with the same firmware package. + That is, the dependency specifies the minimum value of the version + that is acceptable. + + + + + + + +Housley Standards Track [Page 29] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + The following object identifier identifies the firmware-package-info + attribute: + + id-aa-firmwarePackageInfo OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 42 } + + The firmware-package-info attribute values have ASN.1 type + FirmwarePackageInfo: + + FirmwarePackageInfo ::= SEQUENCE { + fwPkgType INTEGER OPTIONAL, + dependencies SEQUENCE OF + PreferredOrLegacyPackageIdentifier OPTIONAL } + +2.2.10. Firmware Package Message Digest + + The firmware package signer SHOULD include a firmware-package- + message-digest attribute, which provides the message digest algorithm + and the message digest value computed on the firmware package. The + message digest is computed on the firmware package prior to any + compression, encryption, or signature processing. The bootstrap + loader MAY use this message digest to confirm that the intended + firmware package has been recovered after all of the layers of + encapsulation are removed. + + The following object identifier identifies the firmware-package- + message-digest attribute: + + id-aa-fwPkgMessageDigest OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 41 } + + The firmware-package-message-digest attribute values have ASN.1 type + FirmwarePackageMessageDigest: + + FirmwarePackageMessageDigest ::= SEQUENCE { + algorithm AlgorithmIdentifier, + msgDigest OCTET STRING } + +2.2.11. Signing Time + + The firmware package signer SHOULD include a signing-time attribute, + specifying the time at which the signature was applied to the + firmware package. Section 11.3 of [CMS] defines the signing-time + attribute. + + + + + +Housley Standards Track [Page 30] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + +2.2.12. Content Hints + + The firmware package signer SHOULD include a content-hints attribute, + including a brief text description of the firmware package. The text + is encoded in UTF-8, which supports most of the world's writing + systems [UTF-8]. Section 2.9 of [ESS] defines the content-hints + attribute. + + When multiple layers of encapsulation are employed, the content-hints + attribute is included in the outermost SignedData to provide + information about the innermost content. In this case, the content- + hints attribute provides a brief text description of the firmware + package, which can help a person select the correct firmware package + when more than one is available. + + When the preferred firmware package name forms are used, the + content-hints attribute can provide a linkage to a legacy firmware + package name. This is especially helpful when an existing + configuration management system is in use, but the features + associated with the preferred firmware package name are deemed + useful. A firmware package name associated with such a configuration + management system might look something like + "R1234.C0(AJ11).D62.A02.11(b)." Including these firmware package + names in the text description may be helpful to developers by + providing a clear linkage between the two name forms. + + The content-hints attribute contains two fields, and in this case, + both fields MUST be present. The fields of ContentHints are used as + follows: + + contentDescription provides a brief text description of the firmware + package. + + contentType provides the content type of the inner most content type, + and in this case, it MUST be id-ct-firmwarePackage + (1.2.840.113549.1.9.16.1.16). + +2.2.13. Signing Certificate + + When the firmware-signer's public key is contained in a certificate, + the firmware package signer SHOULD include a signing-certificate + attribute to identify the certificate that was employed. However, if + the firmware package signature does not have a certificate (meaning + that the signature will only be validated with the trust anchor + public key), then the firmware package signer is unable to include a + signing-certificate attribute. Section 5.4 of [ESS] defines this + attribute. + + + + +Housley Standards Track [Page 31] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + The signing-certificate attribute contains two fields: certs and + policies. The certs field MUST be present, and the policies field + MAY be present. The fields of SigningCertificate are used as + follows: + + certs contains a sequence of certificate identifiers. In this case, + sequence of certificate identifiers contains a single entry. The + certs field MUST contain only the certificate identifier of the + certificate that contains the public key used to verify the + firmware package signature. The certs field uses the ESSCertID + syntax specified in Section 5.4 of [ESS], and it is comprised of + the SHA-1 hash [SHA1] of the entire ASN.1 DER encoded certificate + and, optionally, the certificate issuer and the certificate serial + number. The SHA-1 hash value MUST be present. The certificate + issuer and the certificate serial number SHOULD be present. + + policies is optional; when it is present, it contains a sequence of + policy information. The policies field, when present, MUST + contain only one entry, and that entry MUST match one of the + certificate policies in the certificate policies extension of the + certificate that contains the public key used to verify the + firmware package signature. The policies field uses the + PolicyInformation syntax specified in Section 4.2.1.5 of + [PROFILE], and it is comprised of the certificate policy object + identifier and, optionally, certificate policy qualifiers. The + certificate policy object identifier MUST be present. The + certificate policy qualifiers SHOULD NOT be present. + +2.3. Unsigned Attributes + + CMS allows a SET of unsigned attributes to be included; however, in + this specification, the set MUST be absent or include a single + instance of the wrapped-firmware-decryption-key attribute. Because + the digital signature does not cover this attribute, it can be + altered at any point in the delivery path from the firmware package + signer to the hardware module. This property can be employed to + distribute the firmware-decryption key along with an encrypted and + signed firmware package, allowing the firmware-decryption key to be + wrapped with a different key-encryption key for each link in the + distribution chain. + + The syntax for attributes is defined in [CMS], and it is repeated at + the beginning of Section 2.2 of this document for convenience. Each + of the attributes used with this profile has a single attribute + value, even though the syntax is defined as a SET OF AttributeValue. + There MUST be exactly one instance of AttributeValue present. + + + + + +Housley Standards Track [Page 32] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + The UnsignedAttributes syntax within signerInfo is defined as a SET + OF Attribute. The UnsignedAttributes MUST include only one instance + of any particular attribute. + +2.3.1. Wrapped Firmware Decryption Key + + The firmware package signer, or any other party in the distribution + chain, MAY include a wrapped-firmware-decryption-key attribute. + + The following object identifier identifies the wrapped-firmware- + decryption-key attribute: + + id-aa-wrappedFirmwareKey OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 39 } + + The wrapped-firmware-decryption-key attribute values have ASN.1 type + of EnvelopedData. Section 6 of [CMS] defines the EnvelopedData + content type, which is used to construct the value of the attribute. + EnvelopedData permits the firmware-decryption key to be protected + using symmetric or asymmetric techniques. The EnvelopedData does not + include an encrypted content; rather, the EnvelopedData feature of + having the encrypted content in another location is employed. The + encrypted content is found in the eContent field of the EncryptedData + structure. The firmware-decryption key is contained in the + recipientInfos field. Section 6 of [CMS] refers to this key as the + content-encryption key. + + The EnvelopedData syntax supports many different key management + algorithms. Four general techniques are supported: key transport, + key agreement, symmetric key-encryption keys, and passwords. + + The EnvelopedData content type is profiled for the wrapped-firmware- + decryption-key attribute. The EnvelopedData fields are described + fully in Section 6 of [CMS]. Additional rules apply when + EnvelopedData is used as a wrapped-firmware-decryption-key attribute. + + Within the EnvelopedData structure, the following apply: + + - The set of certificates included in OriginatorInfo MUST NOT + include certificates with a type of extendedCertificate, + v1AttrCert, or v2AttrCert [X.509-97, X.509-00, ACPROFILE]. The + optional crls field MAY be present. + + - The optional unprotectedAttrs field MUST NOT be present. + + + + + + +Housley Standards Track [Page 33] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + Within the EncryptedContentInfo structure, the following apply: + + - contentType MUST match the content type object identifier carried + in the contentType field within the EncryptedContentInfo structure + of EncryptedData as described in Section 2.1.3.1. + + - contentEncryptionAlgorithm identifies the firmware-encryption + algorithm, and any associated parameters, used to encrypt the + firmware package carried in the encryptedContent field of the + EncryptedContentInfo structure of EncryptedData. Therefore, it + MUST exactly match the value of the EncryptedContentInfo structure + of EncryptedData as described in Section 2.1.3.1. + + - encryptedContent is optional, and in this case, it MUST NOT be + present. + +3. Firmware Package Load Receipt + + The Cryptographic Message Syntax (CMS) is used to indicate that a + firmware package loaded successfully. Support for firmware package + load receipts is OPTIONAL. However, those hardware modules that + choose to generate such receipts MUST follow the conventions + specified in this section. Because not all hardware modules will + have private signature keys, the firmware package load receipt can be + either signed or unsigned. Use of the signed firmware package load + receipt is RECOMMENDED. + + Hardware modules that support receipt generation MUST have a unique + serial number. Hardware modules that support signed receipt + generation MUST have a private signature key to sign the receipt and + the corresponding signature validation certificate or its designator. + The designator is the certificate issuer name and the certificate + serial number, or it is the public key identifier. Memory- + constrained hardware modules will generally store the public key + identifier since it requires less storage. + + The unsigned firmware package load receipt is encapsulated by + ContentInfo. Alternatively, the signed firmware package load receipt + is encapsulated by SignedData, which is in turn encapsulated by + ContentInfo. + + + + + + + + + + + +Housley Standards Track [Page 34] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + The firmware package load receipt is summarized as follows (see [CMS] + for the full syntax): + + ContentInfo { + contentType id-signedData, -- (1.2.840.113549.1.7.2) + -- OR -- + id-ct-firmwareLoadReceipt, + -- (1.2.840.113549.1.9.16.1.17) + content SignedData + -- OR -- + FirmwarePackageLoadReceipt + } + + SignedData { + version CMSVersion, -- always set to 3 + digestAlgorithms DigestAlgorithmIdentifiers, -- Only one + encapContentInfo EncapsulatedContentInfo, + certificates CertificateSet, -- Optional Module certificate + crls CertificateRevocationLists, -- Optional + signerInfos SET OF SignerInfo -- Only one + } + + SignerInfo { + version CMSVersion, -- either set to 1 or 3 + sid SignerIdentifier, + digestAlgorithm DigestAlgorithmIdentifier, + signedAttrs SignedAttributes, -- Required + signatureAlgorithm SignatureAlgorithmIdentifier, + signature SignatureValue, + unsignedAttrs UnsignedAttributes -- Omit + } + + EncapsulatedContentInfo { + eContentType id-ct-firmwareLoadReceipt, + -- (1.2.840.113549.1.9.16.1.17) + eContent OCTET STRING -- Contains receipt + } + + FirmwarePackageLoadReceipt { + version INTEGER, -- The DEFAULT is always used + hwType OBJECT IDENTIFIER, -- Hardware module type + hwSerialNum OCTET STRING, -- H/W module serial number + fwPkgName PreferredOrLegacyPackageIdentifier, + trustAnchorKeyID OCTET STRING, -- Optional + decryptKeyID OCTET STRING -- Optional + } + + + + + +Housley Standards Track [Page 35] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + +3.1. Firmware Package Load Receipt CMS Content Type Profile + + This section specifies the conventions for using the CMS ContentInfo + and SignedData content types for firmware package load receipts. It + also defines the firmware package load receipt content type. + +3.1.1. ContentInfo + + The CMS requires that the outermost encapsulation be ContentInfo + [CMS]. The fields of ContentInfo are used as follows: + + contentType indicates the type of the associated content. If the + firmware package load receipt is signed, then the encapsulated + type MUST be SignedData, and the id-signedData + (1.2.840.113549.1.7.2) object identifier MUST be present in this + field. If the receipt is not signed, then the encapsulated type + MUST be FirmwarePackageLoadReceipt, and the id-ct- + firmwareLoadReceipt (1.2.840.113549.1.9.16.1.17) object identifier + MUST be present in this field. + + content holds the associated content. If the firmware package load + receipt is signed, then this field MUST contain the SignedData. + If the receipt is not signed, then this field MUST contain the + FirmwarePackageLoadReceipt. + +3.1.2. SignedData + + The SignedData content type contains the firmware package load + receipt and one digital signature. If the hardware module locally + stores its certificate, then the certificate can be included as well. + The fields of SignedData are used as follows: + + version is the syntax version number, and in this case, it MUST be + set to 3. + + digestAlgorithms is a collection of message digest algorithm + identifiers, and in this case, it MUST contain a single message + digest algorithm identifier. The message digest algorithms + employed by the hardware module MUST be present. + + encapContentInfo is the signed content, consisting of a content type + identifier and the content itself. The use of the + EncapsulatedContentInfo type is discussed further in Section + 3.1.2.2. + + certificates is an optional collection of certificates. If the + hardware module locally stores its certificate, then the X.509 + certificate of the hardware module SHOULD be included. If the + + + +Housley Standards Track [Page 36] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + hardware module does not, then the certificates field is omitted. + PKCS#6 extended certificates [PKCS#6] and attribute certificates + (either version 1 or version 2) [X.509-97, X.509-00, ACPROFILE] + MUST NOT be included in the set of certificates. + + crls is an optional collection of certificate revocation lists + (CRLs). CRLs MAY be included, but they will normally be omitted + since hardware modules will not generally have access to the most + recent CRL. Signed receipt recipients SHOULD be able to handle + the presence of the optional crls field. + + signerInfos is a collection of per-signer information, and in this + case, the collection MUST contain exactly one SignerInfo. The use + of the SignerInfo type is discussed further in Section 3.1.2.1. + +3.1.2.1. SignerInfo + + The hardware module is represented in the SignerInfo type. The + fields of SignerInfo are used as follows: + + version is the syntax version number, and it MUST be either 1 or 3, + depending on the method used to identify the hardware module's + public key. The use of the subjectKeyIdentifier is RECOMMENDED, + which results in the use of version 3. + + sid specifies the hardware module's certificate (and thereby the + hardware module's public key). CMS supports two alternatives: + issuerAndSerialNumber and subjectKeyIdentifier. The hardware + module MUST support one or both of the alternatives for receipt + generation; however, the support of subjectKeyIdentifier is + RECOMMENDED. The issuerAndSerialNumber alternative identifies the + hardware module's certificate by the issuer's distinguished name + and the certificate serial number. The identified certificate, in + turn, contains the hardware module's public key. The + subjectKeyIdentifier alternative identifies the hardware module's + public key directly. When this public key is contained in a + certificate, this identifier SHOULD appear in the X.509 + subjectKeyIdentifier extension. + + digestAlgorithm identifies the message digest algorithm, and any + associated parameters, used by the hardware module. It MUST + contain the message digest algorithms employed to sign the + receipt. (Note that this message digest algorithm identifier MUST + be the same as the one carried in the digestAlgorithms value in + SignedData.) + + + + + + +Housley Standards Track [Page 37] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + signedAttrs is an optional collection of attributes that are signed + along with the content. The signedAttrs are optional in the CMS, + but in this specification, signedAttrs are REQUIRED for use with + the firmware package load receipt content. The SET OF attributes + MUST be DER encoded [X.509-88]. Section 3.2 of this document + lists the attributes that MUST be included in the collection. + Other attributes MAY be included, but the recipient will ignore + any unrecognized signed attributes. + + signatureAlgorithm identifies the signature algorithm, and any + associated parameters, used to sign the receipt. + + signature is the digital signature. + + unsignedAttrs is an optional collection of attributes that are not + signed, and in this case, there MUST NOT be any unsigned + attributes present. + +3.1.2.2. EncapsulatedContentInfo + + The FirmwarePackageLoadReceipt is encapsulated in an OCTET STRING, + and it is carried within the EncapsulatedContentInfo type. The + fields of EncapsulatedContentInfo are used as follows: + + eContentType is an object identifier that uniquely specifies the + content type, and in this case, it MUST be the value of id-ct- + firmwareLoadReceipt (1.2.840.113549.1.9.16.1.17). + + eContent is the firmware package load receipt, encapsulated in an + OCTET STRING. The eContent octet string need not be DER encoded. + +3.1.3. FirmwarePackageLoadReceipt + + The following object identifier identifies the firmware package load + receipt content type: + + id-ct-firmwareLoadReceipt OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) ct(1) 17 } + + + + + + + + + + + + +Housley Standards Track [Page 38] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + The firmware package load receipt content type has the ASN.1 type + FirmwarePackageLoadReceipt: + + FirmwarePackageLoadReceipt ::= SEQUENCE { + version FWReceiptVersion DEFAULT v1, + hwType OBJECT IDENTIFIER, + hwSerialNum OCTET STRING, + fwPkgName PreferredOrLegacyPackageIdentifier, + trustAnchorKeyID OCTET STRING OPTIONAL, + decryptKeyID [1] OCTET STRING OPTIONAL } + + FWReceiptVersion ::= INTEGER { v1(1) } + + The fields of the FirmwarePackageLoadReceipt type have the following + meanings: + + version is an integer that provides the syntax version number for + compatibility with future revisions of this specification. + Implementations that conform to this specification MUST set the + version to the default value, which is v1. + + hwType is an object identifier that identifies the type of hardware + module on which the firmware package was loaded. + + hwSerialNum is the serial number of the hardware module on which the + firmware package was loaded. No particular structure is imposed + on the serial number; it need not be an integer. However, the + combination of the hwType and hwSerialNum uniquely identifies the + hardware module. + + fwPkgName identifies the firmware package that was loaded. As + described in Section 2.2.3, two approaches to naming firmware + packages are supported: legacy and preferred. A legacy firmware + package name is an octet string. A preferred firmware package + name is a combination of the firmware package object identifier + and an integer version number. + + trustAnchorKeyID is optional, and when it is present, it identifies + the trust anchor that was used to validate the firmware package + signature. + + decryptKeyID is optional, and when it is present, it identifies the + firmware-decryption key that was used to decrypt the firmware + package. + + The firmware package load receipt MUST include the version, hwType, + hwSerialNum, and fwPkgName fields, and it SHOULD include the + trustAnchorKeyID field. The firmware package load receipt MUST NOT + + + +Housley Standards Track [Page 39] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + include the decryptKeyID, unless the firmware package associated with + the receipt is encrypted, the firmware-decryption key is available to + the hardware module, and the firmware package was successfully + decrypted. + +3.2. Signed Attributes + + The hardware module MUST digitally sign a collection of attributes + along with the firmware package load receipt. Each attribute in the + collection MUST be DER encoded [X.509-88]. The syntax for attributes + is defined in [CMS], and it was repeated in Section 2.2 for + convenience. + + Each of the attributes used with this profile has a single attribute + value, even though the syntax is defined as a SET OF AttributeValue. + There MUST be exactly one instance of AttributeValue present. + + The SignedAttributes syntax within signerInfo is defined as a SET OF + Attributes. The SignedAttributes MUST include only one instance of + any particular attribute. + + The hardware module MUST include the content-type and message-digest + attributes. If the hardware module includes a real-time clock, then + the hardware module SHOULD also include the signing-time attribute. + The hardware module MAY include any other attribute that it deems + appropriate. + +3.2.1. Content Type + + The hardware module MUST include a content-type attribute with the + value of id-ct-firmwareLoadReceipt (1.2.840.113549.1.9.16.1.17). + Section 11.1 of [CMS] defines the content-type attribute. + +3.2.2. Message Digest + + The hardware module MUST include a message-digest attribute, having + as its value the message digest of the FirmwarePackageLoadReceipt + content. Section 11.2 of [CMS] defines the message-digest attribute. + +3.2.3. Signing Time + + If the hardware module includes a real-time clock, then the hardware + module SHOULD include a signing-time attribute, specifying the time + at which the receipt was generated. Section 11.3 of [CMS] defines + the signing-time attribute. + + + + + + +Housley Standards Track [Page 40] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + +4. Firmware Package Load Error + + The Cryptographic Message Syntax (CMS) is used to indicate that an + error has occurred while attempting to load a protected firmware + package. Support for firmware package load error reports is + OPTIONAL. However, those hardware modules that choose to generate + such error reports MUST follow the conventions specified in this + section. Not all hardware modules have private signature keys; + therefore the firmware package load error report can be either signed + or unsigned. Use of the signed firmware package error report is + RECOMMENDED. + + Hardware modules that support error report generation MUST have a + unique serial number. Hardware modules that support signed error + report generation MUST also have a private signature key to sign the + error report and the corresponding signature validation certificate + or its designator. The designator is the certificate issuer name and + the certificate serial number, or it is the public key identifier. + Memory-constrained hardware modules will generally store the public + key identifier since it requires less storage. + + The unsigned firmware package load error report is encapsulated by + ContentInfo. Alternatively, the signed firmware package load error + report is encapsulated by SignedData, which is in turn encapsulated + by ContentInfo. + + The firmware package load error report is summarized as follows (see + [CMS] for the full syntax): + + ContentInfo { + contentType id-signedData, -- (1.2.840.113549.1.7.2) + -- OR -- + id-ct-firmwareLoadError, + -- (1.2.840.113549.1.9.16.1.18) + content SignedData + -- OR -- + FirmwarePackageLoadError + } + + SignedData { + version CMSVersion, -- Always set to 3 + digestAlgorithms DigestAlgorithmIdentifiers, -- Only one + encapContentInfo EncapsulatedContentInfo, + certificates CertificateSet, -- Optional Module certificate + crls CertificateRevocationLists, -- Optional + signerInfos SET OF SignerInfo -- Only one + } + + + + +Housley Standards Track [Page 41] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + SignerInfo { + version CMSVersion, -- either set to 1 or 3 + sid SignerIdentifier, + digestAlgorithm DigestAlgorithmIdentifier, + signedAttrs SignedAttributes, -- Required + signatureAlgorithm SignatureAlgorithmIdentifier, + signature SignatureValue, + unsignedAttrs UnsignedAttributes -- Omit + } + + EncapsulatedContentInfo { + eContentType id-ct-firmwareLoadError, + -- (1.2.840.113549.1.9.16.1.18) + eContent OCTET STRING -- Contains error report + } + + FirmwarePackageLoadError { + version INTEGER, -- The DEFAULT is always used + hwType OBJECT IDENTIFIER, -- Hardware module type + hwSerialNum OCTET STRING, -- H/W module serial number + errorCode FirmwarePackageLoadErrorCode -- Error identifier + vendorErrorCode VendorErrorCode, -- Optional + fwPkgName PreferredOrLegacyPackageIdentifier, -- Optional + config SEQUENCE OF CurrentFWConfig, -- Optional + } + + CurrentFWConfig { -- Repeated for each package in configuration + fwPkgType INTEGER, -- Firmware package type; Optional + fwPkgName PreferredOrLegacyPackageIdentifier + } + +4.1. Firmware Package Load Error CMS Content Type Profile + + This section specifies the conventions for using the CMS ContentInfo + and SignedData content types for firmware package load error reports. + It also defines the firmware package load error content type. + +4.1.1. ContentInfo + + The CMS requires that the outermost encapsulation be ContentInfo + [CMS]. The fields of ContentInfo are used as follows: + + contentType indicates the type of the associated content. If the + firmware package load error report is signed, then the + encapsulated type MUST be SignedData, and the id-signedData + (1.2.840.113549.1.7.2) object identifier MUST be present in this + field. If the report is not signed, then the encapsulated type + + + + +Housley Standards Track [Page 42] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + MUST be FirmwarePackageLoadError, and the id-ct-firmwareLoadError + (1.2.840.113549.1.9.16.1.18) object identifier MUST be present in + this field. + + content holds the associated content. If the firmware package load + error report is signed, then this field MUST contain the + SignedData. If the report is not signed, then this field MUST + contain the FirmwarePackageLoadError. + +4.1.2. SignedData + + The SignedData content type contains the firmware package load error + report and one digital signature. If the hardware module locally + stores its certificate, then the certificate can be included as well. + The fields of SignedData are used exactly as described in Section + 3.1.2. + +4.1.2.1. SignerInfo + + The hardware module is represented in the SignerInfo type. The + fields of SignerInfo are used exactly as described in Section + 3.1.2.1. + +4.1.2.2. EncapsulatedContentInfo + + The FirmwarePackageLoadError is encapsulated in an OCTET STRING, and + it is carried within the EncapsulatedContentInfo type. The fields of + EncapsulatedContentInfo are used as follows: + + eContentType is an object identifier that uniquely specifies the + content type, and in this case, it MUST be the value of id-ct- + firmwareLoadError (1.2.840.113549.1.9.16.1.18). + + eContent is the firmware package load error report, encapsulated in + an OCTET STRING. The eContent octet string need not be DER + encoded. + +4.1.3. FirmwarePackageLoadError + + The following object identifier identifies the firmware package load + error report content type: + + id-ct-firmwareLoadError OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) ct(1) 18 } + + + + + + +Housley Standards Track [Page 43] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + The firmware package load error report content type has the ASN.1 + type FirmwarePackageLoadError: + + FirmwarePackageLoadError ::= SEQUENCE { + version FWErrorVersion DEFAULT v1, + hwType OBJECT IDENTIFIER, + hwSerialNum OCTET STRING, + errorCode FirmwarePackageLoadErrorCode, + vendorErrorCode VendorLoadErrorCode OPTIONAL, + fwPkgName PreferredOrLegacyPackageIdentifier OPTIONAL, + config [1] SEQUENCE OF CurrentFWConfig OPTIONAL } + + FWErrorVersion ::= INTEGER { v1(1) } + + CurrentFWConfig ::= SEQUENCE { + fwPkgType INTEGER OPTIONAL, + fwPkgName PreferredOrLegacyPackageIdentifier } + + FirmwarePackageLoadErrorCode ::= ENUMERATED { + decodeFailure (1), + badContentInfo (2), + badSignedData (3), + badEncapContent (4), + badCertificate (5), + badSignerInfo (6), + badSignedAttrs (7), + badUnsignedAttrs (8), + missingContent (9), + noTrustAnchor (10), + notAuthorized (11), + badDigestAlgorithm (12), + badSignatureAlgorithm (13), + unsupportedKeySize (14), + signatureFailure (15), + contentTypeMismatch (16), + badEncryptedData (17), + unprotectedAttrsPresent (18), + badEncryptContent (19), + badEncryptAlgorithm (20), + missingCiphertext (21), + noDecryptKey (22), + decryptFailure (23), + badCompressAlgorithm (24), + missingCompressedContent (25), + decompressFailure (26), + wrongHardware (27), + stalePackage (28), + notInCommunity (29), + + + +Housley Standards Track [Page 44] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + unsupportedPackageType (30), + missingDependency (31), + wrongDependencyVersion (32), + insufficientMemory (33), + badFirmware (34), + unsupportedParameters (35), + breaksDependency (36), + otherError (99) } + + VendorLoadErrorCode ::= INTEGER + + The fields of the FirmwarePackageLoadError type have the following + meanings: + + version is an integer, and it provides the syntax version number for + compatibility with future revisions of this specification. + Implementations that conform to this specification MUST set the + version to the default value, which is v1. + + hwType is an object identifier that identifies the type of hardware + module on which the firmware package load was attempted. + + hwSerialNum is the serial number of the hardware module on which the + firmware package load was attempted. No particular structure is + imposed on the serial number; it need not be an integer. However, + the combination of the hwType and hwSerialNum uniquely identifies + the hardware module. + + errorCode identifies the error that occurred. + + vendorErrorCode is optional; however, it MUST be present if the + errorCode contains a value of otherError. When errorCode contains + a value other than otherError, the vendorErrorCode can provide + vendor-specific supplemental information. + + fwPkgName is optional. When it is present, it identifies the + firmware package that was being loaded when the error occurred. + As described in Section 2.2.3, two approaches to naming firmware + packages are supported: legacy and preferred. A legacy firmware + package name is an octet string. A preferred firmware package + name is a combination of the firmware package object identifier + and an integer version number. + + config identifies the current firmware configuration. The field is + OPTIONAL, but support for this field is RECOMMENDED for hardware + modules that permit the loading of more than one firmware package. + One instance of CurrentFWConfig is used to provide information + about each firmware package in hardware module. + + + +Housley Standards Track [Page 45] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + The fields of the CurrentFWConfig type have the following meanings: + + fwPkgType identifies the firmware package type. The firmware package + type is an INTEGER, and the meaning of the integer value is + specific to each hardware module. + + fwPkgName identifies the firmware package. As described in Section + 2.2.3, two approaches to naming firmware packages are supported: + legacy and preferred. A legacy firmware package name is an octet + string. A preferred firmware package name is a combination of the + firmware package object identifier and an integer version number. + + The errorCode values have the following meanings: + + decodeFailure: The ASN.1 decode of the firmware package load failed. + The provided input did not conform to BER, or it was not ASN.1 at + all. + + badContentInfo: Invalid ContentInfo syntax, or the contentType + carried within the ContentInfo is unknown or unsupported. + + badSignedData: Invalid SignedData syntax, the version is unknown or + unsupported, or more than one entry is present in + digestAlgorithms. + + badEncapContent: Invalid EncapsulatedContentInfo syntax, or the + contentType carried within the eContentType is unknown or + unsupported. This error can be generated due to problems located + in SignedData or CompressedData. + + badCertificate: Invalid syntax for one or more certificates in + CertificateSet. + + badSignerInfo: Invalid SignerInfo syntax, or the version is unknown + or unsupported. + + badSignedAttrs: Invalid signedAttrs syntax within SignerInfo. + + badUnsignedAttrs: The unsignedAttrs within SignerInfo contains an + attribute other than the wrapped-firmware-decryption-key + attribute, which is the only unsigned attribute supported by this + specification. + + missingContent: The optional eContent is missing in + EncapsulatedContentInfo, which is required in this specification. + This error can be generated due to problems located in SignedData + or CompressedData. + + + + +Housley Standards Track [Page 46] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + noTrustAnchor: Two situations can lead to this error. In one case, + the subjectKeyIdentifier does not identify the public key of a + trust anchor or a certification path that terminates with an + installed trust anchor. In the other case, the + issuerAndSerialNumber does not identify the public key of a trust + anchor or a certification path that terminates with an installed + trust anchor. + + notAuthorized: The sid within SignerInfo leads to an installed trust + anchor, but that trust anchor is not an authorized firmware + package signer. + + badDigestAlgorithm: The digestAlgorithm in either SignerInfo or + SignedData is unknown or unsupported. + + badSignatureAlgorithm: The signatureAlgorithm in SignerInfo is + unknown or unsupported. + + unsupportedKeySize: The signatureAlgorithm in SignerInfo is known and + supported, but the firmware package signature could not be + validated because an unsupported key size was employed by the + signer. + + signatureFailure: The signatureAlgorithm in SignerInfo is known and + supported, but the signature in signature in SignerInfo could not + be validated. + + contentTypeMismatch: The contentType carried within the eContentType + does not match the content type carried in the signed attribute. + + badEncryptedData: Invalid EncryptedData syntax; the version is + unknown or unsupported. + + unprotectedAttrsPresent: EncryptedData contains unprotectedAttrs, + which are not permitted in this specification. + + badEncryptContent: Invalid EncryptedContentInfo syntax, or the + contentType carried within the contentType is unknown or + unsupported. + + badEncryptAlgorithm: The firmware-encryption algorithm identified by + contentEncryptionAlgorithm in EncryptedContentInfo is unknown or + unsupported. + + missingCiphertext: The optional encryptedContent is missing in + EncryptedContentInfo, which is required in this specification. + + + + + +Housley Standards Track [Page 47] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + noDecryptKey: The hardware module does not have the firmware- + decryption key named in the decrypt key identifier signed + attribute. + + decryptFailure: The firmware package did not decrypt properly. + + badCompressAlgorithm: The compression algorithm identified by + compressionAlgorithm in CompressedData is unknown or unsupported. + + missingCompressedContent: The optional eContent is missing in + EncapsulatedContentInfo, which is required in this specification. + + decompressFailure: The firmware package did not decompress properly. + + wrongHardware: The processing hardware module is not listed in the + target hardware module identifiers signed attribute. + + stalePackage: The firmware package is rejected because it is stale. + + notInCommunity: The hardware module is not a member of the community + described in the community identifiers signed attribute. + + unsupportedPackageType: The firmware package type identified in the + firmware package information signed attribute is not supported by + the combination of the hardware module and the bootstrap loader. + + missingDependency: The firmware package being loaded depends on + routines that are part of another firmware package, but that + firmware package is not available. + + wrongDependencyVersion: The firmware package being loaded depends on + routines that are part of the another firmware package, and the + available version of that package has an older version number than + is required. The available firmware package does not fulfill the + dependencies. + + insufficientMemory: The firmware package could not be loaded because + the hardware module did not have sufficient memory. + + badFirmware: The signature on the firmware package was validated, but + the firmware package itself was not in an acceptable format. The + details will be specific to each hardware module. For example, a + hardware module that is composed of multiple firmware-programmable + components could not find the internal tagging within the firmware + package to distribute executable code to each of the components. + + + + + + +Housley Standards Track [Page 48] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + unsupportedParameters: The signature on the firmware package could + not be validated because the signer used signature algorithm + parameters that are not supported by the hardware module signature + verification routines. + + breaksDependency: Another firmware package has a dependency that can + no longer be satisfied if the firmware package being loaded is + accepted. + + otherError: An error occurred that does not fit any of the previous + error codes. + +4.2. Signed Attributes + + The hardware module MUST digitally sign a collection of attributes + along with the firmware package load error report. Each attribute in + the collection MUST be DER encoded [X.509-88]. The syntax for + attributes is defined in [CMS], and it was repeated in Section 2.2 + for convenience. + + Each of the attributes used with this profile has a single attribute + value, even though the syntax is defined as a SET OF AttributeValue. + There MUST be exactly one instance of AttributeValue present. + + The SignedAttributes syntax within signerInfo is defined as a SET OF + Attributes. The SignedAttributes MUST include only one instance of + any particular attribute. + + The hardware module MUST include the content-type and message-digest + attributes. If the hardware module includes a real-time clock, then + the hardware module SHOULD also include the signing-time attribute. + The hardware module MAY include any other attribute that it deems + appropriate. + +4.2.1. Content Type + + The hardware module MUST include a content-type attribute with the + value of id-ct-firmwareLoadError (1.2.840.113549.1.9.16.1.18). + Section 11.1 of [CMS] defines the content-type attribute. + +4.2.2. Message Digest + + The hardware module MUST include a message-digest attribute, having + as its value the message digest of the FirmwarePackageLoadError + content. Section 11.2 of [CMS] defines the message-digest attribute. + + + + + + +Housley Standards Track [Page 49] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + +4.2.3. Signing Time + + If the hardware module includes a real-time clock, then hardware + module SHOULD include a signing-time attribute, specifying the time + at which the firmware package load error report was generated. + Section 11.3 of [CMS] defines the signing-time attribute. + +5. Hardware Module Name + + Support for firmware package load receipts, as discussed in Section + 3, is OPTIONAL, and support for the firmware package load error + reports, as discussed in Section 4, is OPTIONAL. Hardware modules + that support receipt or error report generation MUST have unique + serial numbers. Further, hardware modules that support signed + receipt or error report generation MUST have private signature keys + and corresponding signature validation certificates [PROFILE] or + their designators. The conventions for hardware module naming in the + signature validation certificates are specified in this section. + + The hardware module vendor or a trusted third party MUST issue the + signature validation certificate prior to deployment of the hardware + module. The certificate is likely to be issued at the time of + manufacture. The subject alternative name in this certificate + identifies the hardware module. The subject distinguished name is + empty, but a critical subject alternative name extension contains the + hardware module name, using the otherName choice within the + GeneralName structure. + + The hardware module name form is identified by the id-on- + hardwareModuleName object identifier: + + id-on-hardwareModuleName OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) dod(6) internet(1) security(5) + mechanisms(5) pkix(7) on(8) 4 } + + A HardwareModuleName is composed of an object identifier and an octet + string: + + HardwareModuleName ::= SEQUENCE { + hwType OBJECT IDENTIFIER, + hwSerialNum OCTET STRING } + + The fields of the HardwareModuleName type have the following + meanings: + + hwType is an object identifier that identifies the type of hardware + module. A unique object identifier names a hardware model and + revision. + + + +Housley Standards Track [Page 50] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + hwSerialNum is the serial number of the hardware module. No + particular structure is imposed on the serial number; it need not + be an integer. However, the combination of the hwType and + hwSerialNum uniquely identifies the hardware module. + +6. Security Considerations + + This document describes the use of the Cryptographic Message Syntax + (CMS) to protect firmware packages; therefore, the security + considerations discussed in [CMS] apply to this specification as + well. + + The conventions specified in this document raise a few security + considerations of their own. + +6.1. Cryptographic Keys and Algorithms + + Private signature keys must be protected. Compromise of the private + key used to sign firmware packages permits unauthorized parties to + generate firmware packages that are acceptable to hardware modules. + Compromise of the hardware module private key allows unauthorized + parties to generate signed firmware package load receipts and error + reports. + + The firmware-decryption key must be protected. Compromise of the key + may result in the disclosure of the firmware package to unauthorized + parties. + + Cryptographic algorithms become weaker with time. As new + cryptanalysis techniques are developed and computing performance + improves, the work factor to break a particular cryptographic + algorithm will be reduced. The ability to change the firmware + package provides an opportunity to update or replace cryptographic + algorithms. Although this capability is desirable, cryptographic + algorithm replacement can lead to interoperability failures. + Therefore, the rollout of new cryptographic algorithms must be + managed. Generally, the previous generation of cryptographic + algorithms and their replacements need to be supported at the same + time in order to facilitate an orderly transition. + +6.2. Random Number Generation + + When firmware packages are encrypted, the source of the firmware + package must randomly generate firmware-encryption keys. Also, the + generation of public/private signature key pairs relies on a random + numbers. The use of inadequate pseudo-random number generators + (PRNGs) to generate cryptographic keys can result in little or no + security. An attacker may find it much easier to reproduce the PRNG + + + +Housley Standards Track [Page 51] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + environment that produced the keys, searching the resulting small set + of possibilities, rather than brute-force searching the whole key + space. The generation of quality random numbers is difficult. RFC + 4086 [RANDOM] offers important guidance in this area. + +6.3. Stale Firmware Package Version Number + + The firmware signer determines whether a stale version number is + included. The policy of the firmware signer needs to consider many + factors. Consider the flaw found by Ian Goldberg and David Wagner in + the random number generator of the Netscape browser in 1996 [DDJ]. + This flaw completely undermines confidentiality protection. A + firmware signer might use the stale version number to ensure that + upgraded hardware modules do not resume use of the flawed firmware. + However, another firmware signer may not consider this an appropriate + situation to employ the stale version number, preferring to delegate + this decision to someone closer to the operation of the hardware + module. Such a person is likely to be in a better position to + evaluate whether other bugs introduced in the newer firmware package + impose worse operational concerns than the confidentiality concern + caused by the flawed random number generator. For example, a user + who never uses the encryption feature of the flawed Netscape browser + will determine the most appropriate version to use without + considering the random number flaw or its fix. + + The stale version number is especially useful when the security + interests of the person choosing which firmware package version to + load into a particular hardware module do not align with the security + interests of the firmware package signer. For example, stale version + numbers may be useful in hardware modules that provide digital rights + management (DRM). Also, stale version numbers will be useful when + the deployment organization (as opposed to the firmware package + vendor) is the firmware signer. Further, stale version numbers will + be useful for firmware packages that need to be trusted to implement + organizational (as opposed to the deployment organization) security + policy, regardless of whether the firmware signer is the deployment + organization or the vendor. For example, hardware devices employed + by the military will probably make use of stale version numbers. + + The use of a stale version number in a firmware package that employs + the preferred firmware package name form cannot completely prevent + subsequent use of the stale firmware package. Despite this + shortcoming, the feature is included since it is useful in some + important situations. By loading different types of firmware + packages, each with its own stale firmware package version number + until the internal storage for the stale version number is exceeded, + the user can circumvent the mechanism. Consider a hardware module + + + + +Housley Standards Track [Page 52] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + that has storage for two stale version numbers. Suppose that FWPKG-A + version 3 is loaded, indicating that FWPKG-A version 2 is stale. The + user can sequentially load the following: + + - FWPKG-B version 8, indicating that FWPKG-B version 4 is stale. + (Note: The internal storage indicates that FWPKG-A version 2 + and FWPKG-B version 4 are stale.) + + - FWPKG-C version 5, indicating that FWPKG-C version 3 is stale. + (Note: The internal storage indicates that FWPKG-B version 4 + and FWPKG-C version 3 are stale.) + + - FWPKG-A version 2. + + Because many hardware modules are expected to have very few firmware + packages written for them, the stale firmware package version feature + provides important protections. The amount of non-volatile storage + that needs to be dedicated to saving firmware package identifiers and + version numbers depends on the number of firmware packages that are + likely to be developed for the hardware module. + + The use of legacy firmware package name form does not improve this + situation. In fact, the legacy firmware package names are usually + larger than an object identifier. Thus, comparable stale version + protection requires more memory. + + A firmware signer can ensure that stale version numbers are honored + by limiting the number of different types of firmware packages that + are signed. If all of the hardware modules are able to store a stale + version number for each of the different types of firmware package, + then the hardware module will be able to provide the desired + protection. This requires the firmware signer to have a deep + understanding of all of the hardware modules that might accept the + firmware package. + +6.4. Community Identifiers + + When a firmware package includes a community identifier, the + confidence that the package is only used by the intended community + depends on the mechanism used to configure community membership. + This document does not specify a mechanism for the assignment of + community membership to hardware modules, and the various + alternatives have different security properties. Also, the authority + that makes community identifier assignments to hardware modules might + be different than the authority that generates firmware packages. + + + + + + +Housley Standards Track [Page 53] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + +7. References + +7.1. Normative References + + [COMPRESS] Gutmann, P., "Compressed Data Content Type for + Cryptographic Message Syntax (CMS)", RFC 3274, June + 2002. + + [CMS] Housley, R., "Cryptographic Message Syntax (CMS)", RFC + 3852, July 2004. + + [ESS] Hoffman, P., "Enhanced Security Services for S/MIME", + RFC 2634, June 1999. + + [PROFILE] Housley, R., Polk, W., Ford, W., and D. Solo, "Internet + X.509 Public Key Infrastructure Certificate and + Certificate Revocation List (CRL) Profile", RFC 3280, + April 2002. + + [SHA1] National Institute of Standards and Technology. FIPS + Pub 180-1: Secure Hash Standard. 17 April 1995. + + [STDWORDS] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [UTF-8] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", STD 63, RFC 3629, November 2003. + + [X.208-88] CCITT. Recommendation X.208: Specification of Abstract + Syntax Notation One (ASN.1). 1988. + + [X.209-88] CCITT. Recommendation X.209: Specification of Basic + Encoding Rules for Abstract Syntax Notation One (ASN.1). + 1988. + + [X.509-88] CCITT. Recommendation X.509: The Directory - + Authentication Framework. 1988. + +7.2. Informative References + + [ACPROFILE] Farrell, S. and R. Housley, "An Internet Attribute + Certificate Profile for Authorization", RFC 3281, April + 2002. + + [AES] National Institute of Standards and Technology. FIPS + Pub 197: Advanced Encryption Standard (AES). 26 + November 2001. + + + + +Housley Standards Track [Page 54] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + [DDJ] Goldberg, I. and D. Wagner. "Randomness and the + Netscape Browser." Dr. Dobb's Journal, January 1996. + + [DPD&DPV] Pinkas, D. and R. Housley, "Delegated Path Validation + and Delegated Path Discovery Protocol Requirements", RFC + 3379, September 2002. + + [OCSP] Myers, M., Ankney, R., Malpani, A., Galperin, S., and C. + Adams, "X.509 Internet Public Key Infrastructure Online + Certificate Status Protocol - OCSP", RFC 2560, June + 1999. + + [PKCS#6] RSA Laboratories. PKCS #6: Extended-Certificate Syntax + Standard, Version 1.5. November 1993. + + [RANDOM] Eastlake, D., 3rd, Schiller, J., and S. Crocker, + "Randomness Requirements for Security", BCP 106, RFC + 4086, June 2005. + + [SECREQMTS] National Institute of Standards and Technology. FIPS + Pub 140-2: Security Requirements for Cryptographic + Modules. 25 May 2001. + + [X.509-97] ITU-T. Recommendation X.509: The Directory - + Authentication Framework. 1997. + + [X.509-00] ITU-T. Recommendation X.509: The Directory - + Authentication Framework. 2000. + + + + + + + + + + + + + + + + + + + + + + + +Housley Standards Track [Page 55] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + +Appendix A: ASN.1 Module + + The ASN.1 module contained in this appendix defines the structures + that are needed to implement the CMS-based firmware package wrapper. + It is expected to be used in conjunction with the ASN.1 modules in + [CMS], [COMPRESS], and [PROFILE]. + + + CMSFirmwareWrapper + { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) + pkcs-9(9) smime(16) modules(0) cms-firmware-wrap(22) } + + DEFINITIONS IMPLICIT TAGS ::= BEGIN + + IMPORTS + EnvelopedData + FROM CryptographicMessageSyntax -- [CMS] + { iso(1) member-body(2) us(840) rsadsi(113549) + pkcs(1) pkcs-9(9) smime(16) modules(0) cms-2004(24) }; + + + -- Firmware Package Content Type and Object Identifier + + id-ct-firmwarePackage OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) ct(1) 16 } + + FirmwarePkgData ::= OCTET STRING + + + -- Firmware Package Signed Attributes and Object Identifiers + + id-aa-firmwarePackageID OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 35 } + + FirmwarePackageIdentifier ::= SEQUENCE { + name PreferredOrLegacyPackageIdentifier, + stale PreferredOrLegacyStalePackageIdentifier OPTIONAL } + + PreferredOrLegacyPackageIdentifier ::= CHOICE { + preferred PreferredPackageIdentifier, + legacy OCTET STRING } + + PreferredPackageIdentifier ::= SEQUENCE { + fwPkgID OBJECT IDENTIFIER, + verNum INTEGER (0..MAX) } + + + + +Housley Standards Track [Page 56] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + PreferredOrLegacyStalePackageIdentifier ::= CHOICE { + preferredStaleVerNum INTEGER (0..MAX), + legacyStaleVersion OCTET STRING } + + + id-aa-targetHardwareIDs OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 36 } + + TargetHardwareIdentifiers ::= SEQUENCE OF OBJECT IDENTIFIER + + + id-aa-decryptKeyID OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 37 } + + DecryptKeyIdentifier ::= OCTET STRING + + + id-aa-implCryptoAlgs OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 38 } + + ImplementedCryptoAlgorithms ::= SEQUENCE OF OBJECT IDENTIFIER + + id-aa-implCompressAlgs OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 43 } + + ImplementedCompressAlgorithms ::= SEQUENCE OF OBJECT IDENTIFIER + + + id-aa-communityIdentifiers OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 40 } + + CommunityIdentifiers ::= SEQUENCE OF CommunityIdentifier + + CommunityIdentifier ::= CHOICE { + communityOID OBJECT IDENTIFIER, + hwModuleList HardwareModules } + + HardwareModules ::= SEQUENCE { + hwType OBJECT IDENTIFIER, + hwSerialEntries SEQUENCE OF HardwareSerialEntry } + + + + + + +Housley Standards Track [Page 57] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + HardwareSerialEntry ::= CHOICE { + all NULL, + single OCTET STRING, + block SEQUENCE { + low OCTET STRING, + high OCTET STRING } } + + + id-aa-firmwarePackageInfo OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 42 } + + FirmwarePackageInfo ::= SEQUENCE { + fwPkgType INTEGER OPTIONAL, + dependencies SEQUENCE OF + PreferredOrLegacyPackageIdentifier OPTIONAL } + + + -- Firmware Package Unsigned Attributes and Object Identifiers + + id-aa-wrappedFirmwareKey OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 39 } + + WrappedFirmwareKey ::= EnvelopedData + + + -- Firmware Package Load Receipt Content Type and Object Identifier + + id-ct-firmwareLoadReceipt OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) ct(1) 17 } + + FirmwarePackageLoadReceipt ::= SEQUENCE { + version FWReceiptVersion DEFAULT v1, + hwType OBJECT IDENTIFIER, + hwSerialNum OCTET STRING, + fwPkgName PreferredOrLegacyPackageIdentifier, + trustAnchorKeyID OCTET STRING OPTIONAL, + decryptKeyID [1] OCTET STRING OPTIONAL } + + FWReceiptVersion ::= INTEGER { v1(1) } + + + + + + + + + +Housley Standards Track [Page 58] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + -- Firmware Package Load Error Report Content Type + -- and Object Identifier + + id-ct-firmwareLoadError OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) ct(1) 18 } + + FirmwarePackageLoadError ::= SEQUENCE { + version FWErrorVersion DEFAULT v1, + hwType OBJECT IDENTIFIER, + hwSerialNum OCTET STRING, + errorCode FirmwarePackageLoadErrorCode, + vendorErrorCode VendorLoadErrorCode OPTIONAL, + fwPkgName PreferredOrLegacyPackageIdentifier OPTIONAL, + config [1] SEQUENCE OF CurrentFWConfig OPTIONAL } + + FWErrorVersion ::= INTEGER { v1(1) } + + CurrentFWConfig ::= SEQUENCE { + fwPkgType INTEGER OPTIONAL, + fwPkgName PreferredOrLegacyPackageIdentifier } + + FirmwarePackageLoadErrorCode ::= ENUMERATED { + decodeFailure (1), + badContentInfo (2), + badSignedData (3), + badEncapContent (4), + badCertificate (5), + badSignerInfo (6), + badSignedAttrs (7), + badUnsignedAttrs (8), + missingContent (9), + noTrustAnchor (10), + notAuthorized (11), + badDigestAlgorithm (12), + badSignatureAlgorithm (13), + unsupportedKeySize (14), + signatureFailure (15), + contentTypeMismatch (16), + badEncryptedData (17), + unprotectedAttrsPresent (18), + badEncryptContent (19), + badEncryptAlgorithm (20), + missingCiphertext (21), + noDecryptKey (22), + decryptFailure (23), + badCompressAlgorithm (24), + missingCompressedContent (25), + + + +Housley Standards Track [Page 59] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + + decompressFailure (26), + wrongHardware (27), + stalePackage (28), + notInCommunity (29), + unsupportedPackageType (30), + missingDependency (31), + wrongDependencyVersion (32), + insufficientMemory (33), + badFirmware (34), + unsupportedParameters (35), + breaksDependency (36), + otherError (99) } + + VendorLoadErrorCode ::= INTEGER + + + -- Other Name syntax for Hardware Module Name + + id-on-hardwareModuleName OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) dod(6) internet(1) security(5) + mechanisms(5) pkix(7) on(8) 4 } + + HardwareModuleName ::= SEQUENCE { + hwType OBJECT IDENTIFIER, + hwSerialNum OCTET STRING } + + + END + +Author's Address + + Russell Housley + Vigil Security, LLC + 918 Spring Knoll Drive + Herndon, VA 20170 + USA + + EMail: housley@vigilsec.com + + + + + + + + + + + + + +Housley Standards Track [Page 60] + +RFC 4108 Using CMS to Protect Firmware Packages August 2005 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2005). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE + INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at ietf- + ipr@ietf.org. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + +Housley Standards Track [Page 61] + diff --git a/doc/standardisation/rfc5587.txt b/doc/standardisation/rfc5587.txt new file mode 100644 index 000000000..1670bc58f --- /dev/null +++ b/doc/standardisation/rfc5587.txt @@ -0,0 +1,899 @@ + + + + + + +Network Working Group N. Williams +Request for Comments: 5587 Sun +Category: Standards Track July 2009 + + + Extended Generic Security Service Mechanism Inquiry APIs + +Abstract + + This document introduces new application programming interfaces + (APIs) to the Generic Security Services API (GSS-API) for extended + mechanism attribute inquiry. These interfaces are primarily intended + to reduce instances of hardcoding of mechanism identifiers in GSS + applications. + + These interfaces include mechanism attributes and attribute sets, a + function for inquiring the attributes of a mechanism, a function for + indicating mechanisms that possess given attributes, and a function + for displaying mechanism attributes. + +Status of This Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (c) 2009 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents in effect on the date of + publication of this document (http://trustee.ietf.org/license-info). + Please review these documents carefully, as they describe your rights + and restrictions with respect to this document. + + + + + + + + + + + + + +Williams Standards Track [Page 1] + +RFC 5587 Extended GSS Mech Inquiry July 2009 + + +Table of Contents + + 1. Introduction ....................................................2 + 2. Conventions Used in This Document ...............................2 + 3. New GSS-API Interfaces ..........................................3 + 3.1. Mechanism Attributes and Attribute Sets ....................3 + 3.2. List of Known Mechanism Attributes .........................4 + 3.3. Mechanism Attribute Sets of Existing Mechs .................6 + 3.4. New GSS-API Function Interfaces ............................8 + 3.4.1. Mechanism Attribute Criticality .....................8 + 3.4.2. GSS_Indicate_mechs_by_attrs() .......................9 + 3.4.3. GSS_Inquire_attrs_for_mech() .......................10 + 3.4.4. GSS_Display_mech_attr() ............................10 + 3.4.5. New Major Status Values ............................11 + 3.4.6. C-Bindings .........................................11 + 4. Requirements for Mechanism Designers ...........................13 + 5. IANA Considerations ............................................13 + 6. Security Considerations ........................................13 + 7. References .....................................................13 + 7.1. Normative References ......................................13 + 7.2. Informative References ....................................14 +Appendix A. Typedefs and C Bindings ..................................15 + +1. Introduction + + GSS-API [RFC2743] mechanisms have a number of properties that may be + of interest to applications. The lack of APIs for inquiring about + available mechanisms' properties has meant that many GSS-API + applications must hardcode mechanism Object Identifiers (OIDs). + Ongoing work may result in a variety of new GSS-API mechanisms. + Applications should not have to hardcode their OIDs. + + For example, the Secure Shell version 2 (SSHv2) protocol [RFC4251] + supports the use of GSS-API mechanisms for authentication [RFC4462] + but explicitly prohibits the use of Simple and Protected GSS-API + Negotiation (SPNEGO) [RFC4178]. Future mechanisms that negotiate + mechanisms would have to be forbidden as well, but there is no way to + implement applications that inquire what mechanisms are available and + then programmatically exclude mechanisms "like SPNEGO". + +2. Conventions Used in This Document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC2119]. + + + + + + +Williams Standards Track [Page 2] + +RFC 5587 Extended GSS Mech Inquiry July 2009 + + +3. New GSS-API Interfaces + + We introduce a new concept -- that of mechanism attributes. By + allowing applications to query the set of attributes associated with + individual mechanisms and to find out which mechanisms support a + given set of attributes, we allow applications to select mechanisms + based on their attributes without having to hardcode mechanism OIDs. + + Section 3.1 describes the mechanism attributes concept. Sections + 3.4.2, 3.4.3, and 3.4.4 describe three new interfaces that deal in + mechanisms and attribute sets: + + o GSS_Indicate_mechs_by_attrs() + + o GSS_Inquire_attrs_for_mech() + + o GSS_Display_mech_attr() + +3.1. Mechanism Attributes and Attribute Sets + + An abstraction for the features provided by mechanisms and pseudo- + mechanisms is needed in order to facilitate the programmatic + selection of mechanisms. Pseudo-mechanisms are mechanisms that make + reference to other mechanisms in order to provide their services. + For example, SPNEGO is a pseudo-mechanism, for without other + mechanisms SPNEGO is useless. + + Two data types are needed: one for individual mechanism attributes + and one for mechanism attribute sets. To simplify the mechanism + attribute interfaces, we reuse the 'OID' and 'OID set' data types and + model individual mechanism attribute types as OIDs. + + To this end, we define an open namespace of mechanism attributes and + assign them arcs off of this OID: + + <1.3.6.1.5.5.13> + + Each mechanism has a set of mechanism attributes that it supports as + described in its specification. + + + + + + + + + + + + +Williams Standards Track [Page 3] + +RFC 5587 Extended GSS Mech Inquiry July 2009 + + +3.2. List of Known Mechanism Attributes + + +-------------------------+---------+-------------------------+ + | Mech Attr Name | OID Arc | Arc Name | + +-------------------------+---------+-------------------------+ + | GSS_C_MA_MECH_CONCRETE | (1) | concrete-mech | + | GSS_C_MA_MECH_PSEUDO | (2) | pseudo-mech | + | GSS_C_MA_MECH_COMPOSITE | (3) | composite-mech | + | GSS_C_MA_MECH_NEGO | (4) | mech-negotiation-mech | + | GSS_C_MA_MECH_GLUE | (5) | mech-glue | + | GSS_C_MA_NOT_MECH | (6) | not-mech | + | GSS_C_MA_DEPRECATED | (7) | mech-deprecated | + | GSS_C_MA_NOT_DFLT_MECH | (8) | mech-not-default | + | GSS_C_MA_ITOK_FRAMED | (9) | initial-is-framed | + | GSS_C_MA_AUTH_INIT | (10) | auth-init-princ | + | GSS_C_MA_AUTH_TARG | (11) | auth-targ-princ | + | GSS_C_MA_AUTH_INIT_INIT | (12) | auth-init-princ-initial | + | GSS_C_MA_AUTH_TARG_INIT | (13) | auth-targ-princ-initial | + | GSS_C_MA_AUTH_INIT_ANON | (14) | auth-init-princ-anon | + | GSS_C_MA_AUTH_TARG_ANON | (15) | auth-targ-princ-anon | + | GSS_C_MA_DELEG_CRED | (16) | deleg-cred | + | GSS_C_MA_INTEG_PROT | (17) | integ-prot | + | GSS_C_MA_CONF_PROT | (18) | conf-prot | + | GSS_C_MA_MIC | (19) | mic | + | GSS_C_MA_WRAP | (20) | wrap | + | GSS_C_MA_PROT_READY | (21) | prot-ready | + | GSS_C_MA_REPLAY_DET | (22) | replay-detection | + | GSS_C_MA_OOS_DET | (23) | oos-detection | + | GSS_C_MA_CBINDINGS | (24) | channel-bindings | + | GSS_C_MA_PFS | (25) | pfs | + | GSS_C_MA_COMPRESS | (26) | compress | + | GSS_C_MA_CTX_TRANS | (27) | context-transfer | + | | (28...) | | + +-------------------------+---------+-------------------------+ + + Table 1 + + + + + + + + + + + + + + + +Williams Standards Track [Page 4] + +RFC 5587 Extended GSS Mech Inquiry July 2009 + + + +-------------------------+-----------------------------------------+ + | Mech Attr Name | Purpose | + +-------------------------+-----------------------------------------+ + | GSS_C_MA_MECH_CONCRETE | Indicates that a mech is neither a | + | | pseudo-mechanism nor a composite | + | | mechanism. | + | GSS_C_MA_MECH_PSEUDO | Indicates that a mech is a | + | | pseudo-mechanism. | + | GSS_C_MA_MECH_COMPOSITE | Indicates that a mech is a composite of | + | | other mechanisms. This is reserved for | + | | a specification of "stackable" | + | | pseudo-mechanisms. | + | GSS_C_MA_MECH_NEGO | Indicates that a mech negotiates other | + | | mechs (e.g., SPNEGO has this | + | | attribute). | + | GSS_C_MA_MECH_GLUE | Indicates that the OID is not for a | + | | mechanism but for the GSS-API itself. | + | GSS_C_MA_NOT_MECH | Indicates that the OID is known, yet it | + | | is also known not to be the OID of any | + | | GSS-API mechanism (or of the GSS-API | + | | itself). | + | GSS_C_MA_DEPRECATED | Indicates that a mech (or its OID) is | + | | deprecated and MUST NOT be used as a | + | | default mechanism. | + | GSS_C_MA_NOT_DFLT_MECH | Indicates that a mech (or its OID) MUST | + | | NOT be used as a default mechanism. | + | GSS_C_MA_ITOK_FRAMED | Indicates that the given mechanism's | + | | initial context tokens are properly | + | | framed as per Section 3.1 of [RFC2743]. | + | GSS_C_MA_AUTH_INIT | Indicates support for authentication of | + | | initiator to acceptor. | + | GSS_C_MA_AUTH_TARG | Indicates support for authentication of | + | | acceptor to initiator. | + | GSS_C_MA_AUTH_INIT_INIT | Indicates support for "initial" | + | | authentication of initiator to | + | | acceptor. "Initial authentication" | + | | refers to the use of passwords, or keys | + | | stored on tokens, for authentication. | + | | Whether a mechanism supports initial | + | | authentication may depend on IETF | + | | consensus (see Security | + | | Considerations). | + | GSS_C_MA_AUTH_TARG_INIT | Indicates support for initial | + | | authentication of acceptor to | + | | initiator. | + | GSS_C_MA_AUTH_INIT_ANON | Indicates support for | + | | GSS_C_NT_ANONYMOUS as an initiator | + | | principal name. | + + + +Williams Standards Track [Page 5] + +RFC 5587 Extended GSS Mech Inquiry July 2009 + + + | GSS_C_MA_AUTH_TARG_ANON | Indicates support for | + | | GSS_C_NT_ANONYMOUS as a target | + | | principal name. | + | GSS_C_MA_DELEG_CRED | Indicates support for credential | + | | delegation. | + | GSS_C_MA_INTEG_PROT | Indicates support for per-message | + | | integrity protection. | + | GSS_C_MA_CONF_PROT | Indicates support for per-message | + | | confidentiality protection. | + | GSS_C_MA_MIC | Indicates support for Message Integrity | + | | Code (MIC) tokens. | + | GSS_C_MA_WRAP | Indicates support for WRAP tokens. | + | GSS_C_MA_PROT_READY | Indicates support for per-message | + | | protection prior to full context | + | | establishment. | + | GSS_C_MA_REPLAY_DET | Indicates support for replay detection. | + | GSS_C_MA_OOS_DET | Indicates support for out-of-sequence | + | | detection. | + | GSS_C_MA_CBINDINGS | Indicates support for channel bindings. | + | GSS_C_MA_PFS | Indicates support for Perfect Forward | + | | Security. | + | GSS_C_MA_COMPRESS | Indicates support for compression of | + | | data inputs to GSS_Wrap(). | + | GSS_C_MA_CTX_TRANS | Indicates support for security context | + | | export/import. | + +-------------------------+-----------------------------------------+ + + Table 2 + +3.3. Mechanism Attribute Sets of Existing Mechs + + The Kerberos V mechanism [RFC1964] provides the following mechanism + attributes: + + o GSS_C_MA_MECH_CONCRETE + + o GSS_C_MA_ITOK_FRAMED + + o GSS_C_MA_AUTH_INIT + + o GSS_C_MA_AUTH_TARG + + o GSS_C_MA_DELEG_CRED + + o GSS_C_MA_INTEG_PROT + + o GSS_C_MA_CONF_PROT + + + + +Williams Standards Track [Page 6] + +RFC 5587 Extended GSS Mech Inquiry July 2009 + + + o GSS_C_MA_MIC + + o GSS_C_MA_WRAP + + o GSS_C_MA_PROT_READY + + o GSS_C_MA_REPLAY_DET + + o GSS_C_MA_OOS_DET + + o GSS_C_MA_CBINDINGS + + o GSS_C_MA_CTX_TRANS (some implementations, using implementation- + specific exported context token formats) + + The Kerberos V mechanism also has a deprecated OID that has the same + mechanism attributes as above as well as GSS_C_MA_DEPRECATED. + + The mechanism attributes of the Simple Public-Key GSS-API Mechanism + (SPKM) [RFC2025] family of mechanisms will be provided in a separate + document, as SPKM is currently being reviewed for possibly + significant changes due to problems in its specifications. + + The Low Infrastructure Public Key (LIPKEY) mechanism [RFC2847] offers + the following attributes: + + o GSS_C_MA_MECH_CONCRETE + + o GSS_C_MA_ITOK_FRAMED + + o GSS_C_MA_AUTH_INIT_INIT + + o GSS_C_MA_AUTH_TARG (from SPKM-3) + + o GSS_C_MA_AUTH_TARG_ANON (from SPKM-3) + + o GSS_C_MA_INTEG_PROT + + o GSS_C_MA_CONF_PROT + + o GSS_C_MA_REPLAY_DET + + o GSS_C_MA_OOS_DET + + o GSS_C_MA_CTX_TRANS (some implementations, using implementation- + specific exported context token formats) + + + + + +Williams Standards Track [Page 7] + +RFC 5587 Extended GSS Mech Inquiry July 2009 + + + (LIPKEY should also provide GSS_C_MA_CBINDINGS, but SPKM-3 + requires clarifications on this point.) + + The SPNEGO mechanism [RFC4178] provides the following attributes: + + o GSS_C_MA_MECH_NEGO + + o GSS_C_MA_ITOK_FRAMED + + All other mechanisms' attributes will be described elsewhere. + +3.4. New GSS-API Function Interfaces + + Several new interfaces are given by which, for example, GSS-API + applications may determine what features are provided by a given + mechanism and what mechanisms provide what features. + + These new interfaces are all OPTIONAL. + + Applications should use GSS_Indicate_mechs_by_attrs() instead of + GSS_Indicate_mechs() wherever possible. + + Applications can use GSS_Indicate_mechs_by_attrs() to determine what, + if any, mechanisms provide a given set of features. + + GSS_Indicate_mechs_by_attrs() can also be used to indicate (as in + GSS_Indicate_mechs()) the set of available mechanisms of each type + (concrete, mechanism negotiation pseudo-mechanism, etc.). + +3.4.1. Mechanism Attribute Criticality + + Mechanism attributes may be added at any time. Not only may + attributes be added to the list of known mechanism attributes at any + time, but the set of mechanism attributes supported by a mechanism + can be changed at any time. + + For example, new attributes might be added to reflect whether a + mechanism's initiator must contact an online infrastructure and/or + whether the acceptor must do so. In this example, the Kerberos V + mechanism would gain a new attribute even though the mechanism itself + is not modified. + + Applications making use of attributes not defined herein would then + have no way of knowing whether a GSS-API implementation and its + mechanisms know about new mechanism attributes. To address this + problem, GSS_Indicate_mechs_by_attrs() and + GSS_Inquire_attrs_for_mech() support a notion of critical mechanism + attributes. Applications can search for mechanisms that understand + + + +Williams Standards Track [Page 8] + +RFC 5587 Extended GSS Mech Inquiry July 2009 + + + mechanism attributes that are critical to the application, and the + application may ask what mechanism attributes are understood by a + given mechanism. + +3.4.2. GSS_Indicate_mechs_by_attrs() + + Inputs: + + o desired_mech_attrs SET OF OBJECT IDENTIFIER -- set of GSS_C_MA_* + OIDs that the mechanisms indicated in the mechs output parameter + MUST offer. + + o except_mech_attrs SET OF OBJECT IDENTIFIER -- set of GSS_C_MA_* + OIDs that the mechanisms indicated in the mechs output parameter + MUST NOT offer. + + o critical_mech_attrs SET OF OBJECT IDENTIFIER -- set of GSS_C_MA_* + OIDs that the mechanisms indicated in the mechs output parameter + MUST understand (i.e., mechs must know whether critical attributes + are or are not supported). + + Outputs: + + o major_status INTEGER + + o minor_status INTEGER + + o mechs SET OF OBJECT IDENTIFIER -- set of mechanisms that support + the given desired_mech_attrs but not the except_mech_attrs, and + all of which understand the given critical_mech_attrs (the caller + must release this output with GSS_Release_oid_set()). + + Return major_status codes: + + o GSS_S_COMPLETE indicates success; the output mechs parameter MAY + be the empty set (GSS_C_NO_OID_SET). + + o GSS_S_FAILURE indicates that the request failed for some other + reason. + + GSS_Indicate_mechs_by_attrs() returns the set of OIDs corresponding + to mechanisms that offer at least the desired_mech_attrs but none of + the except_mech_attrs, and that understand all of the attributes + listed in critical_mech_attrs. + + When all three sets of OID input parameters are the empty set, this + function acts as a version of GSS_indicate_mechs() that outputs the + set of all supported mechanisms. + + + +Williams Standards Track [Page 9] + +RFC 5587 Extended GSS Mech Inquiry July 2009 + + +3.4.3. GSS_Inquire_attrs_for_mech() + + Inputs: + + o mech OBJECT IDENTIFIER -- mechanism OID + + Outputs: + + o major_status INTEGER + + o minor_status INTEGER + + o mech_attrs SET OF OBJECT IDENTIFIER -- set of mech_attrs OIDs + (GSS_C_MA_*) supported by the mechanism (the caller must release + this output with GSS_Release_oid_set()). + + o known_mech_attrs SET OF OBJECT IDENTIFIER -- set of mech_attrs + OIDs known to the mechanism implementation (the caller must + release this output with GSS_Release_oid_set()). + + Return major_status codes: + + o GSS_S_COMPLETE indicates success; the output mech_attrs parameter + MAY be the empty set (GSS_C_NO_OID_SET). + + o GSS_S_BAD_MECH indicates that the mechanism named by the mech + parameter does not exist or that the mech is GSS_C_NO_OID and no + default mechanism could be determined. + + o GSS_S_FAILURE indicates that the request failed for some other + reason. + + GSS_Inquire_attrs_for_mech() indicates the set of mechanism + attributes supported by a given mechanism. + +3.4.4. GSS_Display_mech_attr() + + Inputs: + + o mech_attr OBJECT IDENTIFIER -- mechanism attribute OID + + Outputs: + + o major_status INTEGER + + o minor_status INTEGER + + + + + +Williams Standards Track [Page 10] + +RFC 5587 Extended GSS Mech Inquiry July 2009 + + + o name OCTET STRING, -- name of mechanism attribute (e.g., + GSS_C_MA_*). + + o short_desc OCTET STRING, -- a short description of the mechanism + attribute (the caller must release this output with + GSS_Release_buffer()). + + o long_desc OCTET STRING -- a longer description of the mechanism + attribute (the caller must release this output with + GSS_Release_buffer()). + + Return major_status codes: + + o GSS_S_COMPLETE indicates success. + + o GSS_S_BAD_MECH_ATTR indicates that the mechanism attribute + referenced by the mech_attr parameter is unknown to the + implementation. + + o GSS_S_FAILURE indicates that the request failed for some other + reason. + + This function can be used to obtain human-readable descriptions of + GSS-API mechanism attributes. + +3.4.5. New Major Status Values + + A single, new, major status code is added for + GSS_Display_mech_attr(): + + o GSS_S_BAD_MECH_ATTR, + + roughly corresponding to GSS_S_BAD_MECH but applicable to mechanism + attribute OIDs rather than to mechanism OIDs. + + For the C-bindings of the GSS-API [RFC2744], GSS_S_BAD_MECH_ATTR + shall have a routine error number of 19 (this is shifted to the left + by GSS_C_ROUTINE_ERROR_OFFSET). + +3.4.6. C-Bindings + + Note that there is a bug in the C bindings of the GSS-APIv2u1 + [RFC2744] in that the C 'const' attribute is applied to types that + are pointer typedefs. This is a bug because it declares that the + pointer argument is 'const' rather than that the object pointed by it + is const. To avoid this error, we hereby define new typedefs, which + include const properly: + + + + +Williams Standards Track [Page 11] + +RFC 5587 Extended GSS Mech Inquiry July 2009 + + + typedef const gss_buffer_desc * gss_const_buffer_t; + typedef const struct gss_channel_bindings_struct * + gss_const_channel_bindings_t; + typedef const gss_const_ctx_id_t; + typedef const gss_const_cred_id_t; + typedef const gss_const_name_t; + typedef const gss_OID_desc * gss_const_OID; + typedef const gss_OID_set_desc * gss_const_OID_set; + + Figure 1: const typedefs + + Note that only gss_const_OID and gss_const_OID_set are used below. + We include the other const typedefs for convenience since the C + bindings of the GSS-API do use const with pointer typedefs when it + should often instead use the above typedefs instead. + + #define GSS_S_BAD_MECH_ATTR (19ul << GSS_C_ROUTINE_ERROR_OFFSET) + + OM_uint32 gss_indicate_mechs_by_attrs( + OM_uint32 *minor_status, + gss_const_OID_set desired_mech_attrs, + gss_const_OID_set except_mech_attrs, + gss_const_OID_set critical_mech_attrs, + gss_OID_set *mechs); + + OM_uint32 gss_inquire_attrs_for_mech( + OM_uint32 *minor_status, + gss_const_OID mech, + gss_OID_set *mech_attrs, + gss_OID_set *known_mech_attrs); + + OM_uint32 gss_display_mech_attr( + OM_uint32 *minor_status, + gss_const_OID mech_attr, + gss_buffer_t name, + gss_buffer_t short_desc, + gss_buffer_t long_desc); + + Figure 2: C bindings + + Note that output buffers must be released via gss_release_buffer(). + Output OID sets must be released via gss_release_oid_set(). + + Please see Appendix A for a full set of typedef fragments defined in + this document and the necessary code license. + + + + + + +Williams Standards Track [Page 12] + +RFC 5587 Extended GSS Mech Inquiry July 2009 + + +4. Requirements for Mechanism Designers + + All future GSS-API mechanism specifications MUST: + + o list the set of GSS-API mechanism attributes associated with them. + +5. IANA Considerations + + The namespace of programming-language symbols with names beginning + with GSS_C_MA_* is reserved for allocation by IETF Consensus. IANA + allocated a base OID, as an arc of 1.3.6.1.5.5, for the set of + GSS_C_MA_* described herein, and registered all of the GSS_C_MA_* + values described in Section 3.2. + +6. Security Considerations + + This document specifies extensions to a security-related API. It + imposes new requirements on future GSS-API mechanisms, and the + specifications of future protocols that use the GSS-API should make + reference to this document where applicable. The ability to inquire + about specific properties of mechanisms should improve security. + + The semantics of each mechanism attribute may include a security + component. + + Application developers must understand that mechanism attributes may + be added at any time -- both to the set of known mechanism attributes + as well as to existing mechanisms' sets of supported mechanism + attributes. Therefore, application developers using the APIs + described herein must understand what mechanism attributes their + applications depend critically on, and must use the mechanism + attribute criticality features of these APIs. + +7. References + +7.1. Normative References + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2743] Linn, J., "Generic Security Service Application Program + Interface Version 2, Update 1", RFC 2743, January 2000. + + [RFC2744] Wray, J., "Generic Security Service API Version 2 : + C-bindings", RFC 2744, January 2000. + + + + + + +Williams Standards Track [Page 13] + +RFC 5587 Extended GSS Mech Inquiry July 2009 + + +7.2. Informative References + + [RFC1964] Linn, J., "The Kerberos Version 5 GSS-API Mechanism", + RFC 1964, June 1996. + + [RFC2025] Adams, C., "The Simple Public-Key GSS-API Mechanism + (SPKM)", RFC 2025, October 1996. + + [RFC2847] Eisler, M., "LIPKEY - A Low Infrastructure Public Key + Mechanism Using SPKM", RFC 2847, June 2000. + + [RFC4178] Zhu, L., Leach, P., Jaganathan, K., and W. Ingersoll, "The + Simple and Protected Generic Security Service Application + Program Interface (GSS-API) Negotiation Mechanism", + RFC 4178, October 2005. + + [RFC4251] Ylonen, T. and C. Lonvick, "The Secure Shell (SSH) + Protocol Architecture", RFC 4251, January 2006. + + [RFC4462] Hutzelman, J., Salowey, J., Galbraith, J., and V. Welch, + "Generic Security Service Application Program Interface + (GSS-API) Authentication and Key Exchange for the Secure + Shell (SSH) Protocol", RFC 4462, May 2006. + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Williams Standards Track [Page 14] + +RFC 5587 Extended GSS Mech Inquiry July 2009 + + +Appendix A. Typedefs and C Bindings + + This appendix contains the full set of code fragments defined in this + document. + + Copyright (c) 2009 IETF Trust and the persons identified as authors + of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the + distribution. + + - Neither the name of Internet Society, IETF or IETF Trust, nor the + names of specific contributors, may be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + typedef const gss_buffer_desc * gss_const_buffer_t; + typedef const struct gss_channel_bindings_struct * + gss_const_channel_bindings_t; + typedef const gss_const_ctx_id_t; + typedef const gss_const_cred_id_t; + typedef const gss_const_name_t; + typedef const gss_OID_desc * gss_const_OID; + typedef const gss_OID_set_desc * gss_const_OID_set; + + + + + + + +Williams Standards Track [Page 15] + +RFC 5587 Extended GSS Mech Inquiry July 2009 + + + #define GSS_S_BAD_MECH_ATTR (19ul << GSS_C_ROUTINE_ERROR_OFFSET) + + OM_uint32 gss_indicate_mechs_by_attrs( + OM_uint32 *minor_status, + gss_const_OID_set desired_mech_attrs, + gss_const_OID_set except_mech_attrs, + gss_const_OID_set critical_mech_attrs, + gss_OID_set *mechs); + + OM_uint32 gss_inquire_attrs_for_mech( + OM_uint32 *minor_status, + gss_const_OID mech, + gss_OID_set *mech_attrs, + gss_OID_set *known_mech_attrs); + + OM_uint32 gss_display_mech_attr( + OM_uint32 *minor_status, + gss_const_OID mech_attr, + gss_buffer_t name, + gss_buffer_t short_desc, + gss_buffer_t long_desc); + +Author's Address + + Nicolas Williams + Sun Microsystems + 5300 Riata Trace Ct + Austin, TX 78727 + US + + EMail: Nicolas.Williams@sun.com + + + + + + + + + + + + + + + + + + + + +Williams Standards Track [Page 16] + diff --git a/doc/standardisation/rfc6112.txt b/doc/standardisation/rfc6112.txt new file mode 100644 index 000000000..b40775966 --- /dev/null +++ b/doc/standardisation/rfc6112.txt @@ -0,0 +1,899 @@ + + + + + + +Internet Engineering Task Force (IETF) L. Zhu +Request for Comments: 6112 P. Leach +Updates: 4120, 4121, 4556 Microsoft Corporation +Category: Standards Track S. Hartman +ISSN: 2070-1721 Painless Security + April 2011 + + + Anonymity Support for Kerberos + +Abstract + + This document defines extensions to the Kerberos protocol to allow a + Kerberos client to securely communicate with a Kerberos application + service without revealing its identity, or without revealing more + than its Kerberos realm. It also defines extensions that allow a + Kerberos client to obtain anonymous credentials without revealing its + identity to the Kerberos Key Distribution Center (KDC). This + document updates RFCs 4120, 4121, and 4556. + +Status of This Memo + + This is an Internet Standards Track document. + + This document is a product of the Internet Engineering Task Force + (IETF). It represents the consensus of the IETF community. It has + received public review and has been approved for publication by the + Internet Engineering Steering Group (IESG). Further information on + Internet Standards is available in Section 2 of RFC 5741. + + Information about the current status of this document, any errata, + and how to provide feedback on it may be obtained at + http://www.rfc-editor.org/info/rfc6112. + +Copyright Notice + + Copyright (c) 2011 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + + + +Zhu, et al. Standards Track [Page 1] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + This document may contain material from IETF Documents or IETF + Contributions published or made publicly available before November + 10, 2008. The person(s) controlling the copyright in some of this + material may not have granted the IETF Trust the right to allow + modifications of such material outside the IETF Standards Process. + Without obtaining an adequate license from the person(s) controlling + the copyright in such materials, this document may not be modified + outside the IETF Standards Process, and derivative works of it may + not be created outside the IETF Standards Process, except to format + it for publication as an RFC or to translate it into languages other + than English. + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. Conventions Used in This Document . . . . . . . . . . . . . . 3 + 3. Definitions . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 4. Protocol Description . . . . . . . . . . . . . . . . . . . . . 5 + 4.1. Anonymity Support in AS Exchange . . . . . . . . . . . . . 5 + 4.1.1. Anonymous PKINIT . . . . . . . . . . . . . . . . . . . 6 + 4.2. Anonymity Support in TGS Exchange . . . . . . . . . . . . 7 + 4.3. Subsequent Exchanges and Protocol Actions Common to AS + and TGS for Anonymity Support . . . . . . . . . . . . . . 9 + 5. Interoperability Requirements . . . . . . . . . . . . . . . . 10 + 6. GSS-API Implementation Notes . . . . . . . . . . . . . . . . . 10 + 7. PKINIT Client Contribution to the Ticket Session Key . . . . . 11 + 7.1. Combining Two Protocol Keys . . . . . . . . . . . . . . . 12 + 8. Security Considerations . . . . . . . . . . . . . . . . . . . 13 + 9. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 14 + 10. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 15 + 11. References . . . . . . . . . . . . . . . . . . . . . . . . . . 15 + 11.1. Normative References . . . . . . . . . . . . . . . . . . . 15 + 11.2. Informative References . . . . . . . . . . . . . . . . . . 16 + + + + + + + + + + + + + + + + + + +Zhu, et al. Standards Track [Page 2] + +RFC 6112 Kerberos Anonymity Support April 2011 + + +1. Introduction + + In certain situations, the Kerberos [RFC4120] client may wish to + authenticate a server and/or protect communications without revealing + the client's own identity. For example, consider an application that + provides read access to a research database and that permits queries + by arbitrary requesters. A client of such a service might wish to + authenticate the service, to establish trust in the information + received from it, but might not wish to disclose the client's + identity to the service for privacy reasons. + + Extensions to Kerberos are specified in this document by which a + client can authenticate the Key Distribution Center (KDC) and request + an anonymous ticket. The client can use the anonymous ticket to + authenticate the server and protect subsequent client-server + communications. + + By using the extensions defined in this specification, the client can + request an anonymous ticket where the client may reveal the client's + identity to the client's own KDC, or the client can hide the client's + identity completely by using anonymous Public Key Cryptography for + Initial Authentication in Kerberos (PKINIT) as defined in + Section 4.1. Using the returned anonymous ticket, the client remains + anonymous in subsequent Kerberos exchanges thereafter to KDCs on the + cross-realm authentication path and to the server with which it + communicates. + + In this specification, the client realm in the anonymous ticket is + the anonymous realm name when anonymous PKINIT is used to obtain the + ticket. The client realm is the client's real realm name if the + client is authenticated using the client's long-term keys. Note that + the membership of a realm can imply a member of the community + represented by the realm. + + The interaction with Generic Security Service Application Program + Interface (GSS-API) is described after the protocol description. + +2. Conventions Used in This Document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC2119]. + +3. Definitions + + The anonymous Kerberos realm name is defined as a well-known realm + name based on [RFC6111], and the value of this well-known realm name + is the literal "WELLKNOWN:ANONYMOUS". + + + +Zhu, et al. Standards Track [Page 3] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + The anonymous Kerberos principal name is defined as a well-known + Kerberos principal name based on [RFC6111]. The value of the name- + type field is KRB_NT_WELLKNOWN [RFC6111], and the value of the name- + string field is a sequence of two KerberosString components: + "WELLKNOWN", "ANONYMOUS". + + The anonymous ticket flag is defined as bit 16 (with the first bit + being bit 0) in the TicketFlags: + + TicketFlags ::= KerberosFlags + -- anonymous(16) + -- TicketFlags and KerberosFlags are defined in [RFC4120] + + This is a new ticket flag that is used to indicate that a ticket is + an anonymous one. + + An anonymous ticket is a ticket that has all of the following + properties: + + o The cname field contains the anonymous Kerberos principal name. + + o The crealm field contains the client's realm name or the anonymous + realm name. + + o The anonymous ticket contains no information that can reveal the + client's identity. However, the ticket may contain the client + realm, intermediate realms on the client's authentication path, + and authorization data that may provide information related to the + client's identity. For example, an anonymous principal that is + identifiable only within a particular group of users can be + implemented using authorization data and such authorization data, + if included in the anonymous ticket, would disclose the client's + membership of that group. + + o The anonymous ticket flag is set. + + The anonymous KDC option is defined as bit 16 (with the first bit + being bit 0) in the KDCOptions: + + KDCOptions ::= KerberosFlags + -- anonymous(16) + -- KDCOptions and KerberosFlags are defined in [RFC4120] + + + + + + + + + +Zhu, et al. Standards Track [Page 4] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + As described in Section 4, the anonymous KDC option is set to request + an anonymous ticket in an Authentication Service (AS) request or a + Ticket Granting Service (TGS) request. + +4. Protocol Description + + In order to request an anonymous ticket, the client sets the + anonymous KDC option in an AS request or a TGS request. + + The rest of this section is organized as follows: it first describes + protocol actions specific to AS exchanges, then it describes those of + TGS exchanges. These are then followed by the description of + protocol actions common to both AS and TGS and those in subsequent + exchanges. + +4.1. Anonymity Support in AS Exchange + + The client requests an anonymous ticket by setting the anonymous KDC + option in an AS exchange. + + The Kerberos client can use the client's long-term keys, the client's + X.509 certificates [RFC4556], or any other pre-authentication data, + to authenticate to the KDC and requests an anonymous ticket in an AS + exchange where the client's identity is known to the KDC. + + If the client in the AS request is anonymous, the anonymous KDC + option MUST be set in the request. Otherwise, the KDC MUST return a + KRB-ERROR message with the code KDC_ERR_BADOPTION. + + If the client is anonymous and the KDC does not have a key to encrypt + the reply (this can happen when, for example, the KDC does not + support PKINIT [RFC4556]), the KDC MUST return an error message with + the code KDC_ERR_NULL_KEY [RFC4120]. + + When policy allows, the KDC issues an anonymous ticket. If the + client name in the request is the anonymous principal, the client + realm (crealm) in the reply is the anonymous realm, otherwise, the + client realm is the realm of the AS. According to [RFC4120], the + client name and the client realm in the EncTicketPart of the reply + MUST match with the corresponding client name and the client realm of + the KDC reply; the client MUST use the client name and the client + realm returned in the KDC-REP in subsequent message exchanges when + using the obtained anonymous ticket. + + Care MUST be taken by the KDC not to reveal the client's identity in + the authorization data of the returned ticket when populating the + authorization data in a returned anonymous ticket. + + + + +Zhu, et al. Standards Track [Page 5] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + The AD-INITIAL-VERIFIED-CAS authorization data, as defined in + [RFC4556], contains the issuer name of the client certificate. This + authorization is not applicable and MUST NOT be present in the + returned anonymous ticket when anonymous PKINIT is used. When the + client is authenticated (i.e., anonymous PKINIT is not used), if it + is undesirable to disclose such information about the client's + identity, the AD-INITIAL-VERIFIED-CAS authorization data SHOULD be + removed from the returned anonymous ticket. + + The client can use the client keys to mutually authenticate with the + KDC and request an anonymous Ticket Granting Ticket (TGT) in the AS + request. In that case, the reply key is selected as normal, + according to Section 3.1.3 of [RFC4120]. + +4.1.1. Anonymous PKINIT + + This sub-section defines anonymous PKINIT. + + As described earlier in this section, the client can request an + anonymous ticket by authenticating to the KDC using the client's + identity; alternatively, without revealing the client's identity to + the KDC, the Kerberos client can request an anonymous ticket as + follows: the client sets the client name as the anonymous principal + in the AS exchange and provides PA_PK_AS_REQ pre-authentication data + [RFC4556] where the signerInfos field of the SignedData [RFC5652] of + the PA_PK_AS_REQ is empty, and the certificates field is absent. + Because the anonymous client does not have an associated asymmetric + key pair, the client MUST choose the Diffie-Hellman key agreement + method by filling in the Diffie-Hellman domain parameters in the + clientPublicValue [RFC4556]. This use of the anonymous client name + in conjunction with PKINIT is referred to as anonymous PKINIT. If + anonymous PKINIT is used, the realm name in the returned anonymous + ticket MUST be the anonymous realm. + + Upon receiving the anonymous PKINIT request from the client, the KDC + processes the request, according to Section 3.1.2 of [RFC4120]. The + KDC skips the checks for the client's signature and the client's + public key (such as the verification of the binding between the + client's public key and the client name), but performs otherwise + applicable checks, and proceeds as normal, according to [RFC4556]. + For example, the AS MUST check if the client's Diffie-Hellman domain + parameters are acceptable. The Diffie-Hellman key agreement method + MUST be used and the reply key is derived according to Section + 3.2.3.1 of [RFC4556]. If the clientPublicValue is not present in the + request, the KDC MUST return a KRB-ERROR with the code + KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED [RFC4556]. If all goes + well, an anonymous ticket is generated, according to Section 3.1.3 of + [RFC4120], and PA_PK_AS_REP [RFC4556] pre-authentication data is + + + +Zhu, et al. Standards Track [Page 6] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + included in the KDC reply, according to [RFC4556]. If the KDC does + not have an asymmetric key pair, it MAY reply anonymously or reject + the authentication attempt. If the KDC replies anonymously, the + signerInfos field of the SignedData [RFC5652] of PA_PK_AS_REP in the + reply is empty, and the certificates field is absent. The server + name in the anonymous KDC reply contains the name of the TGS. + + Upon receipt of the KDC reply that contains an anonymous ticket and + PA_PK_AS_REP [RFC4556] pre-authentication data, the client can then + authenticate the KDC based on the KDC's signature in the + PA_PK_AS_REP. If the KDC's signature is missing in the KDC reply + (the reply is anonymous), the client MUST reject the returned ticket + if it cannot authenticate the KDC otherwise. + + A KDC that supports anonymous PKINIT MUST indicate the support of + PKINIT, according to Section 3.4 of [RFC4556]. In addition, such a + KDC MUST indicate support for anonymous PKINIT by including a padata + element of padata-type PA_PKINIT_KX and empty padata-value when + including PA-PK-AS-REQ in an error reply. + + When included in a KDC error, PA_PKINIT_KX indicates support for + anonymous PKINIT. As discussed in Section 7, when included in an AS- + REP, PA_PKINIT_KX proves that the KDC and client both contributed to + the session key for any use of Diffie-Hellman key agreement with + PKINIT. + + Note that in order to obtain an anonymous ticket with the anonymous + realm name, the client MUST set the client name as the anonymous + principal in the request when requesting an anonymous ticket in an AS + exchange. Anonymity PKINIT is the only way via which an anonymous + ticket with the anonymous realm as the client realm can be generated + in this specification. + +4.2. Anonymity Support in TGS Exchange + + The client requests an anonymous ticket by setting the anonymous KDC + option in a TGS exchange, and in that request the client can use a + normal Ticket Granting Ticket (TGT) with the client's identity, or an + anonymous TGT, or an anonymous cross-realm TGT. If the client uses a + normal TGT, the client's identity is known to the TGS. + + Note that the client can completely hide the client's identity in an + AS exchange using anonymous PKINIT, as described in the previous + section. + + + + + + + +Zhu, et al. Standards Track [Page 7] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + If the ticket in the PA-TGS-REQ of the TGS request is an anonymous + one, the anonymous KDC option MUST be set in the request. Otherwise, + the KDC MUST return a KRB-ERROR message with the code + KDC_ERR_BADOPTION. + + When policy allows, the KDC issues an anonymous ticket. If the + ticket in the TGS request is an anonymous one, the client name and + the client realm are copied from that ticket; otherwise, the ticket + in the TGS request is a normal ticket, the returned anonymous ticket + contains the client name as the anonymous principal and the client + realm as the true realm of the client. In all cases, according to + [RFC4120] the client name and the client realm in the EncTicketPart + of the reply MUST match with the corresponding client name and the + client realm of the anonymous ticket in the reply; the client MUST + use the client name and the client realm returned in the KDC-REP in + subsequent message exchanges when using the obtained anonymous + ticket. + + Care MUST be taken by the TGS not to reveal the client's identity in + the authorization data of the returned ticket. When propagating + authorization data in the ticket or in the enc-authorization-data + field of the request, the TGS MUST ensure that the client + confidentiality is not violated in the returned anonymous ticket. + The TGS MUST process the authorization data recursively, according to + Section 5.2.6 of [RFC4120], beyond the container levels such that all + embedded authorization elements are interpreted. The TGS SHOULD NOT + populate identity-based authorization data into an anonymous ticket + in that such authorization data typically reveals the client's + identity. The specification of a new authorization data type MUST + specify the processing rules of the authorization data when an + anonymous ticket is returned. If there is no processing rule defined + for an authorization data element or the authorization data element + is unknown, the TGS MUST process it when an anonymous ticket is + returned as follows: + + o If the authorization data element may reveal the client's + identity, it MUST be removed unless otherwise specified. + + o If the authorization data element, that could reveal the client's + identity, is intended to restrict the use of the ticket or limit + the rights otherwise conveyed in the ticket, it cannot be removed + in order to hide the client's identity. In this case, the + authentication attempt MUST be rejected, and the TGS MUST return + an error message with the code KDC_ERR_POLICY. Note this is + applicable to both critical and optional authorization data. + + + + + + +Zhu, et al. Standards Track [Page 8] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + o If the authorization data element is unknown, the TGS MAY remove + it, or transfer it into the returned anonymous ticket, or reject + the authentication attempt, based on local policy for that + authorization data type unless otherwise specified. If there is + no policy defined for a given unknown authorization data type, the + authentication MUST be rejected. The error code is KDC_ERR_POLICY + when the authentication is rejected. + + The AD-INITIAL-VERIFIED-CAS authorization data, as defined in + [RFC4556], contains the issuer name of the client certificate. If it + is undesirable to disclose such information about the client's + identity, the AD-INITIAL-VERIFIED-CAS authorization data SHOULD be + removed from an anonymous ticket. + + The TGS encodes the name of the previous realm into the transited + field, according to Section 3.3.3.2 of [RFC4120]. Based on local + policy, the TGS MAY omit the previous realm, if the cross realm TGT + is an anonymous one, in order to hide the authentication path of the + client. The unordered set of realms in the transited field, if + present, can reveal which realm may potentially be the realm of the + client or the realm that issued the anonymous TGT. The anonymous + Kerberos realm name MUST NOT be present in the transited field of a + ticket. The true name of the realm that issued the anonymous ticket + MAY be present in the transited field of a ticket. + +4.3. Subsequent Exchanges and Protocol Actions Common to AS and TGS for + Anonymity Support + + In both AS and TGS exchanges, the realm field in the KDC request is + always the realm of the target KDC, not the anonymous realm when the + client requests an anonymous ticket. + + Absent other information, the KDC MUST NOT include any identifier in + the returned anonymous ticket that could reveal the client's identity + to the server. + + Unless anonymous PKINIT is used, if a client requires anonymous + communication, then the client MUST check to make sure that the + ticket in the reply is actually anonymous by checking the presence of + the anonymous ticket flag in the flags field of the EncKDCRepPart. + This is because KDCs ignore unknown KDC options. A KDC that does not + understand the anonymous KDC option will not return an error, but + will instead return a normal ticket. + + The subsequent client and server communications then proceed as + described in [RFC4120]. + + + + + +Zhu, et al. Standards Track [Page 9] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + Note that the anonymous principal name and realm are only applicable + to the client in Kerberos messages, the server cannot be anonymous in + any Kerberos message per this specification. + + A server accepting an anonymous service ticket may assume that + subsequent requests using the same ticket originate from the same + client. Requests with different tickets are likely to originate from + different clients. + + Upon receipt of an anonymous ticket, the transited policy check is + performed in the same way as that of a normal ticket if the client's + realm is not the anonymous realm; if the client realm is the + anonymous realm, absent other information any realm in the + authentication path is allowed by the cross-realm policy check. + +5. Interoperability Requirements + + Conforming implementations MUST support the anonymous principal with + a non-anonymous realm, and they MAY support the anonymous principal + with the anonymous realm using anonymous PKINIT. + +6. GSS-API Implementation Notes + + GSS-API defines the name_type GSS_C_NT_ANONYMOUS [RFC2743] to + represent the anonymous identity. In addition, Section 2.1.1 of + [RFC1964] defines the single string representation of a Kerberos + principal name with the name_type GSS_KRB5_NT_PRINCIPAL_NAME. The + anonymous principal with the anonymous realm corresponds to the GSS- + API anonymous principal. A principal with the anonymous principal + name and a non-anonymous realm is an authenticated principal; hence, + such a principal does not correspond to the anonymous principal in + GSS-API with the GSS_C_NT_ANONYMOUS name type. The [RFC1964] name + syntax for GSS_KRB5_NT_PRINCIPAL_NAME MUST be used for importing the + anonymous principal name with a non-anonymous realm name and for + displaying and exporting these names. In addition, this syntax must + be used along with the name type GSS_C_NT_ANONYMOUS for displaying + and exporting the anonymous principal with the anonymous realm. + + At the GSS-API [RFC2743] level, an initiator/client requests the use + of an anonymous principal with the anonymous realm by asserting the + "anonymous" flag when calling GSS_Init_Sec_Context(). The GSS-API + implementation MAY provide implementation-specific means for + requesting the use of an anonymous principal with a non-anonymous + realm. + + GSS-API does not know or define "anonymous credentials", so the + (printable) name of the anonymous principal will rarely be used by or + relevant for the initiator/client. The printable name is relevant + + + +Zhu, et al. Standards Track [Page 10] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + for the acceptor/server when performing an authorization decision + based on the initiator name that is returned from the acceptor side + upon the successful security context establishment. + + A GSS-API initiator MUST carefully check the resulting context + attributes from the initial call to GSS_Init_Sec_Context() when + requesting anonymity, because (as in the GSS-API tradition and for + backwards compatibility) anonymity is just another optional context + attribute. It could be that the mechanism doesn't recognize the + attribute at all or that anonymity is not available for some other + reasons -- and in that case the initiator MUST NOT send the initial + security context token to the acceptor, because it will likely reveal + the initiators identity to the acceptor, something that can rarely be + "un-done". + + Portable initiators are RECOMMENDED to use default credentials + whenever possible, and request anonymity only through the input + anon_req_flag [RFC2743] to GSS_Init_Sec_Context(). + +7. PKINIT Client Contribution to the Ticket Session Key + + The definition in this section was motivated by protocol analysis of + anonymous PKINIT (defined in this document) in building tunneling + channels [RFC6113] and subsequent channel bindings. In order to + enable applications of anonymous PKINIT to form channels, all + implementations of anonymous PKINIT need to meet the requirements of + this section. There is otherwise no connection to the rest of this + document. + + PKINIT is useful for constructing tunneling channels. To ensure that + an attacker cannot create a channel with a given name, it is + desirable that neither the KDC nor the client unilaterally determine + the ticket session key. To achieve that end, a KDC conforming to + this definition MUST encrypt a randomly generated key, called the KDC + contribution key, in the PA_PKINIT_KX padata (defined next in this + section). The KDC contribution key is then combined with the reply + key to form the ticket session key of the returned ticket. These two + keys are then combined using the KRB-FX-CF2 operation defined in + Section 7.1, where K1 is the KDC contribution key, K2 is the reply + key, the input pepper1 is American Standard Code for Information + Interchange (ASCII) [ASAX34] string "PKINIT", and the input pepper2 + is ASCII string "KeyExchange". + + + + + + + + + +Zhu, et al. Standards Track [Page 11] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + PA_PKINIT_KX 147 + -- padata for PKINIT that contains an encrypted + -- KDC contribution key. + + PA-PKINIT-KX ::= EncryptedData -- EncryptionKey + -- Contains an encrypted key randomly + -- generated by the KDC (known as the KDC contribution key). + -- Both EncryptedData and EncryptionKey are defined in [RFC4120] + + The PA_PKINIT_KX padata MUST be included in the KDC reply when + anonymous PKINIT is used; it SHOULD be included if PKINIT is used + with the Diffie-Hellman key exchange but the client is not anonymous; + it MUST NOT be included otherwise (e.g., when PKINIT is used with the + public key encryption as the key exchange). + + The padata-value field of the PA-PKINIT-KX type padata contains the + DER [X.680] [X.690] encoding of the Abstract Syntax Notation One + (ASN.1) type PA-PKINIT-KX. The PA-PKINIT-KX structure is an + EncryptedData. The cleartext data being encrypted is the DER-encoded + KDC contribution key randomly generated by the KDC. The encryption + key is the reply key and the key usage number is + KEY_USAGE_PA_PKINIT_KX (44). + + The client then decrypts the KDC contribution key and verifies the + ticket session key in the returned ticket is the combined key of the + KDC contribution key and the reply key as described above. A + conforming client MUST reject anonymous PKINIT authentication if the + PA_PKINIT_KX padata is not present in the KDC reply or if the ticket + session key of the returned ticket is not the combined key of the KDC + contribution key and the reply key when PA-PKINIT-KX is present in + the KDC reply. + +7.1. Combining Two Protocol Keys + + KRB-FX-CF2() combines two protocol keys based on the pseudo-random() + function defined in [RFC3961]. + + Given two input keys, K1 and K2, where K1 and K2 can be of two + different enctypes, the output key of KRB-FX-CF2(), K3, is derived as + follows: + + KRB-FX-CF2(protocol key, protocol key, octet string, + octet string) -> (protocol key) + + PRF+(K1, pepper1) -> octet-string-1 + PRF+(K2, pepper2) -> octet-string-2 + KRB-FX-CF2(K1, K2, pepper1, pepper2) -> + random-to-key(octet-string-1 ^ octet-string-2) + + + +Zhu, et al. Standards Track [Page 12] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + Where ^ denotes the exclusive-OR operation. PRF+() is defined as + follows: + + PRF+(protocol key, octet string) -> (octet string) + + PRF+(key, shared-info) -> pseudo-random( key, 1 || shared-info ) || + pseudo-random( key, 2 || shared-info ) || + pseudo-random( key, 3 || shared-info ) || ... + + Here the counter value 1, 2, 3, and so on are encoded as a one-octet + integer. The pseudo-random() operation is specified by the enctype + of the protocol key. PRF+() uses the counter to generate enough bits + as needed by the random-to-key() [RFC3961] function for the + encryption type specified for the resulting key; unneeded bits are + removed from the tail. + +8. Security Considerations + + Since KDCs ignore unknown options, a client requiring anonymous + communication needs to make sure that the returned ticket is actually + anonymous. This is because a KDC that does not understand the + anonymous option would not return an anonymous ticket. + + By using the mechanism defined in this specification, the client does + not reveal the client's identity to the server but the client + identity may be revealed to the KDC of the server principal (when the + server principal is in a different realm than that of the client), + and any KDC on the cross-realm authentication path. The Kerberos + client MUST verify the ticket being used is indeed anonymous before + communicating with the server, otherwise, the client's identity may + be revealed unintentionally. + + In cases where specific server principals must not have access to the + client's identity (for example, an anonymous poll service), the KDC + can define server-principal-specific policy that ensures any normal + service ticket can NEVER be issued to any of these server principals. + + If the KDC that issued an anonymous ticket were to maintain records + of the association of identities to an anonymous ticket, then someone + obtaining such records could breach the anonymity. Additionally, the + implementations of most (for now all) KDC's respond to requests at + the time that they are received. Traffic analysis on the connection + to the KDC will allow an attacker to match client identities to + anonymous tickets issued. Because there are plaintext parts of the + tickets that are exposed on the wire, such matching by a third-party + observer is relatively straightforward. A service that is + authenticated by the anonymous principals may be able to infer the + + + + +Zhu, et al. Standards Track [Page 13] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + identity of the client by examining and linking quasi-static protocol + information such as the IP address from which a request is received, + or by linking multiple uses of the same anonymous ticket. + + Two mechanisms, the FAST facility with the hide-client-names option + in [RFC6113] and the Kerberos5 starttls option [STARTTLS], protect + the client identity so that an attacker would never be able to + observe the client identity sent to the KDC. Transport or network + layer security between the client and the server will help prevent + tracking of a particular ticket to link a ticket to a user. In + addition, clients can limit how often a ticket is reused to minimize + ticket linking. + + The client's real identity is not revealed when the client is + authenticated as the anonymous principal. Application servers MAY + reject the authentication in order to, for example, prevent + information disclosure or as part of Denial of Service (DoS) + prevention. Application servers MUST avoid accepting anonymous + credentials in situations where they must record the client's + identity; for example, when there must be an audit trail. + +9. Acknowledgements + + JK Jaganathan helped editing early revisions of this document. + + Clifford Neuman contributed the core notions of this document. + + Ken Raeburn reviewed the document and provided suggestions for + improvements. + + Martin Rex wrote the text for GSS-API considerations. + + Nicolas Williams reviewed the GSS-API considerations section and + suggested ideas for improvements. + + Sam Hartman and Nicolas Williams were great champions of this work. + + Miguel Garcia and Phillip Hallam-Baker reviewed the document and + provided helpful suggestions. + + In addition, the following individuals made significant + contributions: Jeffrey Altman, Tom Yu, Chaskiel M Grundman, Love + Hornquist Astrand, Jeffrey Hutzelman, and Olga Kornievskaia. + + + + + + + + +Zhu, et al. Standards Track [Page 14] + +RFC 6112 Kerberos Anonymity Support April 2011 + + +10. IANA Considerations + + This document defines a new 'anonymous' Kerberos well-known name and + a new 'anonymous' Kerberos well-known realm based on [RFC6111]. IANA + has added these two values to the Kerberos naming registries that are + created in [RFC6111]. + +11. References + +11.1. Normative References + + [ASAX34] American Standards Institute, "American Standard Code for + Information Interchange", ASA X3.4-1963, June 1963. + + [RFC1964] Linn, J., "The Kerberos Version 5 GSS-API Mechanism", + RFC 1964, June 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2743] Linn, J., "Generic Security Service Application Program + Interface Version 2, Update 1", RFC 2743, January 2000. + + [RFC3961] Raeburn, K., "Encryption and Checksum Specifications for + Kerberos 5", RFC 3961, February 2005. + + [RFC4120] Neuman, C., Yu, T., Hartman, S., and K. Raeburn, "The + Kerberos Network Authentication Service (V5)", RFC 4120, + July 2005. + + [RFC4556] Zhu, L. and B. Tung, "Public Key Cryptography for Initial + Authentication in Kerberos (PKINIT)", RFC 4556, + June 2006. + + [RFC5652] Housley, R., "Cryptographic Message Syntax (CMS)", + STD 70, RFC 5652, September 2009. + + [RFC6111] Zhu, L., "Additional Kerberos Naming Constraints", + RFC 6111, April 2011. + + [X.680] "Abstract Syntax Notation One (ASN.1): Specification of + Basic Notation", ITU-T Recommendation X.680: ISO/IEC + International Standard 8824-1:1998, 1997. + + [X.690] "ASN.1 encoding rules: Specification of Basic Encoding + Rules (BER), Canonical Encoding Rules (CER) and + Distinguished Encoding Rules (DER)", ITU-T Recommendation + X.690 ISO/IEC International Standard 8825-1:1998, 1997. + + + +Zhu, et al. Standards Track [Page 15] + +RFC 6112 Kerberos Anonymity Support April 2011 + + +11.2. Informative References + + [RFC6113] Hartman, S. and L. Zhu, "A Generalized Framework for + Kerberos Pre-Authentication", RFC 6113, April 2011. + + [STARTTLS] Josefsson, S., "Using Kerberos V5 over the Transport + Layer Security (TLS) protocol", Work in Progress, + August 2010. + +Authors' Addresses + + Larry Zhu + Microsoft Corporation + One Microsoft Way + Redmond, WA 98052 + US + + EMail: larry.zhu@microsoft.com + + + Paul Leach + Microsoft Corporation + One Microsoft Way + Redmond, WA 98052 + US + + EMail: paulle@microsoft.com + + + Sam Hartman + Painless Security + + EMail: hartmans-ietf@mit.edu + + + + + + + + + + + + + + + + + + +Zhu, et al. Standards Track [Page 16] + diff --git a/doc/standardisation/rfc6113.txt b/doc/standardisation/rfc6113.txt new file mode 100644 index 000000000..e0a579eab --- /dev/null +++ b/doc/standardisation/rfc6113.txt @@ -0,0 +1,2691 @@ + + + + + + +Internet Engineering Task Force (IETF) S. Hartman +Request for Comments: 6113 Painless Security +Updates: 4120 L. Zhu +Category: Standards Track Microsoft Corporation +ISSN: 2070-1721 April 2011 + + + A Generalized Framework for Kerberos Pre-Authentication + +Abstract + + Kerberos is a protocol for verifying the identity of principals + (e.g., a workstation user or a network server) on an open network. + The Kerberos protocol provides a facility called pre-authentication. + Pre-authentication mechanisms can use this facility to extend the + Kerberos protocol and prove the identity of a principal. + + This document describes a more formal model for this facility. The + model describes what state in the Kerberos request a pre- + authentication mechanism is likely to change. It also describes how + multiple pre-authentication mechanisms used in the same request will + interact. + + This document also provides common tools needed by multiple pre- + authentication mechanisms. One of these tools is a secure channel + between the client and the key distribution center with a reply key + strengthening mechanism; this secure channel can be used to protect + the authentication exchange and thus eliminate offline dictionary + attacks. With these tools, it is relatively straightforward to chain + multiple authentication mechanisms, utilize a different key + management system, or support a new key agreement algorithm. + +Status of This Memo + + This is an Internet Standards Track document. + + This document is a product of the Internet Engineering Task Force + (IETF). It represents the consensus of the IETF community. It has + received public review and has been approved for publication by the + Internet Engineering Steering Group (IESG). Further information on + Internet Standards is available in Section 2 of RFC 5741. + + Information about the current status of this document, any errata, + and how to provide feedback on it may be obtained at + http://www.rfc-editor.org/info/rfc6113. + + + + + + +Hartman & Zhu Standards Track [Page 1] + +RFC 6113 Kerberos Preauth Framework April 2011 + + +Copyright Notice + + Copyright (c) 2011 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Hartman & Zhu Standards Track [Page 2] + +RFC 6113 Kerberos Preauth Framework April 2011 + + +Table of Contents + + 1. Introduction ....................................................4 + 1.1. Conventions and Terminology Used in This Document ..........5 + 1.2. Conformance Requirements ...................................5 + 2. Model for Pre-Authentication ....................................6 + 2.1. Information Managed by the Pre-Authentication Model ........7 + 2.2. Initial Pre-Authentication Required Error ..................9 + 2.3. Client to KDC .............................................10 + 2.4. KDC to Client .............................................11 + 3. Pre-Authentication Facilities ..................................12 + 3.1. Client Authentication Facility ............................13 + 3.2. Strengthening Reply Key Facility ..........................13 + 3.3. Replace Reply Key Facility ................................14 + 3.4. KDC Authentication Facility ...............................15 + 4. Requirements for Pre-Authentication Mechanisms .................15 + 4.1. Protecting Requests/Responses .............................16 + 5. Tools for Use in Pre-Authentication Mechanisms .................17 + 5.1. Combining Keys ............................................17 + 5.2. Managing States for the KDC ...............................19 + 5.3. Pre-Authentication Set ....................................20 + 5.4. Definition of Kerberos FAST Padata ........................23 + 5.4.1. FAST Armors ........................................24 + 5.4.2. FAST Request .......................................26 + 5.4.3. FAST Response ......................................30 + 5.4.4. Authenticated Kerberos Error Messages Using + Kerberos FAST ......................................33 + 5.4.5. Outer and Inner Requests ...........................34 + 5.4.6. The Encrypted Challenge FAST Factor ................34 + 5.5. Authentication Strength Indication ........................36 + 6. Assigned Constants .............................................37 + 6.1. New Errors ................................................37 + 6.2. Key Usage Numbers .........................................37 + 6.3. Authorization Data Elements ...............................37 + 6.4. New PA-DATA Types .........................................37 + 7. IANA Considerations ............................................38 + 7.1. Pre-Authentication and Typed Data .........................38 + 7.2. Fast Armor Types ..........................................40 + 7.3. FAST Options ..............................................40 + 8. Security Considerations ........................................41 + 9. Acknowledgements ...............................................42 + 10. References ....................................................43 + 10.1. Normative References .....................................43 + 10.2. Informative References ...................................43 + Appendix A. Test Vectors for KRB-FX-CF2 ...........................45 + Appendix B. ASN.1 Module ..........................................46 + + + + + +Hartman & Zhu Standards Track [Page 3] + +RFC 6113 Kerberos Preauth Framework April 2011 + + +1. Introduction + + The core Kerberos specification [RFC4120] treats pre-authentication + data (padata) as an opaque typed hole in the messages to the key + distribution center (KDC) that may influence the reply key used to + encrypt the KDC reply. This generality has been useful: pre- + authentication data is used for a variety of extensions to the + protocol, many outside the expectations of the initial designers. + However, this generality makes designing more common types of pre- + authentication mechanisms difficult. Each mechanism needs to specify + how it interacts with other mechanisms. Also, tasks such as + combining a key with the long-term secrets or proving the identity of + the user are common to multiple mechanisms. Where there are + generally well-accepted solutions to these problems, it is desirable + to standardize one of these solutions so mechanisms can avoid + duplication of work. In other cases, a modular approach to these + problems is appropriate. The modular approach will allow new and + better solutions to common pre-authentication problems to be used by + existing mechanisms as they are developed. + + This document specifies a framework for Kerberos pre-authentication + mechanisms. It defines the common set of functions that pre- + authentication mechanisms perform as well as how these functions + affect the state of the request and reply. In addition, several + common tools needed by pre-authentication mechanisms are provided. + Unlike [RFC3961], this framework is not complete -- it does not + describe all the inputs and outputs for the pre-authentication + mechanisms. Pre-authentication mechanism designers should try to be + consistent with this framework because doing so will make their + mechanisms easier to implement. Kerberos implementations are likely + to have plug-in architectures for pre-authentication; such + architectures are likely to support mechanisms that follow this + framework plus commonly used extensions. This framework also + facilitates combining multiple pre-authentication mechanisms, each of + which may represent an authentication factor, into a single multi- + factor pre-authentication mechanism. + + One of these common tools is the flexible authentication secure + tunneling (FAST) padata type. FAST provides a protected channel + between the client and the key distribution center (KDC), and it can + optionally deliver key material used to strengthen the reply key + within the protected channel. Based on FAST, pre-authentication + mechanisms can extend Kerberos with ease, to support, for example, + password-authenticated key exchange (PAKE) protocols with zero- + knowledge password proof (ZKPP) [EKE] [IEEE1363.2]. Any pre- + authentication mechanism can be encapsulated in the FAST messages as + defined in Section 5.4. A pre-authentication type carried within + FAST is called a "FAST factor". Creating a FAST factor is the + + + +Hartman & Zhu Standards Track [Page 4] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + easiest path to create a new pre-authentication mechanism. FAST + factors are significantly easier to analyze from a security + standpoint than other pre-authentication mechanisms. + + Mechanism designers should design FAST factors, instead of new pre- + authentication mechanisms outside of FAST. + +1.1. Conventions and Terminology Used in This Document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC2119]. + + This document should be read only after reading the documents + describing the Kerberos cryptography framework [RFC3961] and the core + Kerberos protocol [RFC4120]. This document may freely use + terminology and notation from these documents without reference or + further explanation. + + The word padata is used as a shorthand for pre-authentication data. + + A conversation is the set of all authentication messages exchanged + between the client and the client's Authentication Service (AS) in + order to authenticate the client principal. A conversation as + defined here consists of all messages that are necessary to complete + the authentication between the client and the client's AS. In the + Ticket Granting Service (TGS) exchange, a conversation consists of + the request message and the reply message. The term conversation is + defined here for both AS and TGS for convenience of discussion. See + Section 5.2 for specific rules on the extent of a conversation in the + AS-REQ case. Prior to this framework, implementations needed to use + implementation-specific heuristics to determine the extent of a + conversation. + + If the KDC reply in an AS exchange is verified, the KDC is + authenticated by the client. In this document, verification of the + KDC reply is used as a synonym of authentication of the KDC. + +1.2. Conformance Requirements + + This section summarizes the mandatory-to-implement subset of this + specification as a convenience to implementors. The actual + requirements and their context are stated in the body of the + document. + + Clients conforming to this specification MUST support the padata + defined in Section 5.2. + + + + +Hartman & Zhu Standards Track [Page 5] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + Conforming implementations MUST support Kerberos FAST padata + (Section 5.4). Conforming implementations MUST implement the + FX_FAST_ARMOR_AP_REQUEST armor type. + + Conforming implementations MUST support the encrypted challenge FAST + factor (Section 5.4.6). + +2. Model for Pre-Authentication + + When a Kerberos client wishes to obtain a ticket, it sends an initial + Authentication Service (AS) request to the KDC. If pre- + authentication is required but not being used, then the KDC will + respond with a KDC_ERR_PREAUTH_REQUIRED error [RFC4120]. + Alternatively, if the client knows what pre-authentication to use, it + MAY optimize away a round trip and send an initial request with + padata included in the initial request. If the client includes the + padata computed using the wrong pre-authentication mechanism or + incorrect keys, the KDC MAY return KDC_ERR_PREAUTH_FAILED with no + indication of what padata should have been included. In that case, + the client MUST retry with no padata and examine the error data of + the KDC_ERR_PREAUTH_REQUIRED error. If the KDC includes pre- + authentication information in the accompanying error data of + KDC_ERR_PREAUTH_FAILED, the client SHOULD process the error data and + then retry. + + The conventional KDC maintains no state between two requests; + subsequent requests may even be processed by a different KDC. On the + other hand, the client treats a series of exchanges with KDCs as a + single conversation. Each exchange accumulates state and hopefully + brings the client closer to a successful authentication. + + These models for state management are in apparent conflict. For many + of the simpler pre-authentication scenarios, the client uses one + round trip to find out what mechanisms the KDC supports. Then, the + next request contains sufficient pre-authentication for the KDC to be + able to return a successful reply. For these simple scenarios, the + client only sends one request with pre-authentication data and so the + conversation is trivial. For more complex conversations, the KDC + needs to provide the client with a cookie to include in future + requests to capture the current state of the authentication session. + Handling of multiple round-trip mechanisms is discussed in + Section 5.2. + + This framework specifies the behavior of Kerberos pre-authentication + mechanisms used to identify users or to modify the reply key used to + encrypt the KDC reply. The PA-DATA typed hole may be used to carry + extensions to Kerberos that have nothing to do with proving the + + + + +Hartman & Zhu Standards Track [Page 6] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + identity of the user or establishing a reply key. Such extensions + are outside the scope of this framework. However, mechanisms that do + accomplish these goals should follow this framework. + + This framework specifies the minimum state that a Kerberos + implementation needs to maintain while handling a request in order to + process pre-authentication. It also specifies how Kerberos + implementations process the padata at each step of the AS request + process. + +2.1. Information Managed by the Pre-Authentication Model + + The following information is maintained by the client and KDC as each + request is being processed: + + o The reply key used to encrypt the KDC reply + + o How strongly the identity of the client has been authenticated + + o Whether the reply key has been used in this conversation + + o Whether the reply key has been replaced in this conversation + + o Whether the origin of the KDC reply can be verified by the client + (i.e., whether the KDC is authenticated to the client) + + Conceptually, the reply key is initially the long-term key of the + principal. However, principals can have multiple long-term keys + because of support for multiple encryption types, salts, and + string2key parameters. As described in Section 5.2.7.5 of the + Kerberos protocol [RFC4120], the KDC sends PA-ETYPE-INFO2 to notify + the client what types of keys are available. Thus, in full + generality, the reply key in the pre-authentication model is actually + a set of keys. At the beginning of a request, it is initialized to + the set of long-term keys advertised in the PA-ETYPE-INFO2 element on + the KDC. If multiple reply keys are available, the client chooses + which one to use. Thus, the client does not need to treat the reply + key as a set. At the beginning of a request, the client picks a key + to use. + + KDC implementations MAY choose to offer only one key in the PA-ETYPE- + INFO2 element. Since the KDC already knows the client's list of + supported enctypes from the request, no interoperability problems are + + + + + + + + +Hartman & Zhu Standards Track [Page 7] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + created by choosing a single possible reply key. This way, the KDC + implementation avoids the complexity of treating the reply key as a + set. + + When the padata in the request are verified by the KDC, then the + client is known to have that key; therefore, the KDC SHOULD pick the + same key as the reply key. + + At the beginning of handling a message on both the client and the + KDC, the client's identity is not authenticated. A mechanism may + indicate that it has successfully authenticated the client's + identity. It is useful to keep track of this information on the + client in order to know what pre-authentication mechanisms should be + used. The KDC needs to keep track of whether the client is + authenticated because the primary purpose of pre-authentication is to + authenticate the client identity before issuing a ticket. The + handling of authentication strength using various authentication + mechanisms is discussed in Section 5.5. + + Initially, the reply key is not used. A pre-authentication mechanism + that uses the reply key to encrypt or checksum some data in the + generation of new keys MUST indicate that the reply key is used. + This state is maintained by the client and the KDC to enforce the + security requirement stated in Section 3.3 that the reply key SHOULD + NOT be replaced after it is used. + + Initially, the reply key is not replaced. If a mechanism implements + the Replace Reply Key facility discussed in Section 3.3, then the + state MUST be updated to indicate that the reply key has been + replaced. Once the reply key has been replaced, knowledge of the + reply key is insufficient to authenticate the client. The reply key + is marked as replaced in exactly the same situations as the KDC reply + is marked as not being verified to the client principal. However, + while mechanisms can verify the KDC reply to the client, once the + reply key is replaced, then the reply key remains replaced for the + remainder of the conversation. + + Without pre-authentication, the client knows that the KDC reply is + authentic and has not been modified because it is encrypted in a + long-term key of the client. Only the KDC and the client know that + key. So, at the start of a conversation, the KDC reply is presumed + to be verified using the client's long-term key. It should be noted + that in this document, verifying the KDC reply means authenticating + the KDC, and these phrases are used interchangeably. Any pre- + authentication mechanism that sets a new reply key not based on the + principal's long-term secret MUST either verify the KDC reply some + other way or indicate that the reply is not verified. If a mechanism + indicates that the reply is not verified, then the client + + + +Hartman & Zhu Standards Track [Page 8] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + implementation MUST return an error unless a subsequent mechanism + verifies the reply. The KDC needs to track this state so it can + avoid generating a reply that is not verified. + + In this specification, KDC verification/authentication refers to the + level of authentication of the KDC to the client provided by RFC + 4120. There is a stronger form of KDC verification that, while + sometimes important in Kerberos deployments, is not addressed in this + specification: the typical Kerberos request does not provide a way + for the client machine to know that it is talking to the correct KDC. + Someone who can inject packets into the network between the client + machine and the KDC and who knows the password that the user will + give to the client machine can generate a KDC reply that will decrypt + properly. So, if the client machine needs to authenticate that the + user is in fact the named principal, then the client machine needs to + do a TGS request for itself as a service. Some pre-authentication + mechanisms may provide a way for the client machine to authenticate + the KDC. Examples of this include signing the reply that can be + verified using a well-known public key or providing a ticket for the + client machine as a service. + +2.2. Initial Pre-Authentication Required Error + + Typically, a client starts a conversation by sending an initial + request with no pre-authentication. If the KDC requires pre- + authentication, then it returns a KDC_ERR_PREAUTH_REQUIRED message. + After the first reply with the KDC_ERR_PREAUTH_REQUIRED error code, + the KDC returns the error code KDC_ERR_MORE_PREAUTH_DATA_REQUIRED + (defined in Section 5.2) for pre-authentication configurations that + use multi-round-trip mechanisms; see Section 2.4 for details of that + case. + + The KDC needs to choose which mechanisms to offer the client. The + client needs to be able to choose what mechanisms to use from the + first message. For example, consider the KDC that will accept + mechanism A followed by mechanism B or alternatively the single + mechanism C. A client that supports A and C needs to know that it + should not bother trying A. + + Mechanisms can either be sufficient on their own or can be part of an + authentication set -- a group of mechanisms that all need to + successfully complete in order to authenticate a client. Some + mechanisms may only be useful in authentication sets; others may be + useful alone or in authentication sets. For the second group of + mechanisms, KDC policy dictates whether the mechanism will be part of + an authentication set, offered alone, or both. For each mechanism + that is offered alone (even if it is also offered in an + authentication set), the KDC includes the pre-authentication type ID + + + +Hartman & Zhu Standards Track [Page 9] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + of the mechanism in the padata sequence returned in the + KDC_ERR_PREAUTH_REQUIRED error. Mechanisms that are only offered as + part of an authentication set are not directly represented in the + padata sequence returned in the KDC_ERR_PREAUTH_REQUIRED error, + although they are represented in the PA-AUTHENTICATION-SET sequence. + + The KDC SHOULD NOT send data that is encrypted in the long-term + password-based key of the principal. Doing so has the same security + exposures as the Kerberos protocol without pre-authentication. There + are few situations where the KDC needs to expose cipher text + encrypted in a weak key before the client has proven knowledge of + that key, and where pre-authentication is desirable. + +2.3. Client to KDC + + This description assumes that a client has already received a + KDC_ERR_PREAUTH_REQUIRED from the KDC. If the client performs + optimistic pre-authentication, then the client needs to guess values + for the information it would normally receive from that error + response or use cached information obtained in prior interactions + with the KDC. + + The client starts by initializing the pre-authentication state as + specified. It then processes the padata in the + KDC_ERR_PREAUTH_REQUIRED. + + When processing the response to the KDC_ERR_PREAUTH_REQUIRED, the + client MAY ignore any padata it chooses unless doing so violates a + specification to which the client conforms. Clients conforming to + this specification MUST NOT ignore the padata defined in Section 5.2. + Clients SHOULD choose one authentication set or mechanism that could + lead to authenticating the user and ignore other such mechanisms. + However, this rule does not affect the processing of padata unrelated + to this framework; clients SHOULD process such padata normally. + Since the list of mechanisms offered by the KDC is in the decreasing + preference order, clients typically choose the first mechanism or + authentication set that the client can usefully perform. If a client + chooses to ignore padata, it MUST NOT process the padata, allow the + padata to affect the pre-authentication state, or respond to the + padata. + + For each instance of padata the client chooses to process, the client + processes the padata and modifies the pre-authentication state as + required by that mechanism. + + + + + + + +Hartman & Zhu Standards Track [Page 10] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + After processing the padata in the KDC error, the client generates a + new request. It processes the pre-authentication mechanisms in the + order in which they will appear in the next request, updating the + state as appropriate. The request is sent when it is complete. + +2.4. KDC to Client + + When a KDC receives an AS request from a client, it needs to + determine whether it will respond with an error or an AS reply. + There are many causes for an error to be generated that have nothing + to do with pre-authentication; they are discussed in the core + Kerberos specification. + + From the standpoint of evaluating the pre-authentication, the KDC + first starts by initializing the pre-authentication state. If a PA- + FX-COOKIE pre-authentication data item is present, it is processed + first; see Section 5.2 for a definition. It then processes the + padata in the request. As mentioned in Section 2.3, the KDC MAY + ignore padata that are inappropriate for the configuration and MUST + ignore padata of an unknown type. The KDC MUST NOT ignore padata of + types used in previous messages. For example, if a KDC issues a + KDC_ERR_PREAUTH_REQUIRED error including padata of type x, then the + KDC cannot ignore padata of type x received in an AS-REQ message from + the client. + + At this point, the KDC decides whether it will issue an error or a + reply. Typically, a KDC will issue a reply if the client's identity + has been authenticated to a sufficient degree. + + In the case of a KDC_ERR_MORE_PREAUTH_DATA_REQUIRED error, the KDC + first starts by initializing the pre-authentication state. Then, it + processes any padata in the client's request in the order provided by + the client. Mechanisms that are not understood by the KDC are + ignored. Next, it generates padata for the error response, modifying + the pre-authentication state appropriately as each mechanism is + processed. The KDC chooses the order in which it will generate + padata (and thus the order of padata in the response), but it needs + to modify the pre-authentication state consistently with the choice + of order. For example, if some mechanism establishes an + authenticated client identity, then the subsequent mechanisms in the + generated response receive this state as input. After the padata are + generated, the error response is sent. Typically, the errors with + the code KDC_ERR_MORE_PREAUTH_DATA_REQUIRED in a conversation will + include KDC state, as discussed in Section 5.2. + + To generate a final reply, the KDC generates the padata modifying the + pre-authentication state as necessary. Then, it generates the final + response, encrypting it in the current pre-authentication reply key. + + + +Hartman & Zhu Standards Track [Page 11] + +RFC 6113 Kerberos Preauth Framework April 2011 + + +3. Pre-Authentication Facilities + + Pre-authentication mechanisms can be thought of as providing various + conceptual facilities. This serves two useful purposes. First, + mechanism authors can choose only to solve one specific small + problem. It is often useful for a mechanism designed to offer key + management not to directly provide client authentication but instead + to allow one or more other mechanisms to handle this need. Secondly, + thinking about the abstract services that a mechanism provides yields + a minimum set of security requirements that all mechanisms providing + that facility must meet. These security requirements are not + complete; mechanisms will have additional security requirements based + on the specific protocol they employ. + + A mechanism is not constrained to only offering one of these + facilities. While such mechanisms can be designed and are sometimes + useful, many pre-authentication mechanisms implement several + facilities. It is often easier to construct a secure, simple + solution by combining multiple facilities in a single mechanism than + by solving the problem in full generality. Even when mechanisms + provide multiple facilities, they need to meet the security + requirements for all the facilities they provide. If the FAST factor + approach is used, it is likely that one or a small number of + facilities can be provided by a single mechanism without complicating + the security analysis. + + According to Kerberos extensibility rules (Section 1.5 of the + Kerberos specification [RFC4120]), an extension MUST NOT change the + semantics of a message unless a recipient is known to understand that + extension. Because a client does not know that the KDC supports a + particular pre-authentication mechanism when it sends an initial + request, a pre-authentication mechanism MUST NOT change the semantics + of the request in a way that will break a KDC that does not + understand that mechanism. Similarly, KDCs MUST NOT send messages to + clients that affect the core semantics unless the client has + indicated support for the message. + + The only state in this model that would break the interpretation of a + message is changing the expected reply key. If one mechanism changed + the reply key and a later mechanism used that reply key, then a KDC + that interpreted the second mechanism but not the first would fail to + interpret the request correctly. In order to avoid this problem, + extensions that change core semantics are typically divided into two + parts. The first part proposes a change to the core semantic -- for + example, proposes a new reply key. The second part acknowledges that + the extension is understood and that the change takes effect. + Section 3.2 discusses how to design mechanisms that modify the reply + key to be split into a proposal and acceptance without requiring + + + +Hartman & Zhu Standards Track [Page 12] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + additional round trips to use the new reply key in subsequent pre- + authentication. Other changes in the state described in Section 2.1 + can safely be ignored by a KDC that does not understand a mechanism. + Mechanisms that modify the behavior of the request outside the scope + of this framework need to carefully consider the Kerberos + extensibility rules to avoid similar problems. + +3.1. Client Authentication Facility + + The Client Authentication facility proves the identity of a user to + the KDC before a ticket is issued. Examples of mechanisms + implementing this facility include the encrypted timestamp facility, + defined in Section 5.2.7.2 of the Kerberos specification [RFC4120]. + Mechanisms that provide this facility are expected to mark the client + as authenticated. + + Mechanisms implementing this facility SHOULD require the client to + prove knowledge of the reply key before transmitting a successful KDC + reply. Otherwise, an attacker can intercept the pre-authentication + exchange and get a reply to attack. One way of proving the client + knows the reply key is to implement the Replace Reply Key facility + along with this facility. The Public Key Cryptography for Initial + Authentication in Kerberos (PKINIT) mechanism [RFC4556] implements + Client Authentication alongside Replace Reply Key. + + If the reply key has been replaced, then mechanisms such as + encrypted-timestamp that rely on knowledge of the reply key to + authenticate the client MUST NOT be used. + +3.2. Strengthening Reply Key Facility + + Particularly when dealing with keys based on passwords, it is + desirable to increase the strength of the key by adding additional + secrets to it. Examples of sources of additional secrets include the + results of a Diffie-Hellman key exchange or key bits from the output + of a smart card [KRB-WG.SAM]. Typically, these additional secrets + can be first combined with the existing reply key and then converted + to a protocol key using tools defined in Section 5.1. + + Typically, a mechanism implementing this facility will know that the + other side of the exchange supports the facility before the reply key + is changed. For example, a mechanism might need to learn the + certificate for a KDC before encrypting a new key in the public key + belonging to that certificate. However, if a mechanism implementing + this facility wishes to modify the reply key before knowing that the + other party in the exchange supports the mechanism, it proposes + modifying the reply key. The other party then includes a message + indicating that the proposal is accepted if it is understood and + + + +Hartman & Zhu Standards Track [Page 13] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + meets policy. In many cases, it is desirable to use the new reply + key for client authentication and for other facilities. Waiting for + the other party to accept the proposal and actually modify the reply + key state would add an additional round trip to the exchange. + Instead, mechanism designers are encouraged to include a typed hole + for additional padata in the message that proposes the reply key + change. The padata included in the typed hole are generated assuming + the new reply key. If the other party accepts the proposal, then + these padata are considered as an inner level. As with the outer + level, one authentication set or mechanism is typically chosen for + client authentication, along with auxiliary mechanisms such as KDC + cookies, and other mechanisms are ignored. When mechanisms include + such a container, the hint provided for use in authentication sets + (as defined in Section 5.3) MUST contain a sequence of inner + mechanisms along with hints for those mechanisms. The party + generating the proposal can determine whether the padata were + processed based on whether the proposal for the reply key is + accepted. + + The specific formats of the proposal message, including where padata + are included, is a matter for the mechanism specification. + Similarly, the format of the message accepting the proposal is + mechanism specific. + + Mechanisms implementing this facility and including a typed hole for + additional padata MUST checksum that padata using a keyed checksum or + encrypt the padata. This requirement protects against modification + of the contents of the typed hole. By modifying these contents, an + attacker might be able to choose which mechanism is used to + authenticate the client, or to convince a party to provide text + encrypted in a key that the attacker had manipulated. It is + important that mechanisms strengthen the reply key enough that using + it to checksum padata is appropriate. + +3.3. Replace Reply Key Facility + + The Replace Reply Key facility replaces the key in which a successful + AS reply will be encrypted. This facility can only be used in cases + where knowledge of the reply key is not used to authenticate the + client. The new reply key MUST be communicated to the client and the + KDC in a secure manner. This facility MUST NOT be used if there can + be a man-in-the-middle between the client and the KDC. Mechanisms + implementing this facility MUST mark the reply key as replaced in the + pre-authentication state. Mechanisms implementing this facility MUST + either provide a mechanism to verify the KDC reply to the client or + mark the reply as unverified in the pre-authentication state. + Mechanisms implementing this facility SHOULD NOT be used if a + previous mechanism has used the reply key. + + + +Hartman & Zhu Standards Track [Page 14] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + As with the Strengthening Reply Key facility, Kerberos extensibility + rules require that the reply key not be changed unless both sides of + the exchange understand the extension. In the case of this facility, + it will likely be the case for both sides to know that the facility + is available by the time that the new key is available to be used. + However, mechanism designers can use a container for padata in a + proposal message, as discussed in Section 3.2, if appropriate. + +3.4. KDC Authentication Facility + + This facility verifies that the reply comes from the expected KDC. + In traditional Kerberos, the KDC and the client share a key, so if + the KDC reply can be decrypted, then the client knows that a trusted + KDC responded. Note that the client machine cannot trust the client + unless the machine is presented with a service ticket for it + (typically, the machine can retrieve this ticket by itself). + However, if the reply key is replaced, some mechanism is required to + verify the KDC. Pre-authentication mechanisms providing this + facility allow a client to determine that the expected KDC has + responded even after the reply key is replaced. They mark the pre- + authentication state as having been verified. + +4. Requirements for Pre-Authentication Mechanisms + + This section lists requirements for specifications of pre- + authentication mechanisms. + + For each message in the pre-authentication mechanism, the + specification describes the pa-type value to be used and the contents + of the message. The processing of the message by the sender and + recipient is also specified. This specification needs to include all + modifications to the pre-authentication state. + + Generally, mechanisms have a message that can be sent in the error + data of the KDC_ERR_PREAUTH_REQUIRED error message or in an + authentication set. If the client needs information, such as trusted + certificate authorities, in order to determine if it can use the + mechanism, then this information should be in that message. In + addition, such mechanisms should also define a pa-hint to be included + in authentication sets. Often, the same information included in the + padata-value is appropriate to include in the pa-hint (as defined in + Section 5.3). + + In order to ease security analysis, the mechanism specification + should describe what facilities from this document are offered by the + mechanism. For each facility, the security considerations section of + the mechanism specification should show that the security + + + + +Hartman & Zhu Standards Track [Page 15] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + requirements of that facility are met. This requirement is + applicable to any FAST factor that provides authentication + information. + + Significant problems have resulted in the specification of Kerberos + protocols because much of the KDC exchange is not protected against + alteration. The security considerations section should discuss + unauthenticated plaintext attacks. It should either show that + plaintext is protected or discuss what harm an attacker could do by + modifying the plaintext. It is generally acceptable for an attacker + to be able to cause the protocol negotiation to fail by modifying + plaintext. More significant attacks should be evaluated carefully. + + As discussed in Section 5.2, there is no guarantee that a client will + use the same KDCs for all messages in a conversation. The mechanism + specification needs to show why the mechanism is secure in this + situation. The hardest problem to deal with, especially for + challenge/response mechanisms is to make sure that the same response + cannot be replayed against two KDCs while allowing the client to talk + to any KDC. + +4.1. Protecting Requests/Responses + + Mechanism designers SHOULD protect cleartext portions of pre- + authentication data. Various denial-of-service attacks and downgrade + attacks against Kerberos are possible unless plaintexts are somehow + protected against modification. An early design goal of Kerberos + Version 5 [RFC4120] was to avoid encrypting more of the + authentication exchange than was required. (Version 4 doubly- + encrypted the encrypted part of a ticket in a KDC reply, for + example). This minimization of encryption reduces the load on the + KDC and busy servers. Also, during the initial design of Version 5, + the existence of legal restrictions on the export of cryptography + made it desirable to minimize of the number of uses of encryption in + the protocol. Unfortunately, performing this minimization created + numerous instances of unauthenticated security-relevant plaintext + fields. + + Mechanisms MUST guarantee that by the end of a successful + authentication exchange, both the client and the KDC have verified + all the plaintext sent by the other party. If there is more than one + round trip in the exchange, mechanisms MUST additionally guarantee + that no individual messages were reordered or replayed from a + previous exchange. Strategies for accomplishing this include using + message authentication codes (MACs) to protect the plaintext as it is + sent including some form of nonce or cookie to allow for the chaining + of state from one message to the next or exchanging a MAC of the + entire conversation after a key is established. + + + +Hartman & Zhu Standards Track [Page 16] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + Mechanism designers need to provide a strategy for updating + cryptographic algorithms, such as defining a new pre-authentication + type for each algorithm or taking advantage of the client's list of + supported RFC 3961 encryption types to indicate the client's support + for cryptographic algorithms. + + Primitives defined in [RFC3961] are RECOMMENDED for integrity + protection and confidentiality. Mechanisms based on these primitives + are crypto-agile as the result of using [RFC3961] along with + [RFC4120]. The advantage afforded by crypto-agility is the ability + to incrementally deploy a fix specific to a particular algorithm thus + avoid a multi-year standardization and deployment cycle, when real + attacks do arise against that algorithm. + + Note that data used by FAST factors (defined in Section 5.4) is + encrypted in a protected channel; thus, they do not share the un- + authenticated-text issues with mechanisms designed as full-blown pre- + authentication mechanisms. + +5. Tools for Use in Pre-Authentication Mechanisms + + This section describes common tools needed by multiple pre- + authentication mechanisms. By using these tools, mechanism designers + can use a modular approach to specify mechanism details and ease + security analysis. + +5.1. Combining Keys + + Frequently, a weak key needs to be combined with a stronger key + before use. For example, passwords are typically limited in size and + insufficiently random: therefore, it is desirable to increase the + strength of the keys based on passwords by adding additional secrets. + An additional source of secrecy may come from hardware tokens. + + This section provides standard ways to combine two keys into one. + + KRB-FX-CF1() is defined to combine two passphrases. + + KRB-FX-CF1(UTF-8 string, UTF-8 string) -> (UTF-8 string) + KRB-FX-CF1(x, y) := x || y + + Where || denotes concatenation. The strength of the final key is + roughly the total strength of the individual keys being combined, + assuming that the string_to_key() function [RFC3961] uses all its + input evenly. + + + + + + +Hartman & Zhu Standards Track [Page 17] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + An example usage of KRB-FX-CF1() is when a device provides random but + short passwords, the password is often combined with a personal + identification number (PIN). The password and the PIN can be + combined using KRB-FX-CF1(). + + KRB-FX-CF2() combines two protocol keys based on the pseudo-random() + function defined in [RFC3961]. + + Given two input keys, K1 and K2, where K1 and K2 can be of two + different enctypes, the output key of KRB-FX-CF2(), K3, is derived as + follows: + + KRB-FX-CF2(protocol key, protocol key, octet string, + octet string) -> (protocol key) + + PRF+(K1, pepper1) -> octet-string-1 + PRF+(K2, pepper2) -> octet-string-2 + KRB-FX-CF2(K1, K2, pepper1, pepper2) := + random-to-key(octet-string-1 ^ octet-string-2) + + Where ^ denotes the exclusive-OR operation. PRF+() is defined as + follows: + + PRF+(protocol key, octet string) -> (octet string) + + PRF+(key, shared-info) := pseudo-random( key, 1 || shared-info ) || + pseudo-random( key, 2 || shared-info ) || + pseudo-random( key, 3 || shared-info ) || ... + + Here the counter value 1, 2, 3, and so on are encoded as a one-octet + integer. The pseudo-random() operation is specified by the enctype + of the protocol key. PRF+() uses the counter to generate enough bits + as needed by the random-to-key() [RFC3961] function for the + encryption type specified for the resulting key; unneeded bits are + removed from the tail. Unless otherwise specified, the resulting + enctype of KRB-FX-CF2 is the enctype of k1. The pseudo-random() + operation is the RFC 3961 pseudo-random() operation for the + corresponding input key; the random-to-key() operation is the RFC + 3961 random-to-key operation for the resulting key. + + Mechanism designers MUST specify the values for the input parameter + pepper1 and pepper2 when combining two keys using KRB-FX-CF2(). The + pepper1 and pepper2 MUST be distinct so that if the two keys being + combined are the same, the resulting key is not a trivial key. + + + + + + + +Hartman & Zhu Standards Track [Page 18] + +RFC 6113 Kerberos Preauth Framework April 2011 + + +5.2. Managing States for the KDC + + Kerberos KDCs are stateless in that there is no requirement that + clients will choose the same KDC for the second request in a + conversation. Proxies or other intermediate nodes may also influence + KDC selection. So, each request from a client to a KDC must include + sufficient information that the KDC can regenerate any needed state. + This is accomplished by giving the client a potentially long opaque + cookie in responses to include in future requests in the same + conversation. The KDC MAY respond that a conversation is too old and + needs to restart by responding with a KDC_ERR_PREAUTH_EXPIRED error. + + KDC_ERR_PREAUTH_EXPIRED 90 + + When a client receives this error, the client SHOULD abort the + existing conversation, and restart a new one. + + An example, where more than one message from the client is needed, is + when the client is authenticated based on a challenge/response + scheme. In that case, the KDC needs to keep track of the challenge + issued for a client authentication request. + + The PA-FX-COOKIE padata type is defined in this section to facilitate + state management in the AS exchange. These padata are sent by the + KDC when the KDC requires state for a future transaction. The client + includes this opaque token in the next message in the conversation. + The token may be relatively large; clients MUST be prepared for + tokens somewhat larger than the size of all messages in a + conversation. + + PA-FX-COOKIE 133 + -- Stateless cookie that is not tied to a specific KDC. + + The corresponding padata-value field [RFC4120] contains an opaque + token that will be echoed by the client in its response to an error + from the KDC. + + The cookie token is generated by the KDC and transmitted in a PA-FX- + COOKIE pre-authentication data item of a KRB-ERROR message. The + client MUST copy the exact cookie encapsulated in a PA-FX-COOKIE data + element into the next message of the same conversation. The content + of the cookie field is a local matter of the KDC. As a result, it is + not generally possible to mix KDC implementations from different + vendors in the same realm. However, the KDC MUST construct the + cookie token in such a manner that a malicious client cannot subvert + the authentication process by manipulating the token. The KDC + implementation needs to consider expiration of tokens, key rollover, + and other security issues in token design. The content of the cookie + + + +Hartman & Zhu Standards Track [Page 19] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + field is likely specific to the pre-authentication mechanisms used to + authenticate the client. If a client authentication response can be + replayed to multiple KDCs via the PA-FX-COOKIE mechanism, an + expiration in the cookie is RECOMMENDED to prevent the response being + presented indefinitely. Implementations need to consider replay both + of an entire conversation and of messages within a conversation when + designing what information is stored in a cookie and how pre- + authentication mechanisms are implemented. + + If at least one more message for a mechanism or a mechanism set is + expected by the KDC, the KDC returns a + KDC_ERR_MORE_PREAUTH_DATA_REQUIRED error with a PA-FX-COOKIE to + identify the conversation with the client, according to Section 2.2. + The cookie is not expected to stay constant for a conversation: the + KDC is expected to generate a new cookie for each message. + + KDC_ERR_MORE_PREAUTH_DATA_REQUIRED 91 + + A client MAY throw away the state associated with a conversation and + begin a new conversation by discarding its state and not including a + cookie in the first message of a conversation. KDCs that comply with + this specification MUST include a cookie in a response when the + client can continue the conversation. In particular, a KDC MUST + include a cookie in a KDC_ERR_PREAUTH_REQUIRED or + KDC_ERR_MORE_PREAUTH_DATA_REQUIRED. KDCs SHOULD include a cookie in + errors containing additional information allowing a client to retry. + One reasonable strategy for meeting these requirements is to always + include a cookie in KDC errors. + + A KDC MAY indicate that it is terminating a conversation by not + including a cookie in a response. When FAST is used, clients can + assume that the absence of a cookie means that the KDC is ending the + conversation. Similarly, if a cookie is seen at all during a + conversation, clients MAY assume that the absence of a cookie in a + future message means that the KDC is ending the conversation. + Clients also need to deal with KDCs, prior to this specification, + that do not include cookies; if neither cookies nor FAST are used in + a conversation, the absence of a cookie is not a strong indication + that the KDC is terminating the conversation. + +5.3. Pre-Authentication Set + + If all mechanisms in a group need to successfully complete in order + to authenticate a client, the client and the KDC SHOULD use the PA- + AUTHENTICATION-SET padata element. + + PA-AUTHENTICATION-SET 134 + + + + +Hartman & Zhu Standards Track [Page 20] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + A PA-AUTHENTICATION-SET padata element contains the ASN.1 DER + encoding of the PA-AUTHENTICATION-SET structure: + + PA-AUTHENTICATION-SET ::= SEQUENCE OF PA-AUTHENTICATION-SET-ELEM + + PA-AUTHENTICATION-SET-ELEM ::= SEQUENCE { + pa-type [0] Int32, + -- same as padata-type. + pa-hint [1] OCTET STRING OPTIONAL, + pa-value [2] OCTET STRING OPTIONAL, + ... + } + + The pa-type field of the PA-AUTHENTICATION-SET-ELEM structure + contains the corresponding value of padata-type in PA-DATA [RFC4120]. + Associated with the pa-type is a pa-hint, which is an octet string + specified by the pre-authentication mechanism. This hint may provide + information for the client that helps it determine whether the + mechanism can be used. For example, a public-key mechanism might + include the certificate authorities it trusts in the hint info. Most + mechanisms today do not specify hint info; if a mechanism does not + specify hint info, the KDC MUST NOT send a hint for that mechanism. + To allow future revisions of mechanism specifications to add hint + info, clients MUST ignore hint info received for mechanisms that the + client believes do not support hint info. The pa-value element of + the PA-AUTHENTICATION-SET-ELEM sequence is included to carry the + first padata-value from the KDC to the client. If the client chooses + this authentication set, then the client MUST process this pa-value. + The pa-value element MUST be absent for all but the first entry in + the authentication set. Clients MUST ignore the pa-value for the + second and following entries in the authentication set. + + If the client chooses an authentication set, then its first AS-REQ + message MUST contain a PA-AUTH-SET-SELECTED padata element. This + element contains the encoding of the PA-AUTHENTICATION-SET sequence + received from the KDC corresponding to the authentication set that is + chosen. The client MUST use the same octet values received from the + KDC; it cannot re-encode the sequence. This allows KDCs to use bit- + wise comparison to identify the selected authentication set. + Permitting bit-wise comparison may limit the ability to use certain + pre-authentication mechanisms that generate a dynamic challenge in an + authentication set with optimistic selection of an authentication + set. As with other optimistic pre-authentication failures, the KDC + MAY return KDC_ERR_PREAUTH_FAILED with a new list of pre- + authentication mechanisms (including authentication sets) if + optimistic pre-authentication fails. The PA-AUTH-SET-SELECTED padata + element MUST come before any padata elements from the authentication + set in the padata sequence in the AS-REQ message. The client MAY + + + +Hartman & Zhu Standards Track [Page 21] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + cache authentication sets from prior messages and use them to + construct an optimistic initial AS-REQ. If the KDC receives a PA- + AUTH-SET-SELECTED padata element that does not correspond to an + authentication set that it would offer, then the KDC returns the + KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET error. The e-data in this + error contains a sequence of padata just as for the + KDC_ERR_PREAUTH_REQUIRED error. + + PA-AUTH-SET-SELECTED 135 + KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET 92 + + The PA-AUTHENTICATION-SET appears only in the first message from the + KDC to the client. In particular, the client MAY fail if the + authentication mechanism sets change as the conversation progresses. + Clients MAY assume that the hints provided in the authentication set + contain enough information that the client knows what user interface + elements need to be displayed during the entire authentication + conversation. Exceptional circumstances, such as expired passwords + or expired accounts, may require that additional user interface be + displayed. Mechanism designers need to carefully consider the design + of their hints so that the client has this information. This way, + clients can construct necessary dialogue boxes or wizards based on + the authentication set and can present a coherent user interface. + Current standards for user interfaces do not provide an acceptable + experience when the client has to ask additional questions later in + the conversation. + + When indicating which sets of pre-authentication mechanisms are + supported, the KDC includes a PA-AUTHENTICATION-SET padata element + for each pre-authentication mechanism set. + + The client sends the padata-value for the first mechanism it picks in + the pre-authentication set, when the first mechanism completes, the + client and the KDC will proceed with the second mechanism, and so on + until all mechanisms complete successfully. The PA-FX-COOKIE, as + defined in Section 5.2, MUST be sent by the KDC. One reason for this + requirement is so that the conversation can continue if the + conversation involves multiple KDCs. KDCs MUST support clients that + do not include a cookie because they optimistically choose an + authentication set, although they MAY always return a + KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET and include a cookie in that + message. Clients that support PA-AUTHENTICATION-SET MUST support PA- + FX-COOKIE. + + Before the authentication succeeds and a ticket is returned, the + message that the client sends is an AS-REQ and the message that the + KDC sends is a KRB-ERROR message. The error code in the KRB-ERROR + message from the KDC is KDC_ERR_MORE_PREAUTH_DATA_REQUIRED as defined + + + +Hartman & Zhu Standards Track [Page 22] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + in Section 5.2 and the accompanying e-data contains the DER encoding + of ASN.1 type METHOD-DATA. The KDC includes the padata elements in + the METHOD-DATA. If there are no padata, the e-data field is absent + in the KRB-ERROR message. + + If the client sends the last message for a given mechanism, then the + KDC sends the first message for the next mechanism. If the next + mechanism does not start with a KDC-side challenge, then the KDC + includes a padata item with the appropriate pa-type and an empty pa- + data. + + If the KDC sends the last message for a particular mechanism, the KDC + also includes the first padata for the next mechanism. + +5.4. Definition of Kerberos FAST Padata + + As described in [RFC4120], Kerberos is vulnerable to offline + dictionary attacks. An attacker can request an AS-REP and try + various passwords to see if they can decrypt the resulting ticket. + RFC 4120 provides the encrypted timestamp pre-authentication method + that ameliorates the situation somewhat by requiring that an attacker + observe a successful authentication. However, stronger security is + desired in many environments. The Kerberos FAST pre-authentication + padata defined in this section provides a tool to significantly + reduce vulnerability to offline dictionary attacks. When combined + with encrypted challenge, FAST requires an attacker to mount a + successful man-in-the-middle attack to observe ciphertext. When + combined with host keys, FAST can even protect against active + attacks. FAST also provides solutions to common problems for pre- + authentication mechanisms such as binding of the request and the + reply and freshness guarantee of the authentication. FAST itself, + however, does not authenticate the client or the KDC; instead, it + provides a typed hole to allow pre-authentication data be tunneled. + A pre-authentication data element used within FAST is called a "FAST + factor". A FAST factor captures the minimal work required for + extending Kerberos to support a new pre-authentication scheme. + + A FAST factor MUST NOT be used outside of FAST unless its + specification explicitly allows so. The typed holes in FAST messages + can also be used as generic holes for other padata that are not + intended to prove the client's identity, or establish the reply key. + + New pre-authentication mechanisms SHOULD be designed as FAST factors, + instead of full-blown pre-authentication mechanisms. + + FAST factors that are pre-authentication mechanisms MUST meet the + requirements in Section 4. + + + + +Hartman & Zhu Standards Track [Page 23] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + FAST employs an armoring scheme. The armor can be a Ticket Granting + Ticket (TGT) obtained by the client's machine using the host keys to + pre-authenticate with the KDC, or an anonymous TGT obtained based on + anonymous PKINIT [RFC6112] [RFC4556]. + + The rest of this section describes the types of armors and the syntax + of the messages used by FAST. Conforming implementations MUST + support Kerberos FAST padata. + + Any FAST armor scheme MUST provide a fresh armor key for each + conversation. Clients and KDCs can assume that if a message is + encrypted and integrity protected with a given armor key, then it is + part of the conversation using that armor key. + + All KDCs in a realm MUST support FAST if FAST is offered by any KDC + as a pre-authentication mechanism. + +5.4.1. FAST Armors + + An armor key is used to encrypt pre-authentication data in the FAST + request and the response. The KrbFastArmor structure is defined to + identify the armor key. This structure contains the following two + fields: the armor-type identifies the type of armors and the armor- + value is an OCTET STRING that contains the description of the armor + scheme and the armor key. + + KrbFastArmor ::= SEQUENCE { + armor-type [0] Int32, + -- Type of the armor. + armor-value [1] OCTET STRING, + -- Value of the armor. + ... + } + + The value of the armor key is a matter of the armor type + specification. Only one armor type is defined in this document. + + FX_FAST_ARMOR_AP_REQUEST 1 + + The FX_FAST_ARMOR_AP_REQUEST armor is based on Kerberos tickets. + + Conforming implementations MUST implement the + FX_FAST_ARMOR_AP_REQUEST armor type. If a FAST KDC receives an + unknown armor type it MUST respond with KDC_ERR_PREAUTH_FAILED. + + An armor type may be appropriate for use in armoring AS requests, + armoring TGS requests, or both. TGS armor types MUST authenticate + the client to the KDC, typically by binding the TGT sub-session key + + + +Hartman & Zhu Standards Track [Page 24] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + to the armor key. As discussed below, it is desirable for AS armor + types to authenticate the KDC to the client, but this is not + required. + + FAST implementations MUST maintain state about whether the armor + mechanism authenticates the KDC. If it does not, then a FAST factor + that authenticates the KDC MUST be used if the reply key is replaced. + +5.4.1.1. Ticket-Based Armors + + This is a ticket-based armoring scheme. The armor-type is + FX_FAST_ARMOR_AP_REQUEST, the armor-value contains an ASN.1 DER + encoded AP-REQ. The ticket in the AP-REQ is called an armor ticket + or an armor TGT. The subkey field in the AP-REQ MUST be present. + The armor key is defined by the following function: + + armor_key = KRB-FX-CF2( subkey, ticket_session_key, + "subkeyarmor", "ticketarmor" ) + + The 'ticket_session_key' is the session key from the ticket in the + ap-req. The 'subkey' is the ap-req subkey. This construction + guarantees that both the KDC (through the session key) and the client + (through the subkey) contribute to the armor key. + + The server name field of the armor ticket MUST identify the TGS of + the target realm. Here are three common ways in the decreasing + preference order how an armor TGT SHOULD be obtained: + + 1. If the client is authenticating from a host machine whose + Kerberos realm has an authentication path to the client's realm, + the host machine obtains a TGT by using the host keys. If the + client's realm is different than the realm of the local host, the + machine then obtains a cross-realm TGT to the client's realm as + the armor ticket. Otherwise, the host's primary TGT is the armor + ticket. + + 2. If the client's host machine cannot obtain a host ticket strictly + based on RFC 4120, but the KDC has an asymmetric signing key + whose binding with the expected KDC can be verified by the + client, the client can use anonymous PKINIT [RFC6112] [RFC4556] + to authenticate the KDC and obtain an anonymous TGT as the armor + ticket. The armor ticket can also be a cross-realm TGT obtained + based on the initial primary TGT obtained using anonymous PKINIT + with KDC authentication. + + 3. Otherwise, the client uses anonymous PKINIT to get an anonymous + TGT without KDC authentication and that TGT is the armor ticket. + Note that this mode of operation is vulnerable to man-in-the- + + + +Hartman & Zhu Standards Track [Page 25] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + middle attacks at the time of obtaining the initial anonymous + armor TGT. + + If anonymous PKINIT is used to obtain the armor ticket, the KDC + cannot know whether its signing key can be verified by the client; + hence, the KDC MUST be marked as unverified from the KDC's point of + view while the client could be able to authenticate the KDC by + verifying the KDC's signing key is bound with the expected KDC. The + client needs to carefully consider the risk and benefit tradeoffs + associated with active attacks before exposing cipher text encrypted + using the user's long-term secrets when the armor does not + authenticate the KDC. + + The TGS MUST reject a request if there is an AD-fx-fast-armor (71) + element in the authenticator of the pa-tgs-req padata or if the + ticket in the authenticator of a pa-tgs-req contains the AD-fx-fast- + armor authorization data element. These tickets and authenticators + MAY be used as FAST armor tickets but not to obtain a ticket via the + TGS. This authorization data is used in a system where the + encryption of the user's pre-authentication data is performed in an + unprivileged user process. A privileged process can provide to the + user process a host ticket, an authenticator for use with that + ticket, and the sub-session key contained in the authenticator. In + order for the host process to ensure that the host ticket is not + accidentally or intentionally misused, (i.e., the user process might + use the host ticket to authenticate as the host), it MUST include a + critical authorization data element of the type AD-fx-fast-armor when + providing the authenticator or in the enc-authorization-data field of + the TGS request used to obtain the TGT. The corresponding ad-data + field of the AD-fx-fast-armor element is empty. + + This armor type is only valid for AS requests; implicit armor, + described below in TGS processing, is the only supported way to + establish an armor key for the TGS at this time. + +5.4.2. FAST Request + + A padata type PA-FX-FAST is defined for the Kerberos FAST pre- + authentication padata. The corresponding padata-value field + [RFC4120] contains the DER encoding of the ASN.1 type PA-FX-FAST- + REQUEST. As with all pre-authentication types, the KDC SHOULD + advertise PA-FX-FAST in a PREAUTH_REQUIRED error. KDCs MUST send the + advertisement of PA-FX-FAST with an empty pa-value. Clients MUST + ignore the pa-value of PA-FX-FAST in an initial PREAUTH_REQUIRED + error. FAST is not expected to be used in an authentication set: + clients will typically use FAST padata if available and this decision + should not depend on what other pre-authentication methods are + available. As such, no pa-hint is defined for FAST at this time. + + + +Hartman & Zhu Standards Track [Page 26] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + PA-FX-FAST 136 + -- Padata type for Kerberos FAST + + PA-FX-FAST-REQUEST ::= CHOICE { + armored-data [0] KrbFastArmoredReq, + ... + } + + KrbFastArmoredReq ::= SEQUENCE { + armor [0] KrbFastArmor OPTIONAL, + -- Contains the armor that identifies the armor key. + -- MUST be present in AS-REQ. + req-checksum [1] Checksum, + -- For AS, contains the checksum performed over the type + -- KDC-REQ-BODY for the req-body field of the KDC-REQ + -- structure; + -- For TGS, contains the checksum performed over the type + -- AP-REQ in the PA-TGS-REQ padata. + -- The checksum key is the armor key, the checksum + -- type is the required checksum type for the enctype of + -- the armor key, and the key usage number is + -- KEY_USAGE_FAST_REQ_CHKSUM. + enc-fast-req [2] EncryptedData, -- KrbFastReq -- + -- The encryption key is the armor key, and the key usage + -- number is KEY_USAGE_FAST_ENC. + ... + } + + KEY_USAGE_FAST_REQ_CHKSUM 50 + KEY_USAGE_FAST_ENC 51 + + The PA-FX-FAST-REQUEST structure contains a KrbFastArmoredReq type. + The KrbFastArmoredReq encapsulates the encrypted padata. + + The enc-fast-req field contains an encrypted KrbFastReq structure. + The armor key is used to encrypt the KrbFastReq structure, and the + key usage number for that encryption is KEY_USAGE_FAST_ENC. + + The armor key is selected as follows: + + o In an AS request, the armor field in the KrbFastArmoredReq + structure MUST be present and the armor key is identified + according to the specification of the armor type. + + + + + + + + +Hartman & Zhu Standards Track [Page 27] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + o There are two possibilities for armor for a TGS request. If the + ticket presented in the PA-TGS-REQ authenticator is a TGT, then + the client SHOULD NOT include the armor field in the Krbfastreq + and a subkey MUST be included in the PA-TGS-REQ authenticator. In + this case, the armor key is the same armor key that would be + computed if the TGS-REQ authenticator was used in an + FX_FAST_ARMOR_AP_REQUEST armor. Clients MAY present a non-TGT in + the PA-TGS-REQ authenticator and omit the armor field, in which + case the armor key is the same that would be computed if the + authenticator were used in an FX_FAST_ARMOR_AP_REQUEST armor. + This is the only case where a ticket other than a TGT can be used + to establish an armor key; even though the armor key is computed + the same as an FX_FAST_ARMOR_AP_REQUEST, a non-TGT cannot be used + as an armor ticket in FX_FAST_ARMOR_AP_REQUEST. Alternatively, a + client MAY use an armor type defined in the future for use with + the TGS request. + + The req-checksum field contains a checksum computed differently for + AS and TGS. For an AS-REQ, it is performed over the type KDC-REQ- + BODY for the req-body field of the KDC-REQ structure of the + containing message; for a TGS-REQ, it is performed over the type AP- + REQ in the PA-TGS-REQ padata of the TGS request. The checksum key is + the armor key, and the checksum type is the required checksum type + for the enctype of the armor key per [RFC3961]. This checksum MUST + be a keyed checksum and it is included in order to bind the FAST + padata to the outer request. A KDC that implements FAST will ignore + the outer request, but including a checksum is relatively cheap and + may prevent confusing behavior. + + The KrbFastReq structure contains the following information: + + KrbFastReq ::= SEQUENCE { + fast-options [0] FastOptions, + -- Additional options. + padata [1] SEQUENCE OF PA-DATA, + -- padata typed holes. + req-body [2] KDC-REQ-BODY, + -- Contains the KDC request body as defined in Section + -- 5.4.1 of [RFC4120]. + -- This req-body field is preferred over the outer field + -- in the KDC request. + ... + } + + + + + + + + +Hartman & Zhu Standards Track [Page 28] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + The fast-options field indicates various options that are to modify + the behavior of the KDC. The following options are defined: + + FastOptions ::= KerberosFlags + -- reserved(0), + -- hide-client-names(1), + + Bits Name Description + ----------------------------------------------------------------- + 0 RESERVED Reserved for future expansion of this + field. + 1 hide-client-names Requesting the KDC to hide client + names in the KDC response, as + described next in this section. + 16 kdc-follow-referrals reserved [REFERRALS]. + + Bits 1 through 15 inclusive (with bit 1 and bit 15 included) are + critical options. If the KDC does not support a critical option, it + MUST fail the request with KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS, and + there is no accompanying e-data defined in this document for this + error code. Bit 16 and onward (with bit 16 included) are non- + critical options. KDCs conforming to this specification ignore + unknown non-critical options. + + KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS 93 + + The hide-client-names Option + + The Kerberos response defined in [RFC4120] contains the client + identity in cleartext. This makes traffic analysis + straightforward. The hide-client-names option is designed to + complicate traffic analysis. If the hide-client-names option is + set, the KDC implementing PA-FX-FAST MUST identify the client as + the anonymous principal [RFC6112] in the KDC reply and the error + response. Hence, this option is set by the client if it wishes to + conceal the client identity in the KDC response. A conforming KDC + ignores the client principal name in the outer KDC-REQ-BODY field, + and identifies the client using the cname and crealm fields in the + req-body field of the KrbFastReq structure. + + The kdc-follow-referrals Option + + This option is reserved for [REFERRALS]. + + + + + + + + +Hartman & Zhu Standards Track [Page 29] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + The padata field contains a list of PA-DATA structures as described + in Section 5.2.7 of [RFC4120]. These PA-DATA structures can contain + FAST factors. They can also be used as generic typed-holes to + contain data not intended for proving the client's identity or + establishing a reply key, but for protocol extensibility. If the KDC + supports the PA-FX-FAST-REQUEST padata, unless otherwise specified, + the client MUST place any padata that is otherwise in the outer KDC + request body into this field. In a TGS request, PA-TGS-REQ padata is + not included in this field and it is present in the outer KDC request + body. + + The KDC-REQ-BODY in the FAST structure is used in preference to the + KDC-REQ-BODY outside of the FAST pre-authentication. The outer KDC- + REQ-BODY structure SHOULD be filled in for backwards compatibility + with KDCs that do not support FAST. A conforming KDC ignores the + outer KDC-REQ-BODY field in the KDC request. Pre-authentication data + methods such as [RFC4556] that include a checksum of the KDC-REQ-BODY + should checksum the KDC-REQ-BODY in the FAST structure. + + In a TGS request, a client MAY include the AD-fx-fast-used authdata + either in the pa-tgs-req authenticator or in the authorization data + in the pa-tgs-req ticket. If the KDC receives this authorization + data but does not find a FAST padata, then it MUST return + KRB_APP_ERR_MODIFIED. + +5.4.3. FAST Response + + The KDC that supports the PA-FX-FAST padata MUST include a PA-FX-FAST + padata element in the KDC reply. In the case of an error, the PA-FX- + FAST padata is included in the KDC responses according to + Section 5.4.4. + + The corresponding padata-value field [RFC4120] for the PA-FX-FAST in + the KDC response contains the DER encoding of the ASN.1 type PA-FX- + FAST-REPLY. + + PA-FX-FAST-REPLY ::= CHOICE { + armored-data [0] KrbFastArmoredRep, + ... + } + + KrbFastArmoredRep ::= SEQUENCE { + enc-fast-rep [0] EncryptedData, -- KrbFastResponse -- + -- The encryption key is the armor key in the request, and + -- the key usage number is KEY_USAGE_FAST_REP. + ... + } + KEY_USAGE_FAST_REP 52 + + + +Hartman & Zhu Standards Track [Page 30] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + The PA-FX-FAST-REPLY structure contains a KrbFastArmoredRep + structure. The KrbFastArmoredRep structure encapsulates the padata + in the KDC reply in the encrypted form. The KrbFastResponse is + encrypted with the armor key used in the corresponding request, and + the key usage number is KEY_USAGE_FAST_REP. + + The Kerberos client MUST support a local policy that rejects the + response if PA-FX-FAST-REPLY is not included in the response. + Clients MAY also support policies that fall back to other mechanisms + or that do not use pre-authentication when FAST is unavailable. It + is important to consider the potential downgrade attacks when + deploying such a policy. + + The KrbFastResponse structure contains the following information: + + KrbFastResponse ::= SEQUENCE { + padata [0] SEQUENCE OF PA-DATA, + -- padata typed holes. + strengthen-key [1] EncryptionKey OPTIONAL, + -- This, if present, strengthens the reply key for AS and + -- TGS. MUST be present for TGS. + -- MUST be absent in KRB-ERROR. + finished [2] KrbFastFinished OPTIONAL, + -- Present in AS or TGS reply; absent otherwise. + nonce [3] UInt32, + -- Nonce from the client request. + ... + } + + The padata field in the KrbFastResponse structure contains a list of + PA-DATA structures as described in Section 5.2.7 of [RFC4120]. These + PA-DATA structures are used to carry data advancing the exchange + specific for the FAST factors. They can also be used as generic + typed-holes for protocol extensibility. Unless otherwise specified, + the KDC MUST include any padata that are otherwise in the outer KDC- + REP or KDC-ERROR structure into this field. The padata field in the + KDC reply structure outside of the PA-FX-FAST-REPLY structure + typically includes only the PA-FX-FAST-REPLY padata. + + The strengthen-key field provides a mechanism for the KDC to + strengthen the reply key. If set, the strengthen-key value MUST be + randomly generated to have the same etype as that of the reply key + before being strengthened, and then the reply key is strengthened + after all padata items are processed. Let padata-reply-key be the + reply key after padata processing. + + reply-key = KRB-FX-CF2(strengthen-key, padata-reply-key, + "strengthenkey", "replykey") + + + +Hartman & Zhu Standards Track [Page 31] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + The strengthen-key field MAY be set in an AS reply; it MUST be set in + a TGS reply; it must be absent in an error reply. The strengthen key + is required in a TGS reply so that an attacker cannot remove the FAST + PADATA from a TGS reply, causing the KDC to appear not to support + FAST. + + The finished field contains a KrbFastFinished structure. It is + filled by the KDC in the final message in the conversation. This + field is present in an AS-REP or a TGS-REP when a ticket is returned, + and it is not present in an error reply. + + The KrbFastFinished structure contains the following information: + + KrbFastFinished ::= SEQUENCE { + timestamp [0] KerberosTime, + usec [1] Microseconds, + -- timestamp and usec represent the time on the KDC when + -- the reply was generated. + crealm [2] Realm, + cname [3] PrincipalName, + -- Contains the client realm and the client name. + ticket-checksum [4] Checksum, + -- checksum of the ticket in the KDC-REP using the armor + -- and the key usage is KEY_USAGE_FAST_FINISH. + -- The checksum type is the required checksum type + -- of the armor key. + ... + } + KEY_USAGE_FAST_FINISHED 53 + + The timestamp and usec fields represent the time on the KDC when the + reply ticket was generated, these fields have the same semantics as + the corresponding identically named fields in Section 5.6.1 of + [RFC4120]. The client MUST use the KDC's time in these fields + thereafter when using the returned ticket. The client need not + confirm that the timestamp returned is within allowable clock skew: + the armor key guarantees that the reply is fresh. The client MAY + trust the timestamp returned. + + The cname and crealm fields identify the authenticated client. If + facilities described in [REFERRALS] are used, the authenticated + client may differ from the client in the FAST request. + + The ticket-checksum is a checksum of the issued ticket. The checksum + key is the armor key, and the checksum type is the required checksum + type of the enctype of that key, and the key usage number is + KEY_USAGE_FAST_FINISHED. + + + + +Hartman & Zhu Standards Track [Page 32] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + When FAST padata is included, the PA-FX-COOKIE padata as defined in + Section 5.2 MUST be included in the padata sequence in the + KrbFastResponse sequence if the KDC expects at least one more message + from the client in order to complete the authentication. + + The nonce field in the KrbFastResponse contains the value of the + nonce field in the KDC-REQ of the corresponding client request and it + binds the KDC response with the client request. The client MUST + verify that this nonce value in the reply matches with that of the + request and reject the KDC reply otherwise. To prevent the response + from one message in a conversation from being replayed to a request + in another message, clients SHOULD use a new nonce for each message + in a conversation. + +5.4.4. Authenticated Kerberos Error Messages Using Kerberos FAST + + If the Kerberos FAST padata was included in the request, unless + otherwise specified, the e-data field of the KRB-ERROR message + [RFC4120] contains the ASN.1 DER encoding of the type METHOD-DATA + [RFC4120] and a PA-FX-FAST is included in the METHOD-DATA. The KDC + MUST include all the padata elements such as PA-ETYPE-INFO2 and + padata elements that indicate acceptable pre-authentication + mechanisms [RFC4120] in the KrbFastResponse structure. + + The KDC MUST also include a PA-FX-ERROR padata item in the + KRBFastResponse structure. The padata-value element of this sequence + is the ASN.1 DER encoding of the type KRB-ERROR. The e-data field + MUST be absent in the PA-FX-ERROR padata. All other fields should be + the same as the outer KRB-ERROR. The client ignores the outer error + and uses the combination of the padata in the KRBFastResponse and the + error information in the PA-FX-ERROR. + + PA-FX-ERROR 137 + + If the Kerberos FAST padata is included in the request but not + included in the error reply, it is a matter of the local policy on + the client to accept the information in the error message without + integrity protection. However, the client SHOULD process the KDC + errors as the result of the KDC's inability to accept the AP_REQ + armor and potentially retry another request with a different armor + when applicable. The Kerberos client MAY process an error message + without a PA-FX-FAST-REPLY, if that is only intended to return better + error information to the application, typically for trouble-shooting + purposes. + + In the cases where the e-data field of the KRB-ERROR message is + expected to carry a TYPED-DATA [RFC4120] element, that information + should be transmitted in a pa-data element within the KRBFastResponse + + + +Hartman & Zhu Standards Track [Page 33] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + structure. The padata-type is the same as the data-type would be in + the typed data element and the padata-value is the same as the data- + value. As discussed in Section 7, data-types and padata-types are + drawn from the same namespace. For example, the + TD_TRUSTED_CERTIFIERS structure is expected to be in the KRB-ERROR + message when the error code is KDC_ERR_CANT_VERIFY_CERTIFICATE + [RFC4556]. + +5.4.5. Outer and Inner Requests + + Typically, a client will know that FAST is being used before a + request containing PA-FX-FAST is sent. So, the outer AS request + typically only includes one pa-data item: PA-FX-FAST. The client MAY + include additional pa-data, but the KDC MUST ignore the outer request + body and any padata besides PA-FX-FAST if and only if PA-FX-FAST is + processed. In the case of the TGS request, the outer request should + include PA-FX-FAST and PA-TGS-REQ. + + When an AS generates a response, all padata besides PA-FX-FAST should + be included in PA-FX-FAST. The client MUST ignore other padata + outside of PA-FX-FAST. + +5.4.6. The Encrypted Challenge FAST Factor + + The encrypted challenge FAST factor authenticates a client using the + client's long-term key. This factor works similarly to the encrypted + timestamp pre-authentication option described in [RFC4120]. The word + "challenge" is used instead of "timestamp" because while the + timestamp is used as an initial challenge, if the KDC and client do + not have synchronized time, then the KDC can provide updated time to + the client to use as a challenge. The client encrypts a structure + containing a timestamp in the challenge key. The challenge key used + by the client to send a message to the KDC is KRB-FX- + CF2(armor_key,long_term_key, "clientchallengearmor", + "challengelongterm"). The challenge key used by the KDC encrypting + to the client is KRB-FX-CF2(armor_key, long_term_key, + "kdcchallengearmor", "challengelongterm"). Because the armor key is + fresh and random, the challenge key is fresh and random. The only + purpose of the timestamp is to limit the validity of the + authentication so that a request cannot be replayed. A client MAY + base the timestamp on the KDC time in a KDC error and need not + maintain accurate time synchronization itself. If a client bases its + time on an untrusted source, an attacker may trick the client into + producing an authentication request that is valid at some future + time. The attacker may be able to use this authentication request to + make it appear that a client has authenticated at that future time. + If ticket-based armor is used, then the lifetime of the ticket will + limit the window in which an attacker can make the client appear to + + + +Hartman & Zhu Standards Track [Page 34] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + have authenticated. For many situations, the ability of an attacker + to cause a client to appear to have authenticated is not a + significant concern; the ability to avoid requiring time + synchronization on clients is more valuable. + + The client sends a padata of type PA-ENCRYPTED-CHALLENGE. The + corresponding padata-value contains the DER encoding of ASN.1 type + EncryptedChallenge. + + EncryptedChallenge ::= EncryptedData + -- Encrypted PA-ENC-TS-ENC, encrypted in the challenge key + -- using key usage KEY_USAGE_ENC_CHALLENGE_CLIENT for the + -- client and KEY_USAGE_ENC_CHALLENGE_KDC for the KDC. + + PA-ENCRYPTED-CHALLENGE 138 + KEY_USAGE_ENC_CHALLENGE_CLIENT 54 + KEY_USAGE_ENC_CHALLENGE_KDC 55 + + The client includes some timestamp reasonably close to the KDC's + current time and encrypts it in the challenge key in a PA-ENC-TS-ENC + structure (see Section 5.2.7.2 in RFC 4120). Clients MAY use the + current time; doing so prevents the exposure where an attacker can + cause a client to appear to authenticate in the future. The client + sends the request including this factor. + + On receiving an AS-REQ containing the PA-ENCRYPTED-CHALLENGE FAST + factor, the KDC decrypts the timestamp. If the decryption fails the + KDC SHOULD return KDC_ERR_PREAUTH_FAILED, including PA-ETYPE-INFO2 in + the KRBFastResponse in the error. The KDC confirms that the + timestamp falls within its current clock skew returning + KRB_APP_ERR_SKEW if not. The KDC then SHOULD check to see if the + encrypted challenge is a replay. The KDC MUST NOT consider two + encrypted challenges replays simply because the timestamps are the + same; to be a replay, the ciphertext MUST be identical. Allowing + clients to reuse timestamps avoids requiring that clients maintain + state about which timestamps have been used. + + If the KDC accepts the encrypted challenge, it MUST include a padata + element of type PA-ENCRYPTED-CHALLENGE. The KDC encrypts its current + time in the challenge key. The KDC MUST strengthen the reply key + before issuing a ticket. The client MUST check that the timestamp + decrypts properly. The client MAY check that the timestamp is within + the window of acceptable clock skew for the client. The client MUST + NOT require that the timestamp be identical to the timestamp in the + issued credentials or the returned message. + + + + + + +Hartman & Zhu Standards Track [Page 35] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + The encrypted challenge FAST factor provides the following + facilities: Client Authentication and KDC Authentication. This FAST + factor also takes advantage of the FAST facility to strengthen the + reply key. It does not provide the Replace Reply Key facility. The + Security Considerations section of this document provides an + explanation why the security requirements are met. + + The encrypted challenge FAST factor can be useful in an + authentication set. No pa-hint is defined because the only + information needed by this mechanism is information contained in the + PA-ETYPE-INFO2 pre-authentication data. KDCs are already required to + send PA-ETYPE-INFO2. If KDCs were not required to send PA-ETYPE- + INFO2 then that information would need to be part of a hint for + encrypted challenge. + + Conforming implementations MUST support the encrypted challenge FAST + factor. + +5.5. Authentication Strength Indication + + Implementations that have pre-authentication mechanisms offering + significantly different strengths of client authentication MAY choose + to keep track of the strength of the authentication used as an input + into policy decisions. For example, some principals might require + strong pre-authentication, while less sensitive principals can use + relatively weak forms of pre-authentication like encrypted timestamp. + + An AuthorizationData data type AD-Authentication-Strength is defined + for this purpose. + + AD-authentication-strength 70 + + The corresponding ad-data field contains the DER encoding of the pre- + authentication data set as defined in Section 5.3. This set contains + all the pre-authentication mechanisms that were used to authenticate + the client. If only one pre-authentication mechanism was used to + authenticate the client, the pre-authentication set contains one + element. Unless otherwise specified, the hint and value fields of + the members of this sequence MUST be empty. In order to permit + mechanisms to carry additional information about strength in these + fields in the future, clients and application servers MUST ignore + non-empty hint and value fields for mechanisms unless the + implementation is updated with the interpretation of these fields for + a given pre-authentication mechanism in this authorization element. + + The AD-authentication-strength element MUST be included in the AD- + KDC-ISSUED container so that the KDC integrity protects its contents. + This element can be ignored if it is unknown to the receiver. + + + +Hartman & Zhu Standards Track [Page 36] + +RFC 6113 Kerberos Preauth Framework April 2011 + + +6. Assigned Constants + + The pre-authentication framework and FAST involve using a number of + Kerberos protocol constants. This section lists protocol constants + first introduced in this specification drawn from registries not + managed by IANA. Many of these registries would best be managed by + IANA; that is a known issue that is out of scope for this document. + The constants described in this section have been accounted for and + will appear in the next revision of the Kerberos core specification + or in a document creating IANA registries. + + Section 7 creates IANA registries for a different set of constants + used by the extensions described in this document. + +6.1. New Errors + + KDC_ERR_PREAUTH_EXPIRED 90 + KDC_ERR_MORE_PREAUTH_DATA_REQUIRED 91 + KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET 92 + KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS 93 + +6.2. Key Usage Numbers + + KEY_USAGE_FAST_REQ_CHKSUM 50 + KEY_USAGE_FAST_ENC 51 + KEY_USAGE_FAST_REP 52 + KEY_USAGE_FAST_FINISHED 53 + KEY_USAGE_ENC_CHALLENGE_CLIENT 54 + KEY_USAGE_ENC_CHALLENGE_KDC 55 + +6.3. Authorization Data Elements + + AD-authentication-strength 70 + AD-fx-fast-armor 71 + AD-fx-fast-used 72 + +6.4. New PA-DATA Types + + PA-FX-COOKIE 133 + PA-AUTHENTICATION-SET 134 + PA-AUTH-SET-SELECTED 135 + PA-FX-FAST 136 + PA-FX-ERROR 137 + PA-ENCRYPTED-CHALLENGE 138 + + + + + + + +Hartman & Zhu Standards Track [Page 37] + +RFC 6113 Kerberos Preauth Framework April 2011 + + +7. IANA Considerations + + This document creates a number of IANA registries. These registries + are all located under Kerberos Parameters on http://www.iana.org. + See [RFC5226] for descriptions of the registration policies used in + this section. + +7.1. Pre-Authentication and Typed Data + + RFC 4120 defines pre-authentication data, which can be included in a + KDC request or response in order to authenticate the client or extend + the protocol. In addition, it defines Typed-Data, which is an + extension mechanism for errors. Both pre-authentication data and + typed data are carried as a 32-bit signed integer along with an octet + string. The encoding of typed data and pre-authentication data is + slightly different. However, the types for pre-authentication data + and typed-data are drawn from the same namespace. By convention, + registrations starting with TD- are typed data and registrations + starting with PA- are pre-authentication data. It is important that + these data types be drawn from the same namespace, because some + errors where it would be desirable to include typed data require the + e-data field to be formatted as pre-authentication data. + + When Kerberos FAST is used, pre-authentication data encoding is + always used. + + There is one apparently conflicting registration between typed data + and pre-authentication data. PA-GET-FROM-TYPED-DATA and TD-PADATA + are both assigned the value 22. However, this registration is simply + a mechanism to include an element of the other encoding. The use of + both should be deprecated. + + This document creates a registry for pre-authentication and typed + data. The registration procedures are as follows. Expert review for + pre-authentication mechanisms designed to authenticate users, KDCs, + or establish the reply key. The expert first determines that the + purpose of the method is to authenticate clients, KDCs, or to + establish the reply key. If so, expert review is appropriate. The + expert evaluates the security and interoperability of the + specification. + + IETF review is required if the expert believes that the pre- + authentication method is broader than these three areas. Pre- + authentication methods that change the Kerberos state machine or + otherwise make significant changes to the Kerberos protocol should be + Standards Track RFCs. A concern that a particular method needs to be + a Standards Track RFC may be raised as an objection during IETF + review. + + + +Hartman & Zhu Standards Track [Page 38] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + Several of the registrations indicated below were made at a time when + the Kerberos protocol was less mature and do not meet the current + requirements for this registry. These registrations are included in + order to accurately document what is known about the use of these + protocol code points and to avoid conflicts. + + Type Value Reference + ---------------------------------------------------------------------- + PA-TGS-REQ 1 [RFC4120] + PA-ENC-TIMESTAMP 2 [RFC4120] + PA-PW-SALT 3 [RFC4120] + [reserved] 4 [RFC6113] + PA-ENC-UNIX-TIME 5 (deprecated) [RFC4120] + PA-SANDIA-SECUREID 6 [RFC4120] + PA-SESAME 7 [RFC4120] + PA-OSF-DCE 8 [RFC4120] + PA-CYBERSAFE-SECUREID 9 [RFC4120] + PA-AFS3-SALT 10 [RFC4120] [RFC3961] + PA-ETYPE-INFO 11 [RFC4120] + PA-SAM-CHALLENGE 12 [KRB-WG.SAM] + PA-SAM-RESPONSE 13 [KRB-WG.SAM] + PA-PK-AS-REQ_OLD 14 [PK-INIT-1999] + PA-PK-AS-REP_OLD 15 [PK-INIT-1999] + PA-PK-AS-REQ 16 [RFC4556] + PA-PK-AS-REP 17 [RFC4556] + PA-PK-OCSP-RESPONSE 18 [RFC4557] + PA-ETYPE-INFO2 19 [RFC4120] + PA-USE-SPECIFIED-KVNO 20 [RFC4120] + PA-SVR-REFERRAL-INFO 20 [REFERRALS] + PA-SAM-REDIRECT 21 [KRB-WG.SAM] + PA-GET-FROM-TYPED-DATA 22 (embedded in typed data) [RFC4120] + TD-PADATA 22 (embeds padata) [RFC4120] + PA-SAM-ETYPE-INFO 23 (sam/otp) [KRB-WG.SAM] + PA-ALT-PRINC 24 (crawdad@fnal.gov) [HW-AUTH] + PA-SERVER-REFERRAL 25 [REFERRALS] + PA-SAM-CHALLENGE2 30 (kenh@pobox.com) [KRB-WG.SAM] + PA-SAM-RESPONSE2 31 (kenh@pobox.com) [KRB-WG.SAM] + PA-EXTRA-TGT 41 Reserved extra TGT [RFC6113] + TD-PKINIT-CMS-CERTIFICATES 101 CertificateSet from CMS + TD-KRB-PRINCIPAL 102 PrincipalName + TD-KRB-REALM 103 Realm + TD-TRUSTED-CERTIFIERS 104 [RFC4556] + TD-CERTIFICATE-INDEX 105 [RFC4556] + TD-APP-DEFINED-ERROR 106 Application specific [RFC6113] + TD-REQ-NONCE 107 INTEGER [RFC6113] + TD-REQ-SEQ 108 INTEGER [RFC6113] + TD_DH_PARAMETERS 109 [RFC4556] + TD-CMS-DIGEST-ALGORITHMS 111 [ALG-AGILITY] + + + +Hartman & Zhu Standards Track [Page 39] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + TD-CERT-DIGEST-ALGORITHMS 112 [ALG-AGILITY] + PA-PAC-REQUEST 128 [MS-KILE] + PA-FOR_USER 129 [MS-KILE] + PA-FOR-X509-USER 130 [MS-KILE] + PA-FOR-CHECK_DUPS 131 [MS-KILE] + PA-AS-CHECKSUM 132 [MS-KILE] + PA-FX-COOKIE 133 [RFC6113] + PA-AUTHENTICATION-SET 134 [RFC6113] + PA-AUTH-SET-SELECTED 135 [RFC6113] + PA-FX-FAST 136 [RFC6113] + PA-FX-ERROR 137 [RFC6113] + PA-ENCRYPTED-CHALLENGE 138 [RFC6113] + PA-OTP-CHALLENGE 141 (gareth.richards@rsa.com) [OTP-PREAUTH] + PA-OTP-REQUEST 142 (gareth.richards@rsa.com) [OTP-PREAUTH] + PA-OTP-CONFIRM 143 (gareth.richards@rsa.com) [OTP-PREAUTH] + PA-OTP-PIN-CHANGE 144 (gareth.richards@rsa.com) [OTP-PREAUTH] + PA-EPAK-AS-REQ 145 (sshock@gmail.com) [RFC6113] + PA-EPAK-AS-REP 146 (sshock@gmail.com) [RFC6113] + PA_PKINIT_KX 147 [RFC6112] + PA_PKU2U_NAME 148 [PKU2U] + PA-SUPPORTED-ETYPES 165 [MS-KILE] + PA-EXTENDED_ERROR 166 [MS-KILE] + +7.2. Fast Armor Types + + FAST armor types are defined in Section 5.4.1. A FAST armor type is + a signed 32-bit integer. FAST armor types are assigned by standards + action. + + Type Name Description + ------------------------------------------------------------ + 0 Reserved. + 1 FX_FAST_ARMOR_AP_REQUEST Ticket armor using an ap-req. + +7.3. FAST Options + + A FAST request includes a set of bit flags to indicate additional + options. Bits 0-15 are critical; other bits are non-critical. + Assigning bits greater than 31 may require special support in + implementations. Assignment of FAST options requires standards + action. + + + + + + + + + + +Hartman & Zhu Standards Track [Page 40] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + Type Name Description + ------------------------------------------------------------------- + 0 RESERVED Reserved for future expansion of this + field. + 1 hide-client-names Requesting the KDC to hide client + names in the KDC response + 16 kdc-follow-referrals Reserved. + +8. Security Considerations + + The kdc-referrals option in the Kerberos FAST padata requests the KDC + to act as the client to follow referrals. This can overload the KDC. + To limit the damages of denial of service using this option, KDCs MAY + restrict the number of simultaneous active requests with this option + for any given client principal. + + Regarding the facilities provided by the Encrypted Challenge FAST + factor, the challenge key is derived from the client secrets and + because the client secrets are known only to the client and the KDC, + the verification of the EncryptedChallenge structure proves the + client's identity, the verification of the EncryptedChallenge + structure in the KDC reply proves that the expected KDC responded. + Therefore, the Encrypted Challenge FAST factor as a pre- + authentication mechanism offers the following facilities: Client + Authentication and KDC Authentication. There is no un-authenticated + cleartext introduced by the Encrypted Challenge FAST factor. + + FAST provides an encrypted tunnel over which pre-authentication + conversations can take place. In addition, FAST optionally + authenticates the KDC to the client. It is the responsibility of + FAST factors to authenticate the client to the KDC. Care MUST be + taken to design FAST factors such that they are bound to the + conversation. If this is not done, a man-in-the-middle may be able + to cut&paste a FAST factor from one conversation to another. The + easiest way to do this is to bind each FAST factor to the armor key + that is guaranteed to be unique for each conversation. + + The anonymous PKINIT mode for obtaining an armor ticket does not + always authenticate the KDC to the client before the conversation + begins. Tracking the KDC verified state guarantees that by the end + of the conversation, the client has authenticated the KDC. However, + FAST factor designers need to consider the implications of using + their factor when the KDC has not yet been authenticated. If this + proves problematic in an environment, then the particular FAST factor + should not be used with anonymous PKINIT. + + Existing pre-authentication mechanisms are believed to be at least as + secure when used with FAST as they are when used outside of FAST. + + + +Hartman & Zhu Standards Track [Page 41] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + One part of this security is making sure that when pre-authentication + methods checksum the request, they checksum the inner request rather + than the outer request. If the mechanism checksummed the outer + request, a man-in-the-middle could observe it outside a FAST tunnel + and then cut&paste it into a FAST exchange where the inner rather + than outer request would be used to select attributes of the issued + ticket. Such attacks would typically invalidate auditing information + or create a situation where the client and KDC disagree about what + ticket is issued. However, such attacks are unlikely to allow an + attacker who would not be able to authenticate as a principal to do + so. Even so, FAST is believed to defend against these attacks in + existing legacy mechanism. However, since there is no standard for + how legacy mechanisms bind the request to the pre-authentication or + provide integrity protection, security analysis can be difficult. In + some cases, FAST may significantly improve the integrity protection + of legacy mechanisms. + + The security of the TGS exchange depends on authenticating the client + to the KDC. In the AS exchange, this is done using pre- + authentication data or FAST factors. In the TGS exchange, this is + done by presenting a TGT and by using the session (or sub-session) + key in constructing the request. Because FAST uses a request body in + the inner request, encrypted in the armor key, rather than the + request body in the outer request, it is critical that establishing + the armor key be tied to the authentication of the client to the KDC. + If this is not done, an attacker could manipulate the options + requested in the TGS request, for example, requesting a ticket with + different validity or addresses. The easiest way to bind the armor + key to the authentication of the client to the KDC is for the armor + key to depend on the sub-session key of the TGT. This is done with + the implicit TGS armor supported by this specification. Future armor + types designed for use with the TGS MUST either bind their armor keys + to the TGT or provide another mechanism to authenticate the client to + the KDC. + +9. Acknowledgements + + Sam Hartman would like to thank the MIT Kerberos Consortium for its + funding of his time on this project. + + Several suggestions from Jeffrey Hutzelman based on early revisions + of this documents led to significant improvements of this document. + + The proposal to ask one KDC to chase down the referrals and return + the final ticket is based on requirements in [CROSS]. + + Joel Weber had a proposal for a mechanism similar to FAST that + created a protected tunnel for Kerberos pre-authentication. + + + +Hartman & Zhu Standards Track [Page 42] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + Srinivas Cheruku and Greg Hudson provided valuable review comments. + +10. References + +10.1. Normative References + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC3961] Raeburn, K., "Encryption and Checksum Specifications + for Kerberos 5", RFC 3961, February 2005. + + [RFC4120] Neuman, C., Yu, T., Hartman, S., and K. Raeburn, "The + Kerberos Network Authentication Service (V5)", + RFC 4120, July 2005. + + [RFC4556] Zhu, L. and B. Tung, "Public Key Cryptography for + Initial Authentication in Kerberos (PKINIT)", + RFC 4556, June 2006. + + [RFC5226] Narten, T. and H. Alvestrand, "Guidelines for Writing + an IANA Considerations Section in RFCs", BCP 26, + RFC 5226, May 2008. + + [RFC6112] Zhu, L., Leach, P., and S. Hartman "Anonymity Support + for Kerberos", RFC 6112, April 2011. + +10.2. Informative References + + [ALG-AGILITY] Astrand, L. and L. Zhu, "PK-INIT algorithm agility", + Work in Progress, August 2008. + + [CROSS] Sakane, S., Zrelli, S., and M. Ishiyama , "Problem + statement on the cross-realm operation of Kerberos in + a specific system", Work in Progress, July 2007. + + [EKE] Bellovin, S. and M. Merritt, "Augmented Encrypted Key + Exchange: A Password-Based Protocol Secure Against + Dictionary Attacks and Password File Compromise, + Proceedings of the 1st ACM Conference on Computer and + Communications Security, ACM Press.", November 1993. + + [HW-AUTH] Crawford, M., "Passwordless Initial Authentication to + Kerberos by Hardware Preauthentication", Work + in Progress, October 2006. + + [IEEE1363.2] IEEE, "IEEE P1363.2: Password-Based Public-Key + Cryptography", 2004. + + + +Hartman & Zhu Standards Track [Page 43] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + [KRB-WG.SAM] Hornstein, K., Renard, K., Neuman, C., and G. Zorn, + "Integrating Single-use Authentication Mechanisms + with Kerberos", Work in Progress, July 2004. + + [MS-KILE] Microsoft, "Kerberos Protocol Extensions", . + + [OTP-PREAUTH] Richards, G., "OTP Pre-authentication", Work + in Progress, February 2011. + + [PK-INIT-1999] Tung, B., Neuman, C., Hur, M., Medvinsky, A., + Medvinsky, S., Wray, J., and J. Trostle, "Public Key + Cryptography for Initial Authentication in Kerberos", + Work in Progress, July 1999. + + [PKU2U] Zhu, L., Altman, J., and N. Williams, "Public Key + Cryptography Based User-to-User Authentication - + (PKU2U)", Work in Progress, November 2008. + + [REFERRALS] Hartman, S., Ed., Raeburn, K., and L. Zhu, "Kerberos + Principal Name Canonicalization and KDC-Generated + Cross-Realm Referrals", Work in Progress, March 2011. + + [RFC4557] Zhu, L., Jaganathan, K., and N. Williams, "Online + Certificate Status Protocol (OCSP) Support for Public + Key Cryptography for Initial Authentication in + Kerberos (PKINIT)", RFC 4557, June 2006. + + + + + + + + + + + + + + + + + + + + + + + + +Hartman & Zhu Standards Track [Page 44] + +RFC 6113 Kerberos Preauth Framework April 2011 + + +Appendix A. Test Vectors for KRB-FX-CF2 + + This informative appendix presents test vectors for the KRB-FX-CF2 + function. Test vectors are presented for several encryption types. + In all cases, the first key (k1) is the result of string-to- + key("key1", "key1", default_parameters) and the second key (k2) is + the result of string-to-key("key2", "key2", default_parameters). + Both keys are of the same enctype. The presented test vector is the + hexadecimal encoding of the key produced by KRB-FX-CF2(k1, k2, "a", + "b"). The peppers are one-octet ASCII strings. + + In performing interoperability testing, there was significant + ambiguity surrounding [RFC3961] pseudo-random operations. These test + vectors assume that the AES pseudo-random operation is + aes-ecb(trunc128(sha-1(input))) where trunc128 truncates its input to + 128 bits. The 3DES pseudo-random operation is assumed to be + des3-cbc(trunc128(sha-1(input))). The DES pseudo-random operation is + assumed to be des-cbc(md5(input)). As specified in RFC 4757, the RC4 + pseudo-random operation is hmac-sha1(input). + + Interoperability testing also demonstrated ambiguity surrounding the + DES random-to-key operation. The random-to-key operation is assumed + to be distribute 56 bits into high-7-bits of 8 octets and generate + parity. + + These test vectors were produced with revision 22359 of the MIT + Kerberos sources. The AES 256 and AES 128 test vectors have been + confirmed by multiple other implementors. The RC4 test vectors have + been confirmed by one other implementor. The DES and triple DES test + vectors have not been confirmed. + + aes 128 (enctype 17): 97df97e4b798b29eb31ed7280287a92a + AES256 (enctype 18): 4d6ca4e629785c1f01baf55e2e548566 + b9617ae3a96868c337cb93b5e72b1c7b + DES (enctype 1): 43bae3738c9467e6 + 3DES (enctype 16): e58f9eb643862c13ad38e529313462a7f73e62834fe54a01 + RC4 (enctype 23): 24d7f6b6bae4e5c00d2082c5ebab3672 + + + + + + + + + + + + + + +Hartman & Zhu Standards Track [Page 45] + +RFC 6113 Kerberos Preauth Framework April 2011 + + +Appendix B. ASN.1 Module + + KerberosPreauthFramework { + iso(1) identified-organization(3) dod(6) internet(1) + security(5) kerberosV5(2) modules(4) preauth-framework(3) + } DEFINITIONS EXPLICIT TAGS ::= BEGIN + + IMPORTS + KerberosTime, PrincipalName, Realm, EncryptionKey, Checksum, + Int32, EncryptedData, PA-ENC-TS-ENC, PA-DATA, KDC-REQ-BODY, + Microseconds, KerberosFlags, UInt32 + FROM KerberosV5Spec2 { iso(1) identified-organization(3) + dod(6) internet(1) security(5) kerberosV5(2) + modules(4) krb5spec2(2) }; + -- as defined in RFC 4120. + + PA-AUTHENTICATION-SET ::= SEQUENCE OF PA-AUTHENTICATION-SET-ELEM + + PA-AUTHENTICATION-SET-ELEM ::= SEQUENCE { + pa-type [0] Int32, + -- same as padata-type. + pa-hint [1] OCTET STRING OPTIONAL, + pa-value [2] OCTET STRING OPTIONAL, + ... + } + + KrbFastArmor ::= SEQUENCE { + armor-type [0] Int32, + -- Type of the armor. + armor-value [1] OCTET STRING, + -- Value of the armor. + ... + } + + PA-FX-FAST-REQUEST ::= CHOICE { + armored-data [0] KrbFastArmoredReq, + ... + } + + KrbFastArmoredReq ::= SEQUENCE { + armor [0] KrbFastArmor OPTIONAL, + -- Contains the armor that identifies the armor key. + -- MUST be present in AS-REQ. + req-checksum [1] Checksum, + -- For AS, contains the checksum performed over the type + -- KDC-REQ-BODY for the req-body field of the KDC-REQ + -- structure; + -- For TGS, contains the checksum performed over the type + + + +Hartman & Zhu Standards Track [Page 46] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + -- AP-REQ in the PA-TGS-REQ padata. + -- The checksum key is the armor key, the checksum + -- type is the required checksum type for the enctype of + -- the armor key, and the key usage number is + -- KEY_USAGE_FAST_REQ_CHKSUM. + enc-fast-req [2] EncryptedData, -- KrbFastReq -- + -- The encryption key is the armor key, and the key usage + -- number is KEY_USAGE_FAST_ENC. + ... + } + + KrbFastReq ::= SEQUENCE { + fast-options [0] FastOptions, + -- Additional options. + padata [1] SEQUENCE OF PA-DATA, + -- padata typed holes. + req-body [2] KDC-REQ-BODY, + -- Contains the KDC request body as defined in Section + -- 5.4.1 of [RFC4120]. + -- This req-body field is preferred over the outer field + -- in the KDC request. + ... + } + + FastOptions ::= KerberosFlags + -- reserved(0), + -- hide-client-names(1), + -- kdc-follow-referrals(16) + + PA-FX-FAST-REPLY ::= CHOICE { + armored-data [0] KrbFastArmoredRep, + ... + } + + KrbFastArmoredRep ::= SEQUENCE { + enc-fast-rep [0] EncryptedData, -- KrbFastResponse -- + -- The encryption key is the armor key in the request, and + -- the key usage number is KEY_USAGE_FAST_REP. + ... + } + + KrbFastResponse ::= SEQUENCE { + padata [0] SEQUENCE OF PA-DATA, + -- padata typed holes. + strengthen-key [1] EncryptionKey OPTIONAL, + -- This, if present, strengthens the reply key for AS and + -- TGS. MUST be present for TGS + -- MUST be absent in KRB-ERROR. + + + +Hartman & Zhu Standards Track [Page 47] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + finished [2] KrbFastFinished OPTIONAL, + -- Present in AS or TGS reply; absent otherwise. + nonce [3] UInt32, + -- Nonce from the client request. + ... + } + + KrbFastFinished ::= SEQUENCE { + timestamp [0] KerberosTime, + usec [1] Microseconds, + -- timestamp and usec represent the time on the KDC when + -- the reply was generated. + crealm [2] Realm, + cname [3] PrincipalName, + -- Contains the client realm and the client name. + ticket-checksum [4] Checksum, + -- checksum of the ticket in the KDC-REP using the armor + -- and the key usage is KEY_USAGE_FAST_FINISH. + -- The checksum type is the required checksum type + -- of the armor key. + ... + } + + EncryptedChallenge ::= EncryptedData + -- Encrypted PA-ENC-TS-ENC, encrypted in the challenge key + -- using key usage KEY_USAGE_ENC_CHALLENGE_CLIENT for the + -- client and KEY_USAGE_ENC_CHALLENGE_KDC for the KDC. + END + +Authors' Addresses + + Sam Hartman + Painless Security + + EMail: hartmans-ietf@mit.edu + + + Larry Zhu + Microsoft Corporation + One Microsoft Way + Redmond, WA 98052 + US + + EMail: larry.zhu@microsoft.com + + + + + + + +Hartman & Zhu Standards Track [Page 48] + diff --git a/doc/standardisation/rfc6717.txt b/doc/standardisation/rfc6717.txt new file mode 100644 index 000000000..8bd72ffc3 --- /dev/null +++ b/doc/standardisation/rfc6717.txt @@ -0,0 +1,731 @@ + + + + + + +Independent Submission H. Hotz +Request for Comments: 6717 Jet Propulsion Lab, Caltech +Category: Informational R. Allbery +ISSN: 2070-1721 Stanford University + August 2012 + + + kx509 Kerberized Certificate Issuance Protocol in Use in 2012 + +Abstract + + This document describes a protocol, called kx509, for using Kerberos + tickets to acquire X.509 certificates. These certificates may be + used for many of the same purposes as X.509 certificates acquired by + other means, but if a Kerberos infrastructure already exists, then + the overhead of using kx509 may be much less. + + While not standardized, this protocol is already in use at several + large organizations, and certificates issued with this protocol are + recognized by the International Grid Trust Federation. + +Status of This Memo + + This document is not an Internet Standards Track specification; it is + published for informational purposes. + + This is a contribution to the RFC Series, independently of any other + RFC stream. The RFC Editor has chosen to publish this document at + its discretion and makes no statement about its value for + implementation or deployment. Documents approved for publication by + the RFC Editor are not a candidate for any level of Internet + Standard; see Section 2 of RFC 5741. + + Information about the current status of this document, any errata, + and how to provide feedback on it may be obtained at + http://www.rfc-editor.org/info/rfc6717. + +Copyright Notice + + Copyright (c) 2012 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. + + + +Hotz & Allbery Informational [Page 1] + +RFC 6717 kx509 August 2012 + + +Table of Contents + + 1. Introduction ....................................................2 + 1.1. Requirements Language ......................................3 + 2. Protocol Data ...................................................3 + 2.1. Request Packet .............................................3 + 2.2. Reply Packet ...............................................4 + 3. Protocol Operation ..............................................7 + 4. Acknowledgements ................................................8 + 5. IANA Considerations .............................................8 + 6. Security Considerations .........................................9 + 7. References .....................................................10 + 7.1. Normative References ......................................10 + 7.2. Informative References ....................................10 + Appendix A. Certificate Caching and Deployment Considerations ....12 + Appendix B. Historic Extensions ..................................12 + Appendix C. Example Exchange .....................................12 + +1. Introduction + + The two primary ways of providing cryptographically secure + identification on the Internet are Kerberos tickets [RFC4120] and + X.509 [RFC5280] [X.509] certificates. + + In practical IT infrastructure where both are in use, it's highly + desirable to deploy their support in a way that guarantees they both + authoritatively refer to the same entities. There is already a + widely adopted standard for using X.509 certificates to acquire + corresponding Kerberos tickets called Public Key Cryptography for + Initial Authentication in Kerberos (PKINIT) [RFC4556]. This document + describes the kx509 protocol for supporting the symmetric operation + of acquiring X.509 certificates using Kerberos tickets. + + Preparing and reviewing this document exposed a number of issues that + are discussed in the security considerations. Unfortunately, some of + them can only be addressed with an incompatible upgrade to this + protocol. The IETF's Kerberos working group has an expected work + item to address these issues. + + The International Grid Trust Federation [IGTF] supports the use of + Short Lived Credential Services [SLCS] as a means to authenticate for + resource usage based on other, native identity stores that an + organization maintains. X.509 certificates issued using the kx509 + protocol based on a Kerberos identity is one of the recognized + credential services. The certificate profile for that use is outside + the scope of this RFC but is described in [GRID-prof]. + + + + + +Hotz & Allbery Informational [Page 2] + +RFC 6717 kx509 August 2012 + + + In normal operation, kx509 can be used after a Kerberos ticket- + granting-ticket (TGT) is acquired, which is most likely during user + login. First, the client generates an RSA public/private key pair. + Next, using the Kerberos ticket-granting-ticket, it acquires a + Kerberos service ticket for the KCA (Kerberized Certificate + Authority) and uses this to send the public half of its key pair. + The KCA will decrypt the service ticket, verify the integrity of the + incoming packet, determine the identity of the user, and use the + session key to send back a corresponding X.509 certificate. + +1.1. Requirements Language + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC 2119 [RFC2119]. + +2. Protocol Data + + The protocol consists of a single request/reply exchange using UDP. + + Both the request and the reply packet begin with four bytes of + version ID information, followed by a DER-encoded ASN.1 message. The + first two bytes of the version ID are reserved. They MUST be set to + zero when sent and SHOULD be ignored when received. The third and + fourth bytes are the major and minor version numbers, respectively. + The version of the protocol described in this document is designated + 2.0, so the first four bytes of the packet are 0, 0, 2, and 0. + + Incompatible variations of this protocol MUST use a different major + version number. + +2.1. Request Packet + + The request consists of a version ID, followed by a DER-encoded ASN.1 + message containing a Kerberos AP-REQ, integrity check data on the + request, and public key generated by the client. The ASN.1 encoding + is: + + KX509Request ::= SEQUENCE { + AP-REQ OCTET STRING, + pk-hash OCTET STRING, + pk-key OCTET STRING + } + + The AP-REQ is as described in [RFC4120], Section 5.5.1. + + + + + + +Hotz & Allbery Informational [Page 3] + +RFC 6717 kx509 August 2012 + + + The pk-hash is Hashed Message Authentication Code (HMAC) using SHA-1 + as the underlying hash. All 160 bits are sent. The key used is the + Kerberos session key. The data to be hashed is the concatenation of + the following: + + o 4-byte version ID at the beginning of the packet. + + o OCTET STRING of the AP-REQ. + + o OCTET STRING of the pk-key. + + The pk-key contains a public key. This key and its corresponding + private key are generated by the client before contacting the server. + Implementations of this protocol MUST support RSA keys, in which case + the key is a DER-encoded RSAPublicKey as defined in [RFC3447], + Section A.1.1, and then it is stored in this octet string in the + request. Its encoding as an OCTET STRING starts with the 0x30 byte + sequence at the beginning of a DER-encoded RSAPublicKey. Use of + other public-key types is not defined. + + Appendix C shows an example request packet. + +2.2. Reply Packet + + The reply consists of a version ID, followed by a DER-encoded ASN.1 + message containing an error code, an optional authentication hash, + optional certificate, and optional error text. The service SHOULD + return replies of the same version as the request where possible. + + KX509Response ::= SEQUENCE { + error-code[0] INTEGER DEFAULT 0, + hash[1] OCTET STRING OPTIONAL, + certificate[2] OCTET STRING OPTIONAL, + e-text[3] VisibleString OPTIONAL + } + + Although the format of the reply contains independently optional + objects, the server MUST only generate replies with one of the + following allowed combinations. + + +------------+------+-------------+--------+ + | | hash | certificate | | + | error-code | hash | | e-text | + | error-code | | | e-text | + +------------+------+-------------+--------+ + + + + + + +Hotz & Allbery Informational [Page 4] + +RFC 6717 kx509 August 2012 + + + The first case is returned when the server successfully generates a + certificate for the user. The certificate is a DER-encoded + certificate as defined in [RFC5280], Appendix A, page 116. Its + encoding as an OCTET STRING starts with the 0x30 byte sequence that + is at the beginning of a DER-encoded certificate. + + The second case is returned when the server successfully + authenticates the user and their key, but is unable for some other + reason to generate a certificate. + + The third case MAY be returned if the server is unable to + successfully authenticate the user and intends to return some + unauthenticated information to the client. + + The hash on a response is computed using SHA-1 HMAC as for the + request. + + The data that is hashed is the concatenation of the following things: + + o 4-byte version ID at the beginning of the packet. + + o DER representation of the error-code exclusive of the tag and + length, if it is present. + + o OCTET STRING of the certificate, if it is present. + + o VisibleString representation of the e-text exclusive of the tag + and length, if it is present. + + In other words, the hash is computed on the data in the fields that + are present, exclusive of the overall ASN.1 wrapping. + + The e-text MAY be translated into other character sets for display + purposes, but the hash is computed on the e-text in its VisibleString + representation. If the e-text contains NUL characters, the client + MAY ignore any part of the error message after the first NUL + character for display purposes. + + As implied by the above table, if the reply does not contain a + certificate, it MUST contain an error message and a non-zero error + code. Conversely, if a certificate is returned, then the error-code + MUST be zero. The server SHOULD use the DEFAULT encoding for a zero + error-code value by omitting any explicit error-code from the reply. + + + + + + + + +Hotz & Allbery Informational [Page 5] + +RFC 6717 kx509 August 2012 + + + The defined values for error-code are as follows: + + +------------+-----------------------------+------------------------+ + | error-code | Condition | Example | + +------------+-----------------------------+------------------------+ + | 1 | Permanent problem with | Incompatible version | + | | client request | | + | 2 | Solvable problem with | Expired Kerberos | + | | client request | credentials | + | 3 | Temporary problem with | Packet loss | + | | client request | | + | 4 | Permanent problem with the | Internal | + | | server | misconfiguration | + | 5 | Temporary problem with the | Server overloaded | + | | server | | + +------------+-----------------------------+------------------------+ + + If a client error is returned, the client SHOULD NOT retry the + request unless some remedial action is first taken, although if + error-code 3 is returned, the client MAY retry with other servers + before giving up. + + If a server error is returned, it is RECOMMENDED that the client + retry the request with a different server if one is known. + + Since all KCAs serving a Kerberos realm are intended to be + equivalent, in accordance with Section 4.1.2.2 of [RFC5280], the + certificates returned from different KCAs serving the same Kerberos + realm MUST NOT contain duplicate serial numbers. + + This protocol and document do not address certificate verification or + path construction. There are no provisions for returning any + additional certificates that might be needed. Any application using + a returned certificate must be configured independently to address + these issues. An incompatible upgrade to this protocol will provide + options to address this issue. + + The returned certificate MUST identify the Kerberos client principal + from the AP-REQ in the original KX509Request in the subject of the + certificate or in a subjectAltName extension. The identification + MUST be unique within the organization's deployed infrastructure. It + is RECOMMENDED that a subjectAltName extension be included of type + id-pkinit-san as described in [RFC4556], Section 3.2.2. Note that + the id-pkinit-san is simply a standard representation of a Kerberos + principal and has no other implications with respect to PKINIT. + + + + + + +Hotz & Allbery Informational [Page 6] + +RFC 6717 kx509 August 2012 + + + Other extensions MAY be added according to local policy. + + Appendix C shows an example reply packet. + +3. Protocol Operation + + Absent errors, the protocol consists of a single request, sent via + UDP, and a single reply, also sent via UDP. + + There is no special provision for requests or replies that exceed the + allowable size of a UDP packet. Also, some implementations have + imposed hard size limits that are smaller than a typical UDP MTU and + will limit the use of extensions and the supportable key size. Even + without hard limits, if the request or reply exceeds the MTU size of + a UDP packet for the infrastructure in use, then the reliability of + the exchange will decrease significantly. + + For "normal" Kerberos AP-REQ structures, and "normal" X.509 + certificates, this is unlikely unless the Kerberos service ticket + contains large amounts of authorization data. For this reason, it is + RECOMMENDED that service tickets for the KCA be issued without + authorization data. If the KCA performs authorization, it should do + so by other means. + + Before constructing the request, the client must know the canonical + name(s) and port(s) of the server(s) to contact. It MAY determine + them by looking up the service's SRV record as described in + [RFC2782]. The entry to be used is _kca._udp._realm_, where _realm_ + is the Kerberos realm, used as part of the DNS name. + + The client has to acquire a service ticket in order to construct the + AP-REQ for the service. Conventionally, the Kerberos service + principal name to use for this service has a first component of + "kca_service". Absent local configuration or other external + knowledge of the correct principal to use, the second and final + component is conventionally the canonical name of the KCA server + being contacted, and the realm of the principal is determined + following normal Kerberos domain-to-realm mapping conventions, as + discussed in [RFC4120], Section 1.3. + + When the server receives a request, it MUST verify the following + properties of the request before issuing a certificate: + + o The AP-REQ can be decoded and is not expired. + + o If the request uses cross-realm authentication, then it satisfies + the requirements of local policy and [RFC4120], Sections 1.2 and + 2.7. + + + +Hotz & Allbery Informational [Page 7] + +RFC 6717 kx509 August 2012 + + + o The request's hash is valid. + + The server SHOULD make other sanity checks, such as a minimum public + key length, to the extent feasible. + + The server MAY decline to respond to an erroneous request. If it + does not receive a response, a client MAY retry its request, but the + client SHOULD wait at least one second before doing so. + + The client MUST verify any hash in the reply and MUST NOT use any + certificate in a reply whose hash does not verify. The client MAY + display the e-text if the hash is absent or does not verify but + SHOULD indicate the message is not authenticated. + +4. Acknowledgements + + The original version of kx509 was implemented using Kerberos 4 at the + University of Michigan and was nicely documented in [KX509]. Many + thanks to them for their original work, as well as the subsequent + updates. + + While developing this document, important corrections and comments + were provided by Jeffrey Altman and Love Hornquist Astrand. The + following people also provided many helpful comments and corrections: + Doug Engert, Jeffrey Hutzelman, Sam Hartman, Timothy J. Miller, + Chaskiel Grundman, and Jim Schaad. Alan Sill provided the references + to the International Grid Trust Federation and its acceptable + credential services. Example network traffic was provided by Doug + Engert, Marcus Watts, Matt Crawford, and Chaskiel Grundman from their + deployments and was extremely useful for verifying the reality of + this specification. + +5. IANA Considerations + + This service is conventionally run on UDP port 9878. IANA has + registered that port in the Service Name and Transport Port Number + Registry as follows: + + Service Name: kca-service + Transport Protocol: UDP + Assignee: IESG + Contact: IETF Chair + Description: The kx509 Kerberized Certificate Issuance + Protocol in Use in 2012 + Reference: RFC 6717 + Port Number: 9878 + Assignment Notes: Historically, this service has been referred to + as "kca_service", but this service name does + + + +Hotz & Allbery Informational [Page 8] + +RFC 6717 kx509 August 2012 + + + not meet the registry requirements. + + The Generic Security Service Application Program Interface (GSS-API) + / Kerberos / Simple Authentication and Security Layer (SASL) service + name currently in use for this protocol is "kca_service". This does + not meet the naming requirements for IANA's GSS-API/Kerberos/SASL + service name registry, so no registration has been requested. The + conflict between the conventional service name and the registry rules + is expected to be addressed in a future version of this protocol. + Appropriate registrations will be requested at that time. + +6. Security Considerations + + The only encrypted information in the protocol is that used by + Kerberos itself. The considerations for any Kerberized service apply + here. + + The public key in the request is sent in the clear and without any + guarantees that the requester actually possesses the corresponding + private key. Therefore, the only appropriate uses of the returned + certificate are those where the identity of the requester is + unimportant or the subsequent use independently guarantees that the + user possesses the private key. This issue is expected to be + addressed in a future version of this protocol. + + For example, if the kx509-issued certificate is used for a digital + signature in a way that does not independently demonstrate proof-of- + possession of the private key, then an eavesdropper could request + their own valid certificate via kx509 and claim to have originated + material signed by the legitimate, original requester. [RFC4211], + Appendix C, contains a more detailed discussion of why proof-of- + possession is important. + + An example that should be safe is initial client authentication with + Transport Layer Security (TLS) [RFC5246] connections. If a client + certificate is used, then a Certificate Verify message (Section 7.4.8 + of [RFC5246]) is added to the handshake exchange. It includes a + signature of the handshake messages to that point. Those messages + depend on data known only to the client and server ends of the + specific connection, so computing the signature proves possession of + the private key. This application was the original intended use case + for kx509. + + Some information, such as the public key and certificate, is + transmitted in the clear but (as the name implies) is generally + intended to be publicly available. However, its visibility could + still raise privacy concerns. The hash is used to protect the + integrity of this information. + + + +Hotz & Allbery Informational [Page 9] + +RFC 6717 kx509 August 2012 + + + The policies for issuing Kerberos tickets and X.509 certificates are + usually expressed very differently. An implementation of this + protocol should not provide a mechanism for bypassing ticket or + certificate policies. + + In particular, if the issued certificate can be used with PKINIT, + this authentication loop SHOULD NOT bypass policy limits for either + X.509 certificates or Kerberos tickets. + + X.509 certificates are usually issued with considerably longer + validity times than Kerberos tickets. Care should be taken that the + issued certificate is not valid for longer than the intended policy + should allow. Note that Section 3.2.3 of [RFC4556] REQUIRES that the + lifetime of an issued ticket not exceed the lifetime of the + predecessor certificate. By analogy, it is RECOMMENDED that the + lifetime of an issued certificate not exceed the lifetime of the + predecessor Kerberos ticket unless the implications with respect to + local policy and supporting infrastructure are clearly understood and + allow it. + +7. References + +7.1. Normative References + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC3447] Jonsson, J. and B. Kaliski, "Public-Key Cryptography + Standards (PKCS) #1: RSA Cryptography Specifications + Version 2.1", RFC 3447, February 2003. + + [RFC4120] Neuman, C., Yu, T., Hartman, S., and K. Raeburn, "The + Kerberos Network Authentication Service (V5)", RFC 4120, + July 2005. + + [RFC5280] Cooper, D., Santesson, S., Farrell, S., Boeyen, S., + Housley, R., and W. Polk, "Internet X.509 Public Key + Infrastructure Certificate and Certificate Revocation + List (CRL) Profile", RFC 5280, May 2008. + +7.2. Informative References + + [GRID-prof] "Grid Certificate Profile", March 2008, + . + + [IGTF] "The International Grid Trust Federation", + . + + + + +Hotz & Allbery Informational [Page 10] + +RFC 6717 kx509 August 2012 + + + [KX509] Doster, W., Watts, M., and D. Hyde, "The KX.509 + Protocol", September 2001, . + + [RFC2782] Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS RR for + specifying the location of services (DNS SRV)", + RFC 2782, February 2000. + + [RFC4211] Schaad, J., "Internet X.509 Public Key Infrastructure + Certificate Request Message Format (CRMF)", RFC 4211, + September 2005. + + [RFC4556] Zhu, L. and B. Tung, "Public Key Cryptography for + Initial Authentication in Kerberos (PKINIT)", RFC 4556, + June 2006. + + [RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer + Security (TLS) Protocol Version 1.2", RFC 5246, + August 2008. + + [SLCS] "Short Lived Credential Services", February 2009, + . + + [X.509] International Telecommunications Union, "Recommendation + X.509: The Directory: Public-key and attribute + certificate framework", November 2008. + + + + + + + + + + + + + + + + + + + + + + + + + +Hotz & Allbery Informational [Page 11] + +RFC 6717 kx509 August 2012 + + +Appendix A. Certificate Caching and Deployment Considerations + + As noted in the Security Considerations section, the functional + lifetime of the acquired X.509 certificate should usually match the + lifetime of its predecessor Kerberos ticket. Therefore, it is likely + that X.509 certificates issued with this protocol should be deleted + when the supporting Kerberos tickets are deleted. That makes the + Kerberos ticket cache a reasonable location to store the certificate + (and its private key). + + On the other hand, applications, such as web browsers, probably + expect certificates in different stores. + + A widely used solution to this dichotomy is to implement a PKCS11 + library that supports the kx509-acquired credentials. The + credentials remain stored in the Kerberos credentials cache, but full + PKI functionality is still available via a standard interface for PKI + credentials. + +Appendix B. Historic Extensions + + This appendix documents extensions to the kx509 protocol that are + either no longer in use or are expected to be dropped. + + A subjectAltName othername extension of type kcaAuthRealm (OID value + 1.3.6.1.4.1.250.42.1) is frequently used to include the client's + realm as an ASN.1 octet string. + + The Microsoft-defined userPrincipalName has frequently been used for + the same purpose as the id-pkinit-san. + + The historic implementations of this protocol included provisions for + DSA keys in place of RSA. DSA does not appear to be in use. A + future version of this protocol will use a standard certificate + request structure that will provide algorithm agility. + + The historic implementations of this protocol allowed an optional + client-version field (at the end of the request) of type + VisibleString. If present, the KCA copied it into the issued + certificate as an extension with the OID 1.3.6.1.4.1.250.42.2. This + feature does not appear to be in use. + +Appendix C. Example Exchange + + The request and reply are from the same exchange. The Ethernet, IP, + and UDP headers, and the 4-byte version string at the beginning of + the request and reply packets are all omitted. Only the ASN.1- + encoded portions are shown. + + + +Hotz & Allbery Informational [Page 12] + +RFC 6717 kx509 August 2012 + + + 0:d=0 hl=4 l= 678 cons: SEQUENCE + 4:d=1 hl=4 l= 509 prim: OCTET STRING + [HEX DUMP]:6E8201F9308201F5A003... (AP-REQ) + 517:d=1 hl=2 l= 20 prim: OCTET STRING + [HEX DUMP]:ECFF1C922300D0E9DD02... (pk-hash) + 539:d=1 hl=3 l= 140 prim: OCTET STRING + [HEX DUMP]:30818902818100B70F46... (pk-key) + + Request Packet ASN.1 Decode + + 0:d=0 hl=4 l= 870 cons: SEQUENCE + 4:d=1 hl=2 l= 22 cons: cont [ 1 ] + 6:d=2 hl=2 l= 20 prim: OCTET STRING + [HEX DUMP]:F3A844834C26D843B6FD... (hash) + 28:d=1 hl=4 l= 842 cons: cont [ 2 ] + 32:d=2 hl=4 l= 838 prim: OCTET STRING + [HEX DUMP]:308203423082022AA003... (certificate) + + Reply Packet ASN.1 Decode + +Authors' Addresses + + Henry B. Hotz + Jet Propulsion Laboratory, California Institute of Technology + 4800 Oak Grove Dr. + Pasadena, CA 91109 + USA + + Phone: +01 818 354-4880 + EMail: hotz@jpl.nasa.gov + + + Russ Allbery + Stanford University + P.O. Box 20066 + Stanford, CA 94309 + USA + + EMail: rra@stanford.edu + URI: http://www.eyrie.org/~eagle/ + + + + + + + + + + + +Hotz & Allbery Informational [Page 13] + diff --git a/doc/standardisation/rfc6806.txt b/doc/standardisation/rfc6806.txt new file mode 100644 index 000000000..b4b292e56 --- /dev/null +++ b/doc/standardisation/rfc6806.txt @@ -0,0 +1,1067 @@ + + + + + + +Internet Engineering Task Force (IETF) S. Hartman, Ed. +Request for Comments: 6806 Painless Security +Updates: 4120 K. Raeburn +Category: Standards Track MIT +ISSN: 2070-1721 L. Zhu + Microsoft Corporation + November 2012 + + + Kerberos Principal Name Canonicalization and Cross-Realm Referrals + +Abstract + + This memo documents a method for a Kerberos Key Distribution Center + (KDC) to respond to client requests for Kerberos tickets when the + client does not have detailed configuration information on the realms + of users or services. The KDC will handle requests for principals in + other realms by returning either a referral error or a cross-realm + Ticket-Granting Ticket (TGT) to another realm on the referral path. + The clients will use this referral information to reach the realm of + the target principal and then receive the ticket. This memo also + provides a mechanism for verifying that a request has not been + tampered with in transit. This memo updates RFC 4120. + +Status of This Memo + + This is an Internet Standards Track document. + + This document is a product of the Internet Engineering Task Force + (IETF). It represents the consensus of the IETF community. It has + received public review and has been approved for publication by the + Internet Engineering Steering Group (IESG). Further information on + Internet Standards is available in Section 2 of RFC 5741. + + Information about the current status of this document, any errata, + and how to provide feedback on it may be obtained at + http://www.rfc-editor.org/info/rfc6806. + +Copyright Notice + + Copyright (c) 2012 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + + + +Hartman, et al. Standards Track [Page 1] + +RFC 6806 KDC Referrals November 2012 + + + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + + This document may contain material from IETF Documents or IETF + Contributions published or made publicly available before November + 10, 2008. The person(s) controlling the copyright in some of this + material may not have granted the IETF Trust the right to allow + modifications of such material outside the IETF Standards Process. + Without obtaining an adequate license from the person(s) controlling + the copyright in such materials, this document may not be modified + outside the IETF Standards Process, and derivative works of it may + not be created outside the IETF Standards Process, except to format + it for publication as an RFC or to translate it into languages other + than English. + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. Conventions Used in This Document . . . . . . . . . . . . . . 4 + 3. Requesting a Referral . . . . . . . . . . . . . . . . . . . . 4 + 4. Realm Organization Model . . . . . . . . . . . . . . . . . . . 5 + 4.1. Trust Assumptions . . . . . . . . . . . . . . . . . . . . 5 + 5. Enterprise Principal Name Type . . . . . . . . . . . . . . . . 6 + 6. Name Canonicalization . . . . . . . . . . . . . . . . . . . . 7 + 7. Client Referrals . . . . . . . . . . . . . . . . . . . . . . . 9 + 8. Server Referrals . . . . . . . . . . . . . . . . . . . . . . . 10 + 9. Cross-Realm Routing . . . . . . . . . . . . . . . . . . . . . 11 + 10. Caching Information . . . . . . . . . . . . . . . . . . . . . 11 + 11. Negotiation of FAST and Detecting Modified Requests . . . . . 12 + 12. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 13 + 13. Security Considerations . . . . . . . . . . . . . . . . . . . 13 + 13.1. Shared-Password Case . . . . . . . . . . . . . . . . . . . 16 + 13.2. Pre-Authentication Data . . . . . . . . . . . . . . . . . 16 + 14. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 17 + 15. References . . . . . . . . . . . . . . . . . . . . . . . . . . 17 + 15.1. Normative References . . . . . . . . . . . . . . . . . . . 17 + 15.2. Informative References . . . . . . . . . . . . . . . . . . 17 + Appendix A. Compatibility with Earlier Implementations of + Name Canonicalization . . . . . . . . . . . . . . . . 18 + + + + + + + + + + +Hartman, et al. Standards Track [Page 2] + +RFC 6806 KDC Referrals November 2012 + + +1. Introduction + + Current implementations of the Kerberos Authentication Service (AS) + and Ticket-Granting Service (TGS) protocols, as defined in [RFC4120], + use principal names constructed from a known user or service name and + realm. A service name is typically constructed from a name of the + service and the DNS host name of the computer that is providing the + service. Many existing deployments of Kerberos use a single Kerberos + realm where all users and services would be using the same realm. + However, in an environment where there are multiple Kerberos realms, + the client needs to be able to determine what realm a particular user + or service is in before making an AS or TGS request. Traditionally, + this requires client configuration to make this possible. + + When having to deal with multiple realms, users are forced to know + what realm they are in before they can obtain a Ticket-Granting + Ticket (TGT) with an AS request. However, in many cases, the user + would like to use a more familiar name that is not directly related + to the realm of their Kerberos principal name. A good example of + this is an email name in the style described in [RFC5322]. This + document describes a mechanism that would allow a user to specify a + user principal name that is an alias for the user's Kerberos + principal name. In practice, this would be the name that the user + specifies to obtain a TGT from a Kerberos KDC. The user principal + name no longer has a direct relationship with the Kerberos principal + or realm. Thus, the administrator is able to move the user's + principal to other realms without the user having to know that it + happened. + + Once a TGT has been obtained, the user would like to be able to + access services in any Kerberos realm for which there is an + authentication path from the realm of their principal. To do this + requires that the client be able to determine what realm the target + service principal is in before making the TGS request. Current + implementations of Kerberos typically have a table that maps DNS host + names to corresponding Kerberos realms. The user-supplied host name + or its domain component is looked up in this table (often using the + result of some form of host name lookup performed with insecure DNS + queries, in violation of [RFC4120]). The corresponding realm is then + used to complete the target service principal name. Even if insecure + DNS queries were not used, managing this table is problematic. + + This traditional mechanism requires that each client have very + detailed configuration information about the hosts that are providing + services and their corresponding realms. Having client-side + configuration information can be very costly from an administration + point of view -- especially if there are many realms and computers in + the environment. + + + +Hartman, et al. Standards Track [Page 3] + +RFC 6806 KDC Referrals November 2012 + + + This memo proposes a solution for these problems and simplifies + administration by minimizing the configuration information needed on + each computer using Kerberos. Specifically, it describes a mechanism + to allow the KDC to handle canonicalization of names, provide for + principal aliases for users and services, and allow the KDC to + determine the trusted realm authentication path by being able to + generate referrals to other realms in order to locate principals. + + Two kinds of KDC referrals are introduced in this memo: + + 1. Client referrals, in which the client doesn't know which realm + contains a user account. + + 2. Server referrals, in which the client doesn't know which realm + contains a server account. + + These two types of referrals introduce new opportunities for an + attacker. In order to avoid these attacks, a mechanism is provided + to protect the integrity of the request between the client and KDC. + This mechanism complements the Flexible Authentication Secure Tunnels + (FAST) facility provided in [RFC6113]. A mechanism is provided to + negotiate the availability of FAST. Among other benefits, this can + be used to protect errors generated by the referral process. + +2. Conventions Used in This Document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC2119]. + +3. Requesting a Referral + + In order to request referrals as defined in later sections, the + Kerberos client MUST explicitly request the "canonicalize" KDC option + (bit 15) [RFC4120] for the AS-REQ or TGS-REQ. This flag indicates to + the KDC that the client is prepared to receive a reply that contains + a principal name other than the one requested. + + KDCOptions ::= KerberosFlags + -- canonicalize (15) + -- other KDCOptions values omitted + + When sending names with the "canonicalize" KDC option, the client + should expect that names in the KDC's reply MAY be different than the + name in the request. A referral TGT is a cross-realm TGT that is + returned with the server name of the ticket being different from the + server name in the request [RFC4120]. + + + + +Hartman, et al. Standards Track [Page 4] + +RFC 6806 KDC Referrals November 2012 + + +4. Realm Organization Model + + This memo assumes that the world of principals is arranged on + multiple levels: the realm, the enterprise, and the world. A KDC may + issue tickets for any principal in its realm or cross-realm tickets + for realms with which it has a direct cross-realm relationship. The + KDC also has access to a trusted name service that can resolve any + name from within its enterprise into a realm closer along the + authentication path to the service. This trusted name service + removes the need to use an untrusted DNS lookup for name resolution. + + For example, consider the following configuration, where lines + indicate cross-realm relationships: + + EXAMPLE.COM + / \ + / \ + ADMIN.EXAMPLE.COM DEV.EXAMPLE.COM + + In this configuration, all users in the EXAMPLE.COM enterprise could + have principal names, such as alice@EXAMPLE.COM, with the same realm + portion. In addition, servers at EXAMPLE.COM should be able to have + DNS host names from any DNS domain independent of what Kerberos realm + their principals reside in. + +4.1. Trust Assumptions + + Two realms participate in any cross-realm relationship: an issuing + realm issues a cross-realm ticket, and a consuming realm uses this + ticket. There is a degree of trust of the issuing realm by the + consuming realm implied by this relationship. Whenever a service in + the consuming realm permits an authentication path containing the + issuing realm, that service trusts the issuing realm to accurately + represent the identity of the authenticated principal and any + information about the transited path. If the consuming realm's KDC + sets the transited policy checked flag, the KDC is making the same + trust assumption that a service would. + + This trust is transitive across a multi-hop authentication path. The + service's realm trusts each hop along the authentication path closer + to the client to accurately represent the authenticated identity and + to accurately represent transited information. Any KDC along this + path could impersonate the client. + + KDC-signed or -issued authorization data often implies additional + trust. The implications of such trust from a security and + operational standpoint is an ongoing topic of discussion during the + + + + +Hartman, et al. Standards Track [Page 5] + +RFC 6806 KDC Referrals November 2012 + + + development of this specification. As such, such discussion is out + of scope for this memo. + + Administrators have several tools to limit trust caused by cross- + realm relationships. A service or KDC can control what + authentication paths are acceptable. For example, if a given realm + is not permitted on the authentication path for a particular client, + then that realm cannot affect trust placed in that client principal. + Consuming realms can exercise significant control by deciding what + principals to place on an access-control list. If no client using a + given issuing realm in authentication paths is permitted to access a + resource, then that issuing realm is not trusted in access decisions + regarding that resource. + + Creating a cross-realm relationship implies relatively little + inherent trust in the issuing realm. Significant trust only applies + as principals dependent on that issuing realm are given access to + resources. However, two deployment characteristics may increase the + trust implied by the initial cross-realm relationship. First, a + number of realms provide access to any principal to some resources. + Access decisions involving these resources involve a degree of trust + in all issuing realms in the transited graph. Secondly, many realms + do not constrain the set of principals to which users of that realm + may grant access. In these realms, creating a cross-realm + relationship delegates the decision to trust that realm to users of + the consuming realm. In this situation, creating the cross-realm + relationship is the primary trust decision point under the + administrator's control. + +5. Enterprise Principal Name Type + + The NT-ENTERPRISE type principal name contains one component, a + string of realm-defined content, which is intended to be used as an + alias for another principal name in some realm in the enterprise. It + is used for conveying the alias name, not for the real principal + names within the realms, and thus is only useful when name + canonicalization is requested. + + The intent is to allow unification of email and security principal + names. For example, all users at EXAMPLE.COM may have a client + principal name of the form "joe@EXAMPLE.COM", even though the + principals are contained in multiple realms. This global name is + again an alias for the true client principal name, which indicates + what realm contains the principal. Thus, accounts "alice" in the + realm DEV.EXAMPLE.COM and "bob" in ADMIN.EXAMPLE.COM may log on as + "alice@EXAMPLE.COM" and "bob@EXAMPLE.COM". + + + + + +Hartman, et al. Standards Track [Page 6] + +RFC 6806 KDC Referrals November 2012 + + + This utilizes a new principal name type, as the KDC-REQ message only + contains a single client realm (crealm) field, and the realm portion + of this name corresponds to the Kerberos realm with which the request + is made. Thus, the entire name "alice@EXAMPLE.COM" is transmitted as + a single component in the client name field of the AS-REQ message, + with a name type of NT-ENTERPRISE [RFC4120] (and the local realm + name). The KDC will recognize this name type and then transform the + requested name into the true principal name if the client account + resides in the local realm. The true principal name can have a name + type different from the requested name type. Typically, the true + principal name will be an NT-PRINCIPAL [RFC4120]. + +6. Name Canonicalization + + A service or account may have multiple principal names. For example, + if a host is known by multiple names, host-based services on it may + be known by multiple names in order to prevent the client from + needing a secure directory service to determine the correct host name + to use. In order to avoid the need to update the host whenever a new + alias is created, the KDC may provide the mapping information to the + client in the credential acquisition process. + + If the "canonicalize" KDC option is set, then the KDC MAY change the + client and server principal names and types in the AS response and + ticket returned from those in the request. Names MUST NOT be changed + in the response to a TGS request, although it is common for KDCs to + maintain a set of aliases for service principals. Regardless of + which alias a client requests, the same service key is used. + However, in the TGS request, the client receives a ticket for the + alias requested. Services MUST NOT make distinctions based on which + alias is in the issued ticket, because the service name in a ticket + is not cryptographically protected and can be changed by parties + other than the KDC. + + For example, the AS request may specify a client name of "bob@ + EXAMPLE.COM" as an NT-ENTERPRISE name with the "canonicalize" KDC + option set, and the KDC will return with a client name of "104567" as + an NT-UID [RFC4120]. + + (It is assumed that the client discovers whether the KDC supports the + NT-ENTERPRISE name type via out-of-band mechanisms.) + + See Section 11 for a mechanism to detect modification of the request + between the client and KDC. However, for the best protection, + Flexible Authentication Secure Tunneling (FAST) [RFC6113] or another + mechanism that protects the entire KDC exchange SHOULD be used. + Clients MAY reject responses from a KDC where the client or server + name is changed if the KDC does not support such a mechanism. + + + +Hartman, et al. Standards Track [Page 7] + +RFC 6806 KDC Referrals November 2012 + + + Clients SHOULD reject an AS response that changes the server name + unless the response is protected by such a mechanism or the new + server name is one explicitly expected by the client. For example, + many clients permit the realm name to be changed in an AS response, + even if the response is not protected. See Section 13 for a + discussion of the tradeoffs in allowing unprotected responses. + + In order to permit authorization decisions to be made based on + aliases as well as the canonicalized form of a principal name, the + KDC MAY include the following authorization data element, wrapped in + AD-KDC-ISSUED, in the initial credentials and copy it from a ticket- + granting ticket into additional credentials: + + AD-LOGIN-ALIAS ::= SEQUENCE { -- ad-type number 80 -- + login-aliases [0] SEQUENCE (SIZE (1..MAX)) OF PrincipalName, + ... + } + + The login-aliases field lists one or more of the aliases the + principal is known by. + + In addition to permitting authorization based on aliases, this + permits user-to-user exchanges where the party receiving the + authenticator knows the other party only by an alias. The recipient + of such an authenticator SHOULD check the AD-LOGIN-ALIAS names, if + present, in addition to the normal client name field, against the + identity of the party with which it wishes to authenticate; either + should be allowed to match. (Note that this is not backwards + compatible with [RFC4120]; if the server side of the user-to-user + exchange does not support this extension and does not know the true + principal name, authentication may fail if the alias is sought in the + client name field.) + + The use of AD-KDC-ISSUED authorization data elements in cross-realm + cases has not been well explored at this writing; hence, we will only + specify the inclusion of this data in the one-realm case. The AD- + LOGIN-ALIAS information SHOULD be dropped in the general cross-realm + case. However, a realm MAY implement a policy of accepting and + re-signing (wrapping in a new AD-KDC-ISSUED element) alias + information provided by certain trusted realms in the cross-realm + ticket-granting service. + + The canonical principal name for an alias MUST NOT be in the form of + a ticket-granting service name, as (in a case of server name + canonicalization) that would be construed as a case of cross-realm + referral, described below. + + + + + +Hartman, et al. Standards Track [Page 8] + +RFC 6806 KDC Referrals November 2012 + + +7. Client Referrals + + The simplest form of ticket referral is for a user requesting a + ticket using an AS-REQ. In this case, the client machine will send + the AS-REQ to a convenient realm trusted to map principals, for + example, the realm of the client machine. In the case of the name + alice@EXAMPLE.COM, the client MAY optimistically choose to send the + request to EXAMPLE.COM. The realm in the AS-REQ is always the name + of the realm that the request is for, as specified in [RFC4120]. + + The KDC will try to lookup the name in its local account database. + If the account is present in the realm of the request, it SHOULD + return a KDC reply with the appropriate ticket. + + If the account is not present in the realm specified in the request + and the "canonicalize" KDC option is set, the KDC may look up the + client principal name using some kind of name service or directory + service. If this lookup is unsuccessful, it MUST return the error + KDC_ERR_C_PRINCIPAL_UNKNOWN [RFC4120]. If the lookup is successful, + it MUST return an error KDC_ERR_WRONG_REALM [RFC4120]; in the error + message, the crealm field will contain either the true realm of the + client or another realm that MAY have better information about the + client's true realm. The client MUST NOT use the cname returned in + this error message. + + If the client receives a KDC_ERR_WRONG_REALM error, it will issue a + new AS request with the same client principal name used to generate + the first AS request to the realm specified by the realm field of the + Kerberos error message corresponding to the first request. (The + client realm name will be updated in the new request to refer to this + new realm.) The client SHOULD repeat these steps until it finds the + true realm of the client. To avoid infinite referral loops, an + implementation should limit the number of referrals. A suggested + limit is 5 referrals before giving up. + + Since the same client name is sent to the referring and referred-to + realms, both realms must recognize the same client names. In + particular, the referring realm cannot (usefully) define principal + name aliases that the referred-to realm will not know. + + The true principal name of the client, returned in AS-REP, can be + validated in a subsequent TGS message exchange where its value is + communicated back to the KDC via the authenticator in the PA-TGS-REQ + padata [RFC4120]. However, this requires trusting the referred-to + realm's KDCs. Clients should limit the referral mappings they will + accept to realms trusted via some local policy. Some possible + factors that might be taken into consideration for such a policy + might include: + + + +Hartman, et al. Standards Track [Page 9] + +RFC 6806 KDC Referrals November 2012 + + + o Any realm indicated by the local KDC if the returned KRB-ERROR + message is protected by some additional means, for example, FAST + + o A list of realms configured by an administrator + + o Any realm accepted by the user when explicitly prompted + + One common approach for limiting the realms from which referrals are + accepted is to limit referrals to realms that can construct an + authentication path back to the service principal of the local + machine. This tends to work well when realms are generally within an + organization and all realms that can form an authentication path back + to the local machine have some reasonable level of mapping trust. + Deployments involving more complex trust, for example, high + probability of malicious realms, are likely to need more complex + policy and MAY need to prompt the user before accepting some + referrals. + + There is currently no provision for changing the client name in a + client referral response. + +8. Server Referrals + + The primary difference in server referrals is that the KDC returns a + referral TGT rather than an error message as is done in the client + referrals. + + If the "canonicalize" flag in the KDC options is set and the KDC + doesn't find the principal locally, either as a regular principal or + as an alias for another local principal, the KDC MAY return a cross- + realm ticket-granting ticket to the next hop on the trust path + towards a realm that may be able to resolve the principal name. + + The client will use this referral information to request a chain of + cross-realm ticket-granting tickets until it reaches the realm of the + server, and can then expect to receive a valid service ticket. + + However, an implementation should limit the number of referrals that + it processes to avoid infinite referral loops. A suggested limit is + 5 referrals before giving up. + + The client may cache the mapping of the requested name to the name of + the next realm to use and the principal name to ask for (see + Section 10). + + + + + + + +Hartman, et al. Standards Track [Page 10] + +RFC 6806 KDC Referrals November 2012 + + + Here is an example of a client requesting a service ticket for a + service in realm DEV.EXAMPLE.COM where the client is in + ADMIN.EXAMPLE.COM. + + +NC = Canonicalize KDCOption set + C: TGS-REQ sname=http/foo.dev.example.com +NC to ADMIN.EXAMPLE.COM + S: TGS-REP sname=krbtgt/EXAMPLE.COM@ADMIN.EXAMPLE.COM + C: TGS-REQ sname=http/foo.dev.example.com +NC to EXAMPLE.COM + S: TGS-REP sname=krbtgt/DEV.EXAMPLE.COM@EXAMPLE.COM + C: TGS-REQ sname=http/foo.dev.example.com +NC to DEV.EXAMPLE.COM + S: TGS-REP sname=http/foo.dev.example.com@DEV.EXAMPLE.COM + + Note that any referral or alias processing of the server name in + user-to-user authentication should use the same data as client name + canonicalization or referral. Otherwise, the name used by one user + to log in may not be useable by another for user-to-user + authentication to the first. + +9. Cross-Realm Routing + + RFC 4120 permits a KDC to return a closer referral ticket when a + cross-realm TGT is requested. This specification extends this + behavior when the canonicalize flag is set. When this flag is set, a + KDC MAY return a TGT for a realm closer to the service for any + service as discussed in the previous section. When a client follows + such a referral, it includes the realm of the referred-to realm in + the generated request. + + When the canonicalize flag is not set, the rules defined in RFC 4120 + apply. + +10. Caching Information + + It is possible that the client may wish to get additional credentials + for the same service principal, perhaps with different authorization- + data restrictions or other changed attributes. The return of a + server referral from a KDC can be taken as an indication that the + requested principal does not currently exist in the local realm. + Clearly, it would reduce network traffic if the clients could cache + that information and use it when acquiring the second set of + credentials for a service, rather than always having to recheck with + the local KDC to see if the name has been created locally. + + When the TGT expires, the previously returned referral from the local + KDC should be considered invalid, and the local KDC must be asked + again for information for the desired service principal name. (Note + that the client may get back multiple referral TGTs from the local + KDC to the same remote realm, with different lifetimes. The lifetime + + + +Hartman, et al. Standards Track [Page 11] + +RFC 6806 KDC Referrals November 2012 + + + information SHOULD be properly associated with the requested service + principal names. Simply having another TGT for the same remote realm + does not extend the validity of previously acquired information about + one service principal name.) + + Accordingly, KDC authors and maintainers should consider what factors + (e.g., DNS alias lifetimes) they may or may not wish to incorporate + into credential expiration times in cases of referrals. + +11. Negotiation of FAST and Detecting Modified Requests + + Implementations of this specification MUST support the FAST + negotiation mechanism described in this section. This mechanism + provides detection of KDC requests modified by an attacker when those + requests result in a reply instead of an error. In addition, this + mechanism provides a secure way to detect if a KDC supports FAST. + + Clients conforming to this specification MUST send new pre- + authentication data of type PA-REQ-ENC-PA-REP (149) in all AS + requests and MAY send this padata type in TGS requests. The value of + this padata item SHOULD be empty and its value MUST be ignored by a + receiving KDC. Sending this padata item indicates support for this + negotiation mechanism. KDCs conforming to this specification must + always set the ticket flag enc-pa-rep (15) in all the issued tickets. + This ticket flag indicates KDC support for the mechanism. + + The KDC response [RFC4120] is extended to support an additional field + containing encrypted pre-authentication data. + + EncKDCRepPart ::= SEQUENCE { + key [0] EncryptionKey, + last-req [1] LastReq, + nonce [2] UInt32, + key-expiration [3] KerberosTime OPTIONAL, + flags [4] TicketFlags, + authtime [5] KerberosTime, + starttime [6] KerberosTime OPTIONAL, + endtime [7] KerberosTime, + renew-till [8] KerberosTime OPTIONAL, + srealm [9] Realm, + sname [10] PrincipalName, + caddr [11] HostAddresses OPTIONAL, + encrypted-pa-data [12] SEQUENCE OF PA-DATA OPTIONAL + } + + The encrypted-pa-data element MUST be absent unless either the + "canonicalize" KDC option is set or the PA-REQ-ENC-PA-REP padata item + is sent. + + + +Hartman, et al. Standards Track [Page 12] + +RFC 6806 KDC Referrals November 2012 + + + If the PA-REQ-ENC-PA-REP padata item is sent in the request, then the + KDC MUST include a PA-REQ-ENC-PA-REP padata item in the encrypted-pa- + data item of any generated KDC reply. The PA-REQ-ENC-PA-REP pa-data + value contains the checksum computed over the type AS-REQ or TGS-REQ + in the request. The checksum key is the reply key and the checksum + type is the required checksum type for the encryption type of the + reply key, and the key usage number is KEY_USAGE_AS_REQ (56). If the + KDC supports FAST, then the KDC MUST include a padata of type PA-FX- + FAST in any encrypted-pa-data sequence it generates. The padata item + MUST be empty on sending, and the contents of the padata item MUST be + ignored on receiving. + + A client MUST reject a response for which it sent PA-REQ-ENC-PA-REP + if the ENC-PA-REP ticket flag is set and the PA-REQ-ENC-PA-REP padata + item is absent or the checksum is not successfully verified. + +12. IANA Considerations + + PA-REQ-ENC-PA-REP has been registered in the Kerveros "Pre- + authentication and Typed Data" registry + . + +13. Security Considerations + + For the AS exchange case, it is important that the logon mechanism + not trust a name that has not been used to authenticate the user. + For example, the name that the user enters as part of a logon + exchange may not be the name that the user authenticates as, given + that the KDC_ERR_WRONG_REALM error may have been returned. The + relevant Kerberos naming information for logon (if any) is the client + name and client realm in the service ticket targeted at the + workstation obtained using the user's initial TGT. That is, rather + than trusting the client name in the AS response, a workstation + SHOULD perform an AP-REQ authentication against itself as a service + and use the client name in the ticket issued for its service by the + KDC. + + How the client name and client realm are mapped into a local account + for logon is a local matter, but the client logon mechanism MUST use + additional information such as the client realm and/or authorization + attributes from the service ticket presented to the workstation by + the user when mapping the logon credentials to a local account on the + workstation. + + Not all fields in a KDC reply defined by RFC 4120 are protected. + None of the fields defined in RFC 4120 for AS request are protected, + and some information in a TGS request may not be protected. The + referrals mechanism creates several opportunities for attack because + + + +Hartman, et al. Standards Track [Page 13] + +RFC 6806 KDC Referrals November 2012 + + + of these unprotected fields. FAST [RFC6113] can be used to + completely mitigate these issues by protecting both the KDC request + and response. However, FAST requires that a client obtain an armor + ticket before authenticating. Not all realms permit all clients to + obtain armor tickets. Also, while it is expected to be uncommon, a + client might wish to use name canonicalization while obtaining an + armor ticket. The mechanism described in Section 11 detects + modification of the request between the KDC and client, mitigating + some attacks. + + There is a widely deployed base of implementations that use name + canonicalization or server referrals that use neither the negotiation + mechanism nor FAST. So, implementations may be faced with only the + limited protection afforded by RFC 4120, by the negotiation mechanism + discussed in this document, or by FAST. All three situations are + important to consider from a security standpoint. + + An attacker cannot mount a downgrade attack against a client. The + negotiation mechanism described in this document is securely + indicated by the presence of a ticket flag. So, a client will detect + if the facility was available but not used. It is possible for an + attacker to strip the indication that a client supports the + negotiation facility. The client will learn from the response that + this happened, but the KDC will not learn that the client is + attacked. So, for a single round-trip Kerberos exchange, the KDC may + believe the exchange was successful when the client detects an + attack. Packet loss or client failure can produce a similar result; + this is not a significant vulnerability. The negotiation facility + described in this document securely indicates the presence of FAST. + So, if a client wishes to use FAST when it is available, an attacker + cannot force the client to downgrade away from FAST. An attacker MAY + be able to prevent a client from obtaining an armor ticket, for + example, by responding to a request for anonymous Public Key + Cryptography for Initial Authentication in Kerberos (PKINIT) with an + error response. + + If FAST is used, then the communications between the client and KDC + are protected. However, name canonicalization places a new + responsibility for mapping principals onto the KDC. This can + increase the number of KDCs involved in an authentication, which adds + additional trusted third parties to the exchange. + + If only the negotiation mechanism is used, then the request from the + client to the KDC is protected, but not all of the response is + protected. In particular, the client name is not protected; the + ticket is also not protected. An attacker can potentially modify + these fields. Modification of the client name will result in a + denial of service. When the client attempts to authenticate to a + + + +Hartman, et al. Standards Track [Page 14] + +RFC 6806 KDC Referrals November 2012 + + + service (including the TGS), it constructs an AP-REQ message. This + message includes a client name that MUST match the client name in the + ticket according to RFC 4120. Thus, if the client name is changed, + the resulting ticket will fail when used. This is undesirable + because the authentication is separated from the later failure, which + may confuse problem determination. If the ticket is replaced with + another ticket, then later authentication to a service will fail + because the client will not know the session key for the other + ticket. If the ticket is simply modified, then authentication to a + service will fail as with RFC 4120. More significant attacks are + possible if a KDC violates the requirements of RFC 4120 and issues + two tickets with the same session key, or if a service violates the + requirements of RFC 4120 and does not check the client name against + that in the ticket. + + There is an additional attack possible when FAST is not used against + KDC_ERR_WRONG_REALM. Since this is an error response, not an AS + response, it is not protected by the negotiation mechanism. Thus, an + attacker may be able to convince a client to authenticate to a realm + other than the one intended. If an attacker is off-path, this may + give the attacker an advantage in attacking the client's credentials. + Also, see the discussion of shared passwords below. + + More serious attacks are possible if no protection beyond RFC 4120 is + used. In this case, neither the client name nor the service name is + protected between the client and KDC. In the general case, if an + attacker changes the client name, then authentication will fail + because the client will not have the right credentials (password, + certificate, or other) to authenticate as the user selected by the + attacker. However, see the discussion of shared passwords below. + Changing the server name can be a very significant attack. For + example, if a user is authenticating in order to send some + confidential information, then the attacker could gain this + information by directing the user to a server under the attacker's + control. The server name in the response is protected by RFC 4120, + but not the one in the request. Fortunately, users are typically + authenticating to the "krbtgt" service in an AS exchange. Clients + that permit changes to the server name when no protection beyond RFC + 4120 is in use SHOULD carefully restrict what service names are + acceptable. One critical case to consider is the password-changing + service. When a user authenticates to change their password, they + use an AS authentication directly to the password-changing service. + Clients MUST restrict service name changes sufficiently that the + client ends up talking to the correct password-changing service. + + + + + + + +Hartman, et al. Standards Track [Page 15] + +RFC 6806 KDC Referrals November 2012 + + +13.1. Shared-Password Case + + A special case to examine is when the user is known (or correctly + suspected) to use the same password for multiple accounts. A man-in- + the-middle attacker can either alter the request on its way to the + KDC, changing the client principal name, or reply to the client with + a response previously sent by the KDC in response to a request from + the attacker. The response received by the client can then be + decrypted by the user, though if the default "salt" generated from + the principal name is used to produce the user's key, a PA-ETYPE-INFO + or PA-ETYPE-INFO2 preauth record may need to be added or altered by + the attacker to cause the client software to generate the key needed + for the message it will receive. None of this requires the attacker + to know the user's password, and without further checking, this could + cause the user to unknowingly use the wrong credentials. + + In normal operation as described in [RFC4120], a generated AP-REQ + message includes in the Authenticator field a copy of the client's + idea of its own principal name. If this differs from the name in the + KDC-generated ticket, the application server will reject the message. + + With client name canonicalization as described in this document, the + client may get its principal name from the response from the KDC. + Using the wrong credentials may provide an advantage to an attacker. + For example, if a client uses one principal for administrative + operations and one for less privileged operation, an attacker may + coerce a client into using the wrong privilege to either cause some + later operation to succeed or fail. + +13.2. Pre-Authentication Data + + In cases of credential renewal, forwarding, or validation, if + credentials are sent to the KDC that are not an initial ticket- + granting ticket for the client's home realm, the encryption key used + to protect the TGS exchange is one known to a third party (namely, + the service for which the credential was issued). Consequently, in + such an exchange, the protection described earlier may be compromised + by the service. This is not generally believed to be a problem. If + it is, some form of explicit TGS armor could be added to FAST. + + + + + + + + + + + + +Hartman, et al. Standards Track [Page 16] + +RFC 6806 KDC Referrals November 2012 + + +14. Acknowledgments + + John Brezak, Mike Swift, and Jonathan Trostle wrote the initial + version of this document. + + Karthik Jaganathan contributed to earlier versions. + + Sam Hartman's work on this document was funded by the MIT Kerberos + Consortium. + +15. References + +15.1. Normative References + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC4120] Neuman, C., Yu, T., Hartman, S., and K. Raeburn, "The + Kerberos Network Authentication Service (V5)", RFC 4120, + July 2005. + + [RFC6113] Hartman, S. and L. Zhu, "A Generalized Framework for + Kerberos Pre-Authentication", RFC 6113, April 2011. + +15.2. Informative References + + [RFC4556] Zhu, L. and B. Tung, "Public Key Cryptography for Initial + Authentication in Kerberos (PKINIT)", RFC 4556, June 2006. + + [RFC5280] Cooper, D., Santesson, S., Farrell, S., Boeyen, S., + Housley, R., and W. Polk, "Internet X.509 Public Key + Infrastructure Certificate and Certificate Revocation List + (CRL) Profile", RFC 5280, May 2008. + + [RFC5322] Resnick, P., Ed., "Internet Message Format", RFC 5322, + October 2008. + + [XPR] Trostle, J., Kosinovsky, I., and M. Swift, "Implementation + of Crossrealm Referral Handling in the MIT Kerberos + Client", Network and Distributed System Security + Symposium, February 2001. + + + + + + + + + + +Hartman, et al. Standards Track [Page 17] + +RFC 6806 KDC Referrals November 2012 + + +Appendix A. Compatibility with Earlier Implementations of Name + Canonicalization + + The Microsoft Windows 2000 and Windows 2003 releases included an + earlier form of name-canonicalization [XPR]. Here are the + differences: + + 1) Windows include an additional encrypted padata element. The + preauth data type definition in the encrypted preauth data is as + follows: + + + PA-SVR-REFERRAL-INFO 20 + + PA-SVR-REFERRAL-DATA ::= SEQUENCE { + referred-name [1] PrincipalName OPTIONAL, + referred-realm [0] Realm + }} + + The referred-principal is never sent. The referred-realm is + included in TGS replies and includes the realm name of the + realm to which the client is referred. This information is + redundant with the realm in the second component of the + returned TGT. + + 2) When PKINIT [RFC4556] is used, the NT-ENTERPRISE client name is + encoded as a Subject Alternative Name (SAN) extension [RFC5280] in + the client's X.509 certificate. The type of the otherName field + for this SAN extension is AnotherName [RFC5280]. The type-id + field of the type AnotherName is id-ms-sc-logon-upn + (1.3.6.1.4.1.311.20.2.3), and the value field of the type + AnotherName is a KerberosString [RFC4120]. The value of this + KerberosString type is the single component in the name-string + [RFC4120] sequence for the corresponding NT-ENTERPRISE name type. + + In Microsoft's current implementation through the use of global + catalogs, any domain in one forest is reachable from any other domain + in the same forest or another trusted forest with 3 or less + referrals. A forest is a collection of realms with hierarchical + trust relationships: there can be multiple trust trees in a forest; + each child and parent realm pair and each root realm pair have + bidirectional transitive direct trust between them. + + While we might want to permit multiple aliases to exist and even be + reported in AD-LOGIN-ALIAS, the Microsoft implementation permits only + one NT-ENTERPRISE alias to exist, so this question had not previously + arisen. + + + + +Hartman, et al. Standards Track [Page 18] + +RFC 6806 KDC Referrals November 2012 + + +Authors' Addresses + + Sam Hartman (editor) + Painless Security + + EMail: hartmans-ietf@mit.edu + + + Kenneth Raeburn + Massachusetts Institute of Technology + + EMail: raeburn@mit.edu + + + Larry Zhu + Microsoft Corporation + One Microsoft Way + Redmond, WA 98052 + US + + EMail: lzhu@microsoft.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Hartman, et al. Standards Track [Page 19] + diff --git a/doc/vars.tin b/doc/vars.tin index d3e67b7d4..0907397db 100644 --- a/doc/vars.tin +++ b/doc/vars.tin @@ -4,4 +4,5 @@ @c @set dbdir @dbdir@ +@set dbtype @dbtype@ @set PACKAGE_VERSION @PACKAGE_VERSION@ diff --git a/doc/whatis.texi b/doc/whatis.texi index 8c1f45ddb..8c7770b81 100644 --- a/doc/whatis.texi +++ b/doc/whatis.texi @@ -1,6 +1,6 @@ @c $Id$ -@node What is Kerberos?, Building and Installing, Introduction, Top +@node What is Kerberos?, What is PKIX?, Introduction, Top @chapter What is Kerberos? @quotation @@ -35,26 +35,29 @@ services can authenticate each other. @end macro @end ifinfo -@tex -@def@xsub#1{$_{#1}$} -@global@let@sub=@xsub -@end tex - @ifhtml @macro sub{arg} + @html \arg\ @end html + @end macro @end ifhtml -@c ifdocbook -@c macro sub{arg} -@c docbook -@c \arg\ -@c end docbook -@c end macro -@c end ifdocbook +@ifdocbook +@macro sub{arg} +@docbook +@\arg\ +@end docbook +@end macro +@end ifdocbook + +@c @iftex +@c @macro sub{arg} +@c @textsubscript{\arg\} +@c @end macro +@c @end iftex @quotation @strong{Note} This discussion is about Kerberos version 4, but version @@ -130,8 +133,10 @@ It would be possible to add a @dfn{replay cache} to the server side. The idea is to save the authenticators sent during the last few minutes, so that @var{B} can detect when someone is trying to retransmit an already used message. This is somewhat impractical -(mostly regarding efficiency), and is not part of Kerberos 4; MIT -Kerberos 5 contains it. +(mostly regarding performance); MIT Kerberos 5 has a replay cache, +while Heimdal does not. + +However, most GSS-API applicatons do not need a replay cache at all. To authenticate @var{B}, @var{A} might request that @var{B} sends something back that proves that @var{B} has access to the session @@ -159,3 +164,53 @@ from 1988. These documents can be found on our web-page at @url{http://www.pdc.kth.se/kth-krb/}. + +@node What is PKIX?, What is a Certification Authority (CA)?, What is Kerberos?, Top +@chapter What is PKIX? + +PKIX is the set of Internet standards for Public Key Infrastructure (PKI), +based on the ITU-T's x.509 standads. PKI is an authentication mechanism based +on public keys (the 'PK' in 'PKI'). + +In PKIX we have public keys "certified" by certification authorities (CAs). A +"relying party" is software that validates an entity's certificate and, if +valid, trusts the certified public key to "speak for" the entity identified by +the certificate. + +In a PKI every entity has one (or more) certified public/private key pairs. + +@node What is a Certification Authority (CA)?, What is kx509?, What is PKIX?, Top +@chapter What is a Certification Authority (CA)? + +A Certification Authority (CA) is an entity in a PKI that issues certificates +to other entities -- a CA certifies that a public key speaks for a particular, +named entity. + +There are two types of CAs: off-line and online. Typically PKI hierarchies are +organized such that the most security-critical private keys are only used by +off-line CAs to certify the less security-critical public keys of online CAs. + +Heimdal has support for off-line CAs using its Hx509 library and hxtool +command. + +Heimdal also has an online CA with a RESTful, HTTPS-based protocol. + +@node What is kx509?, What is bx509?, What is a Certification Authority (CA)?, Top +@chapter What is kx509? + +kx509 is a kerberized certification authority (CA). Heimdal implements this +protocol in its KDC. The protocol is specified by RFC 6717, though Heimdal has +implemented a number of extensions as well. A client is implemented by the +heimtools command's kx509 sub-command. + +@node What is bx509?, Building and Installing, What is kx509?, Top +@chapter What is kx509? + +bx509 is an online CA, like kx509, but the protocol is based on HTTPS. + +Heimdal's bx509d implementation of bx509 implements two authentication bridges: +a "/bx509" end-point that allows clients to trade bearer tokens (including +Negotiate/Kerberos) and CSRs for certificates, and a "/bnegotiate" end-point +allowing clients to trade bearer tokens (including Negotiate/Kerberos) for +Negotiate tokens to HTTP servers. diff --git a/doc/win2k.texi b/doc/win2k.texi index 6175a3c61..d4ab2fecd 100644 --- a/doc/win2k.texi +++ b/doc/win2k.texi @@ -1,41 +1,36 @@ @c $Id$ -@node Windows 2000 compatability, Programming with Kerberos, Kerberos 4 issues, Top + +@node Windows compatibility, Programming with Kerberos, Things in search for a better place, Top @comment node-name, next, previous, up -@chapter Windows 2000 compatability +@chapter Windows compatibility -Windows 2000 (formerly known as Windows NT 5) from Microsoft implements -Kerberos 5. Their implementation, however, has some quirks, -peculiarities, and bugs. This chapter is a short summary of the things -that we have found out while trying to test Heimdal against Windows -2000. Another big problem with the Kerberos implementation in Windows -2000 is that the available documentation is more focused on getting +Microsoft Windows, starting from version 2000 (formerly known as Windows NT 5), implements Kerberos 5. Their implementation, however, has some quirks, +peculiarities, and bugs. This chapter is a short summary of the compatibility +issues between Heimdal and various Windows versions. + +The big problem with the Kerberos implementation in Windows +is that the available documentation is more focused on getting things to work rather than how they work, and not that useful in figuring -out how things really work. - -This information should apply to Heimdal @value{VERSION} and Windows -2000 Professional. It's of course subject to change all the time and +out how things really work. It's of course subject to change all the time and mostly consists of our not so inspired guesses. Hopefully it's still somewhat useful. @menu -* Configuring Windows 2000 to use a Heimdal KDC:: -* Inter-Realm keys (trust) between Windows 2000 and a Heimdal KDC:: +* Configuring Windows to use a Heimdal KDC:: +* Inter-Realm keys (trust) between Windows and a Heimdal KDC:: * Create account mappings:: * Encryption types:: * Authorisation data:: * Quirks of Windows 2000 KDC:: -* Useful links when reading about the Windows 2000:: +* Useful links when reading about the Windows:: @end menu -@node Configuring Windows 2000 to use a Heimdal KDC, Inter-Realm keys (trust) between Windows 2000 and a Heimdal KDC, Windows 2000 compatability, Windows 2000 compatability +@node Configuring Windows to use a Heimdal KDC, Inter-Realm keys (trust) between Windows and a Heimdal KDC, Windows compatibility, Windows compatibility @comment node-name, next, precious, up -@section Configuring Windows 2000 to use a Heimdal KDC +@section Configuring Windows to use a Heimdal KDC -You need the command line program called @command{ksetup.exe} which is available -in the file @file{SUPPORT/TOOLS/SUPPORT.CAB} on the Windows 2000 Professional -CD-ROM. This program is used to configure the Kerberos settings on a -Workstation. +You need the command line program called @command{ksetup.exe}. This program comes with the Windows Support Tools, available from either the installation CD-ROM (@file{SUPPORT/TOOLS/SUPPORT.CAB}), or from Microsoft web site. Starting from Windows 2008, it is already installed. This program is used to configure the Kerberos settings on a Workstation. @command{Ksetup} store the domain information under the registry key: @code{HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\LSA\Kerberos\Domains}. @@ -88,13 +83,13 @@ The Windows machine will now map any user to the corresponding principal, for example @samp{nisse} to the principal @samp{nisse@@MY.REALM}. (This is most likely what you want.) -@node Inter-Realm keys (trust) between Windows 2000 and a Heimdal KDC, Create account mappings, Configuring Windows 2000 to use a Heimdal KDC, Windows 2000 compatability +@node Inter-Realm keys (trust) between Windows and a Heimdal KDC, Create account mappings, Configuring Windows to use a Heimdal KDC, Windows compatibility @comment node-name, next, precious, up -@section Inter-Realm keys (trust) between Windows 2000 and a Heimdal KDC +@section Inter-Realm keys (trust) between Windows and a Heimdal KDC See also the Step-by-Step guide from Microsoft, referenced below. -Install Windows 2000, and create a new controller (Active Directory +Install Windows, and create a new controller (Active Directory Server) for the domain. By default the trust will be non-transitive. This means that only users @@ -102,8 +97,8 @@ directly from the trusted domain may authenticate. This can be changed to transitive by using the @command{netdom.exe} tool. @command{netdom.exe} can also be used to add the trust between two realms. -You need to tell Windows 2000 on what hosts to find the KDCs for the -non-Windows realm with @command{ksetup}, see @xref{Configuring Windows 2000 +You need to tell Windows on what hosts to find the KDCs for the +non-Windows realm with @command{ksetup}, see @xref{Configuring Windows to use a Heimdal KDC}. This needs to be done on all computers that want enable cross-realm @@ -127,33 +122,36 @@ Management tool, you do it like this: netdom trust NT.REALM.EXAMPLE.COM /Domain:EXAMPLE.COM /add /realm /passwordt:TrustPassword @end example -You also need to add the inter-realm keys to the Heimdal KDC. Make sure -you have matching encryption types (DES, Arcfour and AES in case of Longhorn) +You also need to add the inter-realm keys to the Heimdal KDC. But take +care to the encryption types and salting used for those keys. There should be +no encryption type stronger than the one configured on Windows side for this +relationship, itself limited to the ones supported by this specific version of +Windows. Otherwise, the trust will not works. -Another issue is salting. Since Windows 2000 does not seem to -understand Kerberos 4 salted hashes you might need to turn off anything -similar to the following if you have it, at least while adding the -principals that are going to share keys with Windows 2000. +Here are the version-specific needed information: +@enumerate +@item Windows 2000: maximum encryption type is DES +@item Windows 2003: maximum encryption type is DES +@item Windows 2003RC2: maximum encryption type is RC4, relationship defaults to DES +@item Windows 2008: maximum encryption type is AES, relationship defaults to RC4 +@end enumerate + +For Windows 2003RC2, to change the trust encryption type, you have to use the +@command{ktpass}, from the Windows 2003 Resource kit *service pack2*, available +from Microsoft web site. @example -[kadmin] - default_keys = v5 v4 +C:> ktpass /MITRealmName UNIX.EXAMPLE.COM /TrustEncryp RC4 @end example -So remove v4 from default keys. - -What you probably want to use is this: +For Windows 2008, the same operation can be done with the @command{ksetup}, installed by default. @example -[kadmin] - default_keys = des-cbc-crc:pw-salt arcfour-hmac-md5:pw-salt +C:> ksetup /SetEncTypeAttre EXAMPLE.COM AES256-SHA1 @end example -@c XXX check this -@c It is definitely not supported in base 2003. I haven't been able to -@c get SP1 installed here, but it is supposed to work in that. - -Once that is also done, you can add the required inter-realm keys: +Once the relationship is correctly configured, you can add the required +inter-realm keys, using heimdal default encryption types: @example kadmin add krbtgt/NT.REALM.EXAMPLE.COM@@EXAMPLE.COM @@ -162,11 +160,20 @@ kadmin add krbtgt/REALM.EXAMPLE.COM@@NT.EXAMPLE.COM Use the same passwords for both keys. +And if needed, to remove unsupported encryptions, such as the following ones for a Windows 2003RC2 server. + +@example +kadmin del_enctype krbtgt/REALM.EXAMPLE.COM@@NT.EXAMPLE.COM aes256-cts-hmac-sha1-96 +kadmin del_enctype krbtgt/REALM.EXAMPLE.COM@@NT.EXAMPLE.COM des3-cbc-sha1 +kadmin del_enctype krbtgt/NT.EXAMPLE.COM@@EXAMPLE.COM aes256-cts-hmac-sha1-96 +kadmin del_enctype krbtgt/NT.EXAMPLE.COM@@EXAMPLE.COM des3-cbc-sha1 +@end example + Do not forget to reboot before trying the new realm-trust (after running @command{ksetup}). It looks like it might work, but packets are never sent to the non-Windows KDC. -@node Create account mappings, Encryption types, Inter-Realm keys (trust) between Windows 2000 and a Heimdal KDC, Windows 2000 compatability +@node Create account mappings, Encryption types, Inter-Realm keys (trust) between Windows and a Heimdal KDC, Windows compatibility @comment node-name, next, precious, up @section Create account mappings @@ -183,7 +190,7 @@ This adds @samp{authorizationNames} entry to the users LDAP entry to the Active Directory LDAP catalog. When you create users by script you can add this entry instead. -@node Encryption types, Authorisation data, Create account mappings, Windows 2000 compatability +@node Encryption types, Authorisation data, Create account mappings, Windows compatibility @comment node-name, next, previous, up @section Encryption types @@ -195,7 +202,7 @@ MD4 and DES keys. Users that are converted from a NT4 database, will only have MD4 passwords and will need a password change to get a DES key. -@node Authorisation data, Quirks of Windows 2000 KDC, Encryption types, Windows 2000 compatability +@node Authorisation data, Quirks of Windows 2000 KDC, Encryption types, Windows compatibility @comment node-name, next, previous, up @section Authorisation data @@ -223,15 +230,15 @@ the file. analysing the data. @end enumerate -@node Quirks of Windows 2000 KDC, Useful links when reading about the Windows 2000, Authorisation data, Windows 2000 compatability +@node Quirks of Windows 2000 KDC, Useful links when reading about the Windows, Authorisation data, Windows compatibility @comment node-name, next, previous, up @section Quirks of Windows 2000 KDC -There are some issues with salts and Windows 2000. Using an empty salt---which is the only one that Kerberos 4 supported, and is therefore known -as a Kerberos 4 compatible salt---does not work, as far as we can tell -from out experiments and users' reports. Therefore, you have to make -sure you keep around keys with all the different types of salts that are -required. Microsoft have fixed this issue post Windows 2003. +There are some issues with salts and Windows 2000. Using an empty salt does +not work, as far as we can tell from out experiments and users' reports. +Therefore, you have to make sure you keep around keys with all the different +types of salts that are required. Microsoft have fixed this issue post Windows +2003. Microsoft seems also to have forgotten to implement the checksum algorithms @samp{rsa-md4-des} and @samp{rsa-md5-des}. This can make Name @@ -255,9 +262,9 @@ You should also add the following entries to the @file{krb5.conf} file: These configuration options will make sure that no checksums of the unsupported types are generated. -@node Useful links when reading about the Windows 2000, , Quirks of Windows 2000 KDC, Windows 2000 compatability +@node Useful links when reading about the Windows, , Quirks of Windows 2000 KDC, Windows compatibility @comment node-name, next, previous, up -@section Useful links when reading about the Windows 2000 +@section Useful links when reading about the Windows See also our paper presented at the 2001 Usenix Annual Technical Conference, available in the proceedings or at @@ -272,7 +279,7 @@ short list of the interesting documents that we have managed to find. @uref{http://www.microsoft.com/technet/prodtechnol/windows2000serv/howto/kerbstep.mspx}. Kerberos GSS-API (in Windows-eze SSPI), Windows as a client in a non-Windows KDC realm, adding unix clients to a Windows 2000 KDC, and -adding cross-realm trust (@pxref{Inter-Realm keys (trust) between Windows 2000 +adding cross-realm trust (@pxref{Inter-Realm keys (trust) between Windows and a Heimdal KDC}). @item Windows 2000 Kerberos Authentication: @@ -303,4 +310,5 @@ Other useful programs include these: @itemize @bullet @item pwdump2 -@uref{http://www.bindview.com/Support/RAZOR/Utilities/Windows/pwdump2_readme.cfm}@end itemize +@uref{http://www.bindview.com/Support/RAZOR/Utilities/Windows/pwdump2_readme.cfm} +@end itemize diff --git a/doc/wind.din b/doc/wind.din index a35bd45fe..da36dd1b7 100644 --- a/doc/wind.din +++ b/doc/wind.din @@ -2,7 +2,7 @@ PROJECT_NAME = Heimdal wind library PROJECT_NUMBER = @PACKAGE_VERSION@ -OUTPUT_DIRECTORY = @srcdir@/wind +OUTPUT_DIRECTORY = @srcdir@/doxyout/wind INPUT = @srcdir@/../lib/wind WARN_IF_UNDOCUMENTED = YES diff --git a/etc/Makefile.am b/etc/Makefile.am index a25d86553..6736bbc8f 100644 --- a/etc/Makefile.am +++ b/etc/Makefile.am @@ -2,4 +2,4 @@ include $(top_srcdir)/Makefile.am.common -EXTRA_DIST = services.append +EXTRA_DIST = NTMakefile services.append diff --git a/etc/NTMakefile b/etc/NTMakefile new file mode 100644 index 000000000..aab3f7a17 --- /dev/null +++ b/etc/NTMakefile @@ -0,0 +1,35 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=etc + +!include ../windows/NTMakefile.w32 + diff --git a/include/Makefile.am b/include/Makefile.am index ea01311bf..43ebe7069 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -4,50 +4,83 @@ include $(top_srcdir)/Makefile.am.common SUBDIRS = kadm5 hcrypto gssapi -noinst_PROGRAMS = bits make_crypto +noinst_PROGRAMS = bits CHECK_LOCAL = no-check-local AM_CPPFLAGS += -DHOST=\"$(CANONICAL_HOST)\" nodist_include_HEADERS = krb5-types.h -nodist_noinst_HEADERS = crypto-headers.h + +noinst_HEADERS = heimqueue.h heim_threads.h crypto-headers.h + +EXTRA_DIST = NTMakefile krb5-types.cross config.h.w32 + +if !CROSS_COMPILE krb5-types.h: bits$(EXEEXT) ./bits$(EXEEXT) krb5-types.h -crypto-headers.h: make_crypto$(EXEEXT) - ./make_crypto$(EXEEXT) crypto-headers.h +else + +krb5-types.h: krb5-types.cross + cp $(srcdir)/krb5-types.cross krb5-types.h + +endif CLEANFILES = \ + an2ln_plugin.h \ + asn1-common.h \ + asn1-template.h \ asn1.h \ asn1_err.h \ base64.h \ + ccache_plugin.h \ cms_asn1.h \ + cms_template_asn1.h \ com_err.h \ com_right.h \ - crypto-headers.h \ + common_plugin.h \ + crmf_asn1.h \ + crmf_template_asn1.h \ + db_plugin.h \ + der-private.h \ der-protos.h \ der.h \ digest_asn1.h \ + digest_template_asn1.h \ editline.h \ err.h \ getarg.h \ glob.h \ + gss-preauth-protos.h \ + gss-preauth-private.h \ gssapi.h \ + gssapi_asn1.h \ + gssapi_mech.h \ + gssapi/gssapi_preauth.h \ + hdb-private.h \ hdb-protos.h \ hdb.h \ hdb_asn1.h \ hdb_err.h \ + heim-ipc.h \ heim_asn1.h \ heim_err.h \ + heimbase.h \ + heimbase-svc.h \ + heimbase-protos.h \ heimntlm-protos.h \ heimntlm.h \ hex.h \ + hx509-private.h \ hx509-protos.h \ hx509.h \ hx509_err.h \ k524_err.h \ + k5e1_err.h \ kafs.h \ + kcm-protos.h \ + kdc-private.h \ kdc-protos.h \ kdc.h \ krb5-private.h \ @@ -55,34 +88,60 @@ CLEANFILES = \ krb5-types.h \ krb5.h \ krb5_asn1.h \ + krb5_template_asn1.h \ krb5_ccapi.h \ krb5_err.h \ krb_err.h \ + kuserok_plugin.h \ kx509_asn1.h \ + kx509_template_asn1.h \ kx509_err.h \ locate_plugin.h \ + login-protos.h \ + ntlm_err.h \ + ocsp_asn1.h \ + ocsp_template_asn1.h \ otp.h \ parse_bytes.h \ parse_time.h \ parse_units.h \ + pkcs10_asn1.h \ + pkcs10_template_asn1.h \ pkcs12_asn1.h \ + pkcs12_template_asn1.h \ pkcs8_asn1.h \ + pkcs8_template_asn1.h \ pkcs9_asn1.h \ + pkcs9_template_asn1.h \ pkinit_asn1.h \ + pkinit_template_asn1.h \ resolve.h \ rfc2459_asn1.h \ + rfc2459_template_asn1.h \ + rfc4108_asn1.h \ + rfc4108_template_asn1.h \ roken-common.h \ roken.h \ rtbl.h \ - sl.h \ send_to_kdc_plugin.h \ + sl.h \ + sqlite3.h \ + sqlite3ext.h \ test-mem.h \ vers.h \ vis.h \ wind.h \ wind_err.h \ - windc_plugin.h \ - xdbm.h + kdc-plugin.h \ + kdc-accessors.h \ + kdc-audit.h \ + csr_authorizer_plugin.h \ + gss_preauth_authorizer_plugin.h \ + token_validator_plugin.h \ + xdbm.h \ + x25519_ref10.h \ + x690sample_asn1.h \ + x690sample_template_asn1.h DISTCLEANFILES = \ version.h \ diff --git a/include/NTMakefile b/include/NTMakefile new file mode 100644 index 000000000..8308d6e37 --- /dev/null +++ b/include/NTMakefile @@ -0,0 +1,122 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=include + +SUBDIRS=kadm5 hcrypto gssapi + +!include ../windows/NTMakefile.w32 +!include ../windows/NTMakefile.version +!include ../windows/NTMakefile.config + +INCFILES= \ + $(INCDIR)\config.h \ + $(INCDIR)\crypto-headers.h \ + $(INCDIR)\heimqueue.h \ + $(INCDIR)\heim_threads.h \ + $(INCDIR)\krb5-types.h \ + $(INCDIR)\version.h + +$(INCDIR)\krb5-types.h: $(OBJ)\bits.exe + $(OBJ)\bits.exe $(INCDIR)\krb5-types.h + +$(OBJ)\bits.exe: $(OBJ)\bits.obj + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(INCDIR)\config.h: config.h.w32 ..\windows\NTMakefile.config ..\windows\NTMakefile.version NTMakefile + $(PERL) << < config.h.w32 > $@ + +while(<>) { + + if (m/\@FEATURE_DEFS\@/) { + + if ("$(KRB5)") { print "#define KRB5 1\n"; } + if ("$(KRB4)") { print "#define KRB4 1\n"; } + if ("$(WEAK_CRYPTO)") { print "#define HEIM_WEAK_CRYPTO 1\n"; } + if ("$(HCRYPTO_FALLBACK)") { print "#define HCRYPTO_FALLBACK 1\n"; } else { print "#define HCRYPTO_FALLBACK 0\n"; } + if ("$(PKINIT)") { print "#define PKINIT 1\n"; } + if ("$(NO_AFS)") { print "#define NO_AFS 1\n"; } + if ("$(OPENLDAP)") { print "#define OPENLDAP 1\n"; } + if ("$(OPENLDAP_MODULE)") { print "#define OPENLDAP_MODULE 1\n"; } + if ("$(OTP)") { print "#define OTP 1 \n"; } + if ("$(AUTHENTICATION)") { print "#define AUTHENTICATION 1\n"; } + if ("$(DIAGNOSTICS)") { print "#define DIAGNOSTICS 1\n"; } + if ("$(ENCRYPTION)") { print "#define ENCRYPTION 1\n"; } + if ("$(ENABLE_AFS_STRING_TO_KEY)") { print "#define ENABLE_AFS_STRING_TO_KEY 1\n"; } + if ("$(ENABLE_PTHREAD_SUPPORT)") { print "#define ENABLE_PTHREAD_SUPPORT 1\n"; } + if ("$(HAVE_PTHREAD_H)") { print "#define HAVE_PTHREAD_H 1\n"; } + if ("$(ENV_HACK)") { print "#define ENV_HACK 1\n"; } + if ("$(HAVE_KCM)") { print "#define HAVE_KCM 1\n"; } + if ("$(HAVE_SCC)") { print "#define HAVE_SCC 1\n"; } + if ("$(HAVE_STDINT_H)") { print "#define HAVE_STDINT_H 1\n"; } + if ("$(DIR_hdbdir)") { print "#define HDB_DB_DIR \"".'$(DIR_hdbdir)'."\"\n"; } + if ("$(HAVE_MSLSA_CACHE)") { print "#define HAVE_MSLSA_CACHE 1\n"; } + if ("$(NO_LOCALNAME)") { print "#define NO_LOCALNAME 1\n"; } + + } elsif (m/\@VERSION_OPTDEFS\@/) { + + if ("$(VER_PRERELEASE)") { print "#define VER_PRERELEASE 1\n"; } + if ("$(VER_PRIVATE)") { print "#define VER_PRIVATE \"$(VER_PRIVATE)\"\n"; } + if ("$(VER_SPECIAL)") { print "#define VER_SPECIAL \"$(VER_SPECIAL)\"\n"; } + if ("$(BUILD)" eq "dbg") { print "#define VER_DEBUG 1\n"; } + print "#define HOST \"$(COMPUTERNAME)\"\n"; + + } else { + + s/\@PACKAGE\@/$(VER_PACKAGE)/; + s/\@PACKAGE_NAME\@/$(VER_PACKAGE_NAME)/; + s{\@PACKAGE_BUGREPORT\@}{$(VER_PACKAGE_BUGREPORT:@=\@)}; + s/\@PACKAGE_VERSION\@/$(VER_PACKAGE_VERSION)/; + s/\@PACKAGE_COPYRIGHT\@/$(VER_PACKAGE_COPYRIGHT)/; + s/\@PACKAGE_COMPANY\@/$(VER_PACKAGE_COMPANY)/; + s/\@MAJOR\@/$(VER_PRODUCT_MAJOR)/; + s/\@MINOR\@/$(VER_PRODUCT_MINOR)/; + s/\@AUX\@/$(VER_PRODUCT_AUX)/; + s/\@PATCH\@/$(VER_PRODUCT_PATCH)/; + + print $_; + } +} + +<< + +$(INCDIR)\version.h: ..\windows\NTMakefile.version NTMakefile + $(CP) << $@ +const char *const heimdal_long_version = "@(#)$$Version: $(VER_PACKAGE_NAME) $(VER_PACKAGE_VERSION) by $(USERNAME) on $(COMPUTERNAME) ($(CPU)-pc-windows) $$"; +const char *const heimdal_version = "$(VER_PACKAGE_NAME) $(VER_PACKAGE_VERSION)"; +<< + +all:: $(INCFILES) + +clean:: + -$(RM) $(INCFILES) + diff --git a/include/bits.c b/include/bits.c index 1070428c5..6abdb15c9 100644 --- a/include/bits.c +++ b/include/bits.c @@ -3,6 +3,8 @@ * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -39,36 +41,59 @@ RCSID("$Id$"); #include #include #include +#ifdef WIN32 +#include +#include +#endif -#define BITSIZE(TYPE) \ -{ \ - int b = 0; TYPE x = 1, zero = 0; const char *pre = "u"; \ - char tmp[128], tmp2[128]; \ - while(x){ x <<= 1; b++; if(x < zero) pre=""; } \ - if(b >= len){ \ - int tabs; \ - sprintf(tmp, "%sint%d_t" , pre, len); \ - sprintf(tmp2, "typedef %s %s;", #TYPE, tmp); \ - tabs = 5 - strlen(tmp2) / 8; \ - fprintf(f, "%s", tmp2); \ - while(tabs-- > 0) fprintf(f, "\t"); \ - fprintf(f, "/* %2d bits */\n", b); \ - return; \ - } \ +#ifdef HAVE_SNPRINTF +#define BITSIZE(TYPE) \ +{ \ + int b = 0; TYPE x = 1, zero = 0; const char *pre = "u"; \ + char tmp[128]; \ + while(x){ x <<= 1; b++; if(x < zero) pre=""; } \ + if(b >= len){ \ + size_t tabs; \ + snprintf(tmp, sizeof(tmp), "typedef %s %sint%d_t;", #TYPE, \ + pre, len); \ + tabs = 5 - strlen(tmp) / 8; \ + fprintf(f, "%s", tmp); \ + while(tabs-- > 0) fprintf(f, "\t"); \ + fprintf(f, "/* %2d bits */\n", b); \ + return; \ + } \ } - +#else +#define BITSIZE(TYPE) \ +{ \ + int b = 0; TYPE x = 1, zero = 0; const char *pre = "u"; \ + char tmp[128], tmp2[128]; \ + while(x){ x <<= 1; b++; if(x < zero) pre=""; } \ + if(b >= len){ \ + size_t tabs; \ + sprintf(tmp, "%sint%d_t" , pre, len); \ + sprintf(tmp2, "typedef %s %s;", #TYPE, tmp); \ + tabs = 5 - strlen(tmp2) / 8; \ + fprintf(f, "%s", tmp2); \ + while(tabs-- > 0) \ + fprintf(f, "\t"); \ + fprintf(f, "/* %2d bits */\n", b); \ + return; \ + } \ +} +#endif #ifndef HAVE___ATTRIBUTE__ #define __attribute__(x) #endif static void -try_signed(FILE *f, int len) __attribute__ ((unused)); +try_signed(FILE *f, int len) __attribute__ ((__unused__)); static void -try_unsigned(FILE *f, int len) __attribute__ ((unused)); +try_unsigned(FILE *f, int len) __attribute__ ((__unused__)); static int -print_bt(FILE *f, int flag) __attribute__ ((unused)); +print_bt(FILE *f, int flag) __attribute__ ((__unused__)); static void try_signed(FILE *f, int len) @@ -112,7 +137,8 @@ int main(int argc, char **argv) { FILE *f; int flag; - const char *fn, *hb; + char *p = NULL; + const char *hb; if (argc > 1 && strcmp(argv[1], "--version") == 0) { printf("some version"); @@ -120,14 +146,11 @@ int main(int argc, char **argv) } if(argc < 2){ - fn = "bits.h"; hb = "__BITS_H__"; f = stdout; } else { - char *p; - fn = argv[1]; - p = malloc(strlen(fn) + 5); - sprintf(p, "__%s__", fn); + p = malloc(strlen(argv[1]) + 5); + sprintf(p, "__%s__", argv[1]); hb = p; for(; *p; p++){ if(!isalnum((unsigned char)*p)) @@ -135,9 +158,6 @@ int main(int argc, char **argv) } f = fopen(argv[1], "w"); } - fprintf(f, "/* %s -- this file was generated for %s by\n", fn, HOST); - fprintf(f, " %*s %s */\n\n", (int)strlen(fn), "", - "$Id$"); fprintf(f, "#ifndef %s\n", hb); fprintf(f, "#define %s\n", hb); fprintf(f, "\n"); @@ -157,7 +177,12 @@ int main(int argc, char **argv) fprintf(f, "#include \n"); #endif #ifdef HAVE_SOCKLEN_T +#ifndef WIN32 fprintf(f, "#include \n"); +#else + fprintf(f, "#include \n"); + fprintf(f, "#include \n"); +#endif #endif fprintf(f, "\n"); @@ -234,7 +259,68 @@ int main(int argc, char **argv) fprintf(f, "typedef int krb5_ssize_t;\n"); #endif fprintf(f, "\n"); + +#if defined(_WIN32) + fprintf(f, "typedef SOCKET krb5_socket_t;\n"); +#else + fprintf(f, "typedef int krb5_socket_t;\n"); +#endif + fprintf(f, "\n"); + #endif /* KRB5 */ + + fprintf(f, "#if !defined(__has_extension)\n"); + fprintf(f, "#define __has_extension(x) 0\n"); + fprintf(f, "#endif\n\n"); + + fprintf(f, "#ifndef KRB5TYPES_REQUIRE_GNUC\n"); + fprintf(f, "#define KRB5TYPES_REQUIRE_GNUC(m,n,p) \\\n"); + fprintf(f, " (((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) + __GNUC_PATCHLEVEL__) >= \\\n"); + fprintf(f, " (((m) * 10000) + ((n) * 100) + (p)))\n"); + fprintf(f, "#endif\n\n"); + + fprintf(f, "#ifndef HEIMDAL_DEPRECATED\n"); + fprintf(f, "#if __has_extension(deprecated) || KRB5TYPES_REQUIRE_GNUC(3,1,0)\n"); + fprintf(f, "#define HEIMDAL_DEPRECATED __attribute__ ((__deprecated__))\n"); + fprintf(f, "#elif defined(_MSC_VER) && (_MSC_VER>1200)\n"); + fprintf(f, "#define HEIMDAL_DEPRECATED __declspec(deprecated)\n"); + fprintf(f, "#else\n"); + fprintf(f, "#define HEIMDAL_DEPRECATED\n"); + fprintf(f, "#endif\n"); + fprintf(f, "#endif\n\n"); + + fprintf(f, "#ifndef HEIMDAL_PRINTF_ATTRIBUTE\n"); + fprintf(f, "#if __has_extension(format) || KRB5TYPES_REQUIRE_GNUC(3,1,0)\n"); + fprintf(f, "#define HEIMDAL_PRINTF_ATTRIBUTE(x) __attribute__ ((__format__ x))\n"); + fprintf(f, "#else\n"); + fprintf(f, "#define HEIMDAL_PRINTF_ATTRIBUTE(x)\n"); + fprintf(f, "#endif\n"); + fprintf(f, "#endif\n\n"); + + fprintf(f, "#ifndef HEIMDAL_NORETURN_ATTRIBUTE\n"); + fprintf(f, "#if __has_extension(noreturn) || KRB5TYPES_REQUIRE_GNUC(3,1,0)\n"); + fprintf(f, "#define HEIMDAL_NORETURN_ATTRIBUTE __attribute__ ((__noreturn__))\n"); + fprintf(f, "#else\n"); + fprintf(f, "#define HEIMDAL_NORETURN_ATTRIBUTE\n"); + fprintf(f, "#endif\n"); + fprintf(f, "#endif\n\n"); + + fprintf(f, "#ifndef HEIMDAL_UNUSED_ATTRIBUTE\n"); + fprintf(f, "#if __has_extension(unused) || KRB5TYPES_REQUIRE_GNUC(3,1,0)\n"); + fprintf(f, "#define HEIMDAL_UNUSED_ATTRIBUTE __attribute__ ((__unused__))\n"); + fprintf(f, "#else\n"); + fprintf(f, "#define HEIMDAL_UNUSED_ATTRIBUTE\n"); + fprintf(f, "#endif\n"); + fprintf(f, "#endif\n\n"); + + fprintf(f, "#ifndef HEIMDAL_WARN_UNUSED_RESULT_ATTRIBUTE\n"); + fprintf(f, "#if __has_extension(warn_unused_result) || KRB5TYPES_REQUIRE_GNUC(3,3,0)\n"); + fprintf(f, "#define HEIMDAL_WARN_UNUSED_RESULT_ATTRIBUTE __attribute__ ((__warn_unused_result__))\n"); + fprintf(f, "#else\n"); + fprintf(f, "#define HEIMDAL_WARN_UNUSED_RESULT_ATTRIBUTE\n"); + fprintf(f, "#endif\n"); + fprintf(f, "#endif\n\n"); + fprintf(f, "#endif /* %s */\n", hb); if (f != stdout) diff --git a/include/config.h.w32 b/include/config.h.w32 new file mode 100644 index 000000000..f8be38b5e --- /dev/null +++ b/include/config.h.w32 @@ -0,0 +1,1498 @@ +/*********************************************************************** + * Copyright (c) 2009-2017, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + +#define HEIM_FALLTHROUGH do {} while(0) /* fallthrough */ + +#ifndef RCSID +#define RCSID(msg) \ +static const char *const rcsid[] = { (const char *)rcsid, "@(#)" msg } +#endif + +/* If this file is being included by a resource script, don't bother + with anything other than the version macros. */ +#ifndef RC_INVOKED + +#if defined(_MSC_VER) +#define inline __inline +#endif + +#define MaxHostNameLen (64+4) +#define MaxPathLen MAX_PATH + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN MaxHostNameLen +#endif +#ifndef MAXPATHLEN +#define MAXPATHLEN MaxPathLen +#endif + +#if _MSC_VER < 1900 +# define __func__ __FUNCTION__ +#endif + +#ifdef BUILD_KRB5_LIB +#ifndef KRB5_LIB +#ifdef _WIN32 +#define KRB5_LIB_FUNCTION +#define KRB5_LIB_NORETURN_FUNCTION __declspec(noreturn) +#define KRB5_LIB_CALL __stdcall +#define KRB5_LIB_VARIABLE +#else +#define KRB5_LIB_FUNCTION +#define KRB5_LIB_NORETURN_FUNCTION +#define KRB5_LIB_CALL +#define KRB5_LIB_VARIABLE +#endif +#endif +#endif + + +#ifdef BUILD_HX509_LIB +#ifndef HX509_LIB +#ifdef _WIN32 +#define HX509_LIB_FUNCTION +#define HX509_LIB_NORETURN_FUNCTION __declspec(noreturn) +#define HX509_LIB_CALL __stdcall +#define HX509_LIB_VARIABLE +#else +#define HX509_LIB_FUNCTION +#define HX509_LIB_NORETURN_FUNCTION +#define HX509_LIB_CALL +#define HX509_LIB_VARIABLE +#endif +#endif +#endif + + +#ifdef BUILD_ROKEN_LIB +#ifndef ROKEN_LIB +#ifdef _WIN32 +#define ROKEN_LIB_FUNCTION +#define ROKEN_LIB_NORETURN_FUNCTION __declspec(noreturn) +#define ROKEN_LIB_CALL __cdecl +#define ROKEN_LIB_VARIABLE +#else +#define ROKEN_LIB_FUNCTION +#define ROKEN_LIB_NORETURN_FUNCTION +#define ROKEN_LIB_CALL +#define ROKEN_LIB_VARIABLE +#endif +#endif +#endif + + +#ifdef BUILD_GSSAPI_LIB +#ifndef GSSAPI_LIB +#ifdef _WIN32 +#define GSSAPI_LIB_FUNCTION +#define GSSAPI_LIB_NORETURN_FUNCTION __declspec(noreturn) +#define GSSAPI_LIB_CALL __stdcall +#define GSSAPI_LIB_VARIABLE +#else +#define GSSAPI_LIB_FUNCTION +#define GSSAPI_LIB_NORETURN_FUNCTION +#define GSSAPI_LIB_CALL +#define GSSAPI_LIB_VARIABLE +#endif +#endif +#endif + + +#ifdef BUILD_KDC_LIB +#ifndef KDC_LIB +#ifdef _WIN32 +#define KDC_LIB_FUNCTION +#define KDC_LIB_NORETURN_FUNCTION __declspec(noreturn) +#define KDC_LIB_CALL __stdcall +#define KDC_LIB_VARIABLE +#else +#define KDC_LIB_FUNCTION +#define KDC_LIB_NORETURN_FUNCTION +#define KDC_LIB_CALL +#define KDC_LIB_VARIABLE +#endif +#endif +#endif + + +/* Feature macros */ + +@FEATURE_DEFS@ + +/* Define is backslashes act as path name delimiters */ +#define BACKSLASH_PATH_DELIM 1 + +/* Path separator character */ +#define PATH_SEP ";" + +/* Define if you want to use DES encryption in telnet. */ +#define DES_ENCRYPTION 1 + +/* Define this if you want support for broken ENV_{VAR,VAL} telnets. */ +/* #undef ENV_HACK */ + +/* define if prototype of gethostbyaddr is compatible with struct hostent + *gethostbyaddr(const void *, size_t, int) */ +/* #undef GETHOSTBYADDR_PROTO_COMPATIBLE */ + +/* define if prototype of gethostbyname is compatible with struct hostent + *gethostbyname(const char *) */ +#define GETHOSTBYNAME_PROTO_COMPATIBLE 1 + +/* define if prototype of getservbyname is compatible with struct servent + *getservbyname(const char *, const char *) */ +#define GETSERVBYNAME_PROTO_COMPATIBLE 1 + +/* define if prototype of getsockname is compatible with int getsockname(int, + struct sockaddr*, socklen_t*) */ +/* #undef GETSOCKNAME_PROTO_COMPATIBLE */ + +/* Define if you have the `altzone' variable. */ +/* #undef HAVE_ALTZONE */ + +/* Define to 1 if you have the `arc4random' function. */ +/* #undef HAVE_ARC4RANDOM */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ARPA_INET_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ARPA_NAMESER_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ARPA_TELNET_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ASL_H */ + +/* Define to 1 if you have the `asnprintf' function. */ +/* #undef HAVE_ASNPRINTF */ + +/* Define to 1 if you have the `asprintf' function. */ +/* #undef HAVE_ASPRINTF */ + +/* Define to 1 if you have the `atexit' function. */ +#define HAVE_ATEXIT 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_BIND_BITYPES_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_BSDSETJMP_H */ + +/* Define to 1 if you have the `bswap16' function. */ +/* #undef HAVE_BSWAP16 */ + +/* Define to 1 if you have the `bswap32' function. */ +/* #undef HAVE_BSWAP32 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_CAPABILITY_H */ + +/* Define to 1 if you have the `cap_set_proc' function. */ +/* #undef HAVE_CAP_SET_PROC */ + +/* Define if the system defines 'CHAR' type */ +#define HAVE_CHAR 1 + +/* Define if you have the function `chown'. */ +#define HAVE_CHOWN 1 + +/* Define if you have the function `closefrom'. */ +/* #undef HAVE_CLOSEFROM */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_CONFIG_H */ + +/* Define if is present on the system is should be used for + handling low level console operations. */ +#define HAVE_CONIO_H + +/* Define if you have the function `copyhostent'. */ +/* #undef HAVE_COPYHOSTENT */ + +/* Define to 1 if you have the `crypt' function. */ +/* #undef HAVE_CRYPT */ + +/* Define to 1 if you have the header file. */ +/* #ndef HAVE_CRYPT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_CURSES_H */ + +/* Define if you have the function `daemon'. */ +/* #define HAVE_DAEMON 1 */ + +/* define if you have a berkeley db1/2 library */ +/* #undef HAVE_DB1 */ + +/* define if you have a berkeley db3/4 library */ +/* #define HAVE_DB3 1 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DB3_DB_H */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_DB4_DB_H 1 */ + +/* Define to 1 if you have the `dbm_firstkey' function. */ +/* #define HAVE_DBM_FIRSTKEY 1 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DBM_H */ + +/* Define to 1 if you have the `dbopen' function. */ +/* #undef HAVE_DBOPEN */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_DB_185_H 1 */ + +/* Define to 1 if you have the `db_create' function. */ +/* #define HAVE_DB_CREATE 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_DB_H 1 */ + +/* define if you have ndbm compat in db */ +/* #define HAVE_DB_NDBM 1 */ + +/* Define to 1 if you have the declaration of `altzone', and to 0 if you + don't. */ +/* #undef HAVE_DECL_ALTZONE */ + +/* Define to 1 if you have the declaration of `environ', and to 0 if you + don't. */ +#define HAVE_DECL_ENVIRON 1 + +/* Define to 1 if you have the declaration of `h_errlist', and to 0 if you + don't. */ +/* #undef HAVE_DECL_H_ERRLIST */ + +/* Define to 1 if you have the declaration of `h_errno', and to 0 if you + don't. */ +#define HAVE_DECL_H_ERRNO 1 + +/* Define to 1 if you have the declaration of `h_nerr', and to 0 if you don't. + */ +/* #undef HAVE_DECL_H_NERR */ + +/* Define to 1 if you have the declaration of `optarg', and to 0 if you don't. + */ +/* #undef HAVE_DECL_OPTARG */ + +/* Define to 1 if you have the declaration of `opterr', and to 0 if you don't. + */ +/* #undef HAVE_DECL_OPTERR */ + +/* Define to 1 if you have the declaration of `optind', and to 0 if you don't. + */ +/* #undef HAVE_DECL_OPTIND */ + +/* Define to 1 if you have the declaration of `optopt', and to 0 if you don't. + */ +/* #undef HAVE_DECL_OPTOPT */ + +/* Define to 1 if you have the declaration of `timezone', and to 0 if you + don't. */ +#define HAVE_DECL_TIMEZONE 1 + +/* Define to 1 if you have the declaration of `_res', and to 0 if you don't. + */ +/* #undef HAVE_DECL__RES */ + +/* Define to 1 if you have the declaration of `__progname', and to 0 if you + don't. */ +#define HAVE_DECL___PROGNAME 0 + +/* Define to 1 if you have the header file. */ +/* MSVC doesn't provide a , but we implement it in + lib/roken. */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you have the header file. */ +/* MSVC doesn't provide a , but we implement it in lib/roken. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the `dlopen' function. */ +/* MSVC doesn't provide a , but we implement it in lib/roken. */ +#define HAVE_DLOPEN 1 + +/* Define to 1 if you have the `dladdr' function. */ +/* MSVC doesn't provide a , but we implement it in lib/roken. */ +#define HAVE_DLADDR 1 + +/* Define to 1 if you have the `dn_expand' function. */ +/* #undef HAVE_DN_EXPAND */ + +/* Define to 1 if you have the `door_create' function. */ +/* #undef HAVE_DOOR_CREATE */ + +/* Define if you have the function `ecalloc'. */ +/* #undef HAVE_ECALLOC */ + +/* Define to 1 if you have the `el_init' function. */ +/* #undef HAVE_EL_INIT */ + +/* Define if you have the function `emalloc'. */ +/* #undef HAVE_EMALLOC */ + +/* Define if you have the function `erealloc'. */ +/* #undef HAVE_EREALLOC */ + +/* Define if you have the function `err'. */ +#define HAVE_ERR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define if you have the function `errx'. */ +#define HAVE_ERRX 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERR_H 1 + +/* Define if you have the function `estrdup'. */ +/* #undef HAVE_ESTRDUP */ + +/* Define if you have the function `fchown'. */ +/* #undef HAVE_FCHOWN */ + +/* Define to 1 if you have the `fcntl' function. */ +/* #undef HAVE_FCNTL */ + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the function `flock'. */ +/* #undef HAVE_FLOCK */ + +/* Define if you have the function `fnmatch'. */ +/* #undef HAVE_FNMATCH */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_FNMATCH_H */ + +/* Define if you have the function `fseeko'. */ +/* #undef HAVE_FSEEKO */ + +/* Define if you have the function `ftello'. */ +/* #undef HAVE_FTELLO */ + +/* Define if you have the function `_fseeki64'. */ +#define HAVE__FSEEKI64 1 + +/* Define if you have the function `_ftelli64'. */ +#define HAVE__FTELLI64 1 + +/* Define if el_init takes four arguments. */ +/* #undef HAVE_FOUR_VALUED_EL_INIT */ + +/* Have -framework Security */ +/* #undef HAVE_FRAMEWORK_SECURITY */ + +/* Define to 1 if you have the `freeaddrinfo' function. */ +#define HAVE_FREEADDRINFO 1 + +/* Define if you have the function `freehostent'. */ +/* #undef HAVE_FREEHOSTENT */ + +/* Define to 1 if you have the `gai_strerror' function. */ +#define HAVE_GAI_STRERROR 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_GDBM_NDBM_H */ + +/* Define to 1 if you have the `getaddrinfo' function. */ +#define HAVE_GETADDRINFO 1 + +/* Define to 1 if you have the `getconfattr' function. */ +/* #undef HAVE_GETCONFATTR */ + +/* Define if you have the function `getcwd'. */ +#define HAVE_GETCWD 1 + +/* Define if you have the function `getdtablesize'. */ +/* #define HAVE_GETDTABLESIZE 1 */ + +/* Define if you have the function `getegid'. */ +/* #define HAVE_GETEGID 1 */ + +/* Define if you have the function `geteuid'. */ +/* #define HAVE_GETEUID 1 */ + +/* Define if you have the function `getgid'. */ +/* #define HAVE_GETGID 1 */ + +/* Define to 1 if you have the `gethostbyname2' function. */ +/* #undef HAVE_GETHOSTBYNAME2 */ + +/* Define if you have the function `gethostname'. */ +#define HAVE_GETHOSTNAME 1 + +/* Define if you have the function `getifaddrs'. */ +/* #undef HAVE_GETIFADDRS */ + +/* Define if you have the function `getipnodebyaddr'. */ +/* #undef HAVE_GETIPNODEBYADDR */ + +/* Define if you have the function `getipnodebyname'. */ +/* #undef HAVE_GETIPNODEBYNAME */ + +/* Define to 1 if you have the `getlogin' function. */ +/* #define HAVE_GETLOGIN 1 */ + +/* Define to 1 if you have the `getlogin_r' function. */ +/* #define HAVE_GETLOGIN_R 1 */ + +/* Define if you have a working getmsg. */ +/* #undef HAVE_GETMSG */ + +/* Define to 1 if you have the `getnameinfo' function. */ +#define HAVE_GETNAMEINFO 1 + +/* Define if you have the function `getopt'. */ +/* #define HAVE_GETOPT 1 */ + +/* Define to 1 if you have the `getpagesize' function. */ +/* #define HAVE_GETPAGESIZE 1 */ + +/* Define to 1 if you have the `getpeereid' function. */ +/* #define HAVE_GETPEEREID 1 */ + +/* Define to 1 if you have the `getpeerucred' function. */ +/* #undef HAVE_GETPEERUCRED */ + +/* Define to 1 if you have the `getprogname' function. */ +/* #define HAVE_GETPROGNAME 1 */ + +/* Define to 1 if you have the `getpwnam_r' function. */ +/* #define HAVE_GETPWNAM_R 1 */ + +/* Define to 1 if you have the `getpwuid_r' function. */ +/* #define HAVE_GETPWUID_R 1 */ + +/* Define to 1 if you have the `getrlimit' function. */ +/* #define HAVE_GETRLIMIT 1 */ + +/* Define to 1 if you have the `getsockopt' function. */ +#define HAVE_GETSOCKOPT 1 + +/* Define to 1 if you have the `getspnam' function. */ +/* #undef HAVE_GETSPNAM */ + +/* Define if you have the function `gettimeofday'. */ +/* #define HAVE_GETTIMEOFDAY 1 */ + +/* Define to 1 if you have the `getudbnam' function. */ +/* #undef HAVE_GETUDBNAM */ + +/* Define if you have the function `getuid'. */ +/* #define HAVE_GETUID 1 */ + +/* Define if you have the function `getusershell'. */ +/* #define HAVE_GETUSERSHELL 1 */ + +/* Define to 1 if you have the `grantpt' function. */ +/* #define HAVE_GRANTPT 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_GRP_H 1 */ + +/* Define to 1 if you have the `hstrerror' function. */ +/* #define HAVE_HSTRERROR 1 */ + +/* Define if you have the `h_errlist' variable. */ +/* #undef HAVE_H_ERRLIST */ + +/* Define if you have the `h_errno' variable. */ +/* #define HAVE_H_ERRNO 1 */ + +/* Define if you have the `h_nerr' variable. */ +/* #undef HAVE_H_NERR */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_IFADDRS_H */ + +/* Define if you have the in6addr_loopback variable */ +/* #undef HAVE_IN6ADDR_LOOPBACK */ + +/* */ +#define HAVE_INET_ADDR 1 + +/* define */ +/* #define HAVE_INET_ATON 1 */ + +/* define */ +/* #define HAVE_INET_NTOP 1 */ + +/* define */ +/* #define HAVE_INET_PTON 1 */ + +#if _WIN32_WINNT >= 0x0600 + +#define HAVE_INET_NTOP 1 + +#define HAVE_INET_PTON 1 + +#endif + +/* Define if you have the function `initgroups'. */ +/* #define HAVE_INITGROUPS 1 */ + +/* Define to 1 if you have the `initstate' function. */ +/* #define HAVE_INITSTATE 1 */ + +/* Define if you have the function `innetgr'. */ +/* #undef HAVE_INNETGR */ + +/* Define to 1 if the system has the type `int16_t'. */ +/* #define HAVE_INT16_T 1 */ + +/* Define to 1 if the system has the type `int32_t'. */ +/* #define HAVE_INT32_T 1 */ + +/* Define to 1 if the system has the type `int64_t'. */ +/* #define HAVE_INT64_T 1 */ + +/* Define to 1 if the system has the type `int8_t'. */ +/* #define HAVE_INT8_T 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_INTTYPES_H 1 */ + +/* Define to 1 if you have the header file. */ +#define HAVE_IO_H 1 + +/* Define if you have IPv6. */ +#define HAVE_IPV6 1 + +/* Define to 1 if you have the `issetugid' function. */ +/* #undef HAVE_ISSETUGID */ + +/* Define if you want to use the Kerberos Credentials Manager. */ +/* #define HAVE_KCM 1 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LIBUTIL_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the `loadquery' function. */ +/* #undef HAVE_LOADQUERY */ + +/* Define if you have the function `localtime_r'. */ +/* #define HAVE_LOCALTIME_R 1 */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if the system has the type `long long'. */ +#define HAVE_LONG_LONG 1 + +/* Define if you have the function `lstat'. */ +/* #define HAVE_LSTAT 1 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MAILLOCK_H */ + +/* Define if you have the function `memmove'. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define if you have the function `mkstemp'. */ +/* #define HAVE_MKSTEMP 1 */ + +/* Define to 1 if you have a working `mmap' system call. */ +/* #undef HAVE_MMAP */ + +/* define if you have a ndbm library */ +/* #undef HAVE_NDBM */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NDBM_H */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_NETDB_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETGROUP_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETINET6_IN6_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETINET6_IN6_VAR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETINET_IN6_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETINET_IN6_MACHTYPES_H */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_NETINET_IN_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_NETINET_TCP_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_NETINET_IN_SYSTM_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_NETINET_IP_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_NETINET_TCP_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_NET_IF_H 1 */ + +/* Define if NDBM really is DB (creates files *.db) */ +/* #define HAVE_NEW_DB 1 */ + +/* Define to 1 if you have the `on_exit' function. */ +/* #define HAVE_ON_EXIT 1 */ + +/* Define to 1 if you have the '_onexit' function */ +#define HAVE__ONEXIT 1 + +/* Define to 1 if you have the `openpty' function. */ +/* #define HAVE_OPENPTY 1 */ + +/* define to 1 to use openssl's libcrypto as a (default) backend for libhcrypto */ +/* #undef HAVE_HCRYPTO_W_OPENSSL */ + +/* Define to enable basic OSF C2 support. */ +/* #undef HAVE_OSFC2 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_PATHS_H 1 */ + +/* Define to 1 if you have the `pidfile' function. */ +/* #undef HAVE_PIDFILE */ + +/* Define to 1 if you have the `poll' function. */ +/* #define HAVE_POLL 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_POLL_H 1 */ + +/* Define to 1 if you have the header file. */ +/* This option is added by the NTMakefile if we have a . */ +/* #define HAVE_PTHREAD_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_PTY_H 1 */ + +/* Define if you have the function `putenv'. */ +#define HAVE_PUTENV 1 + +/* Define to 1 if you have the header file. */ +/* #define HAVE_PWD_H 1 */ + +/* Define to 1 if you have the `rand' function. */ +#define HAVE_RAND 1 + +/* Define to 1 if you have the `random' function. */ +/* #define HAVE_RANDOM 1 */ + +/* Define if you have the function `rcmd'. */ +/* #define HAVE_RCMD 1 */ + +/* Define if you have a readline compatible library. */ +/* #define HAVE_READLINE 1 */ + +/* Define if you have the function `readv'. */ +/* #define HAVE_READV 1 */ + +/* Define if you have the function `recvmsg'. */ +/* #define HAVE_RECVMSG 1 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_RESOLV_H */ + +/* Define to 1 if you have the `res_ndestroy' function. */ +/* #undef HAVE_RES_NDESTROY */ + +/* Define to 1 if you have the `res_nsearch' function. */ +/* #undef HAVE_RES_NSEARCH */ + +/* Define to 1 if you have the `res_search' function. */ +/* #undef HAVE_RES_SEARCH */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_RPCSVC_YPCLNT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SAC_H */ + +/* Define to 1 if the system has the type `sa_family_t'. */ +/* #define HAVE_SA_FAMILY_T 1 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SECURITY_PAM_MODULES_H */ + +/* Define to 1 if you have the `select' function. */ +#define HAVE_SELECT 1 + +/* Define if you have the function `sendmsg'. */ +/* #define HAVE_SENDMSG 1 */ + +/* Define if you have the function `setegid'. */ +/* #define HAVE_SETEGID 1 */ + +/* Define if you have the function `setenv'. */ +#define HAVE_SETENV 1 + +/* Define if you have the function `seteuid'. */ +/* #define HAVE_SETEUID 1 */ + +/* Define to 1 if you have the `setitimer' function. */ +/* #define HAVE_SETITIMER 1 */ + +/* Define to 1 if you have the `setlim' function. */ +/* #undef HAVE_SETLIM */ + +/* Define to 1 if you have the `setlogin' function. */ +/* #undef HAVE_SETLOGIN */ + +/* Define to 1 if you have the `setprogname' function. */ +/* #define HAVE_SETPROGNAME 1 */ + +/* Define to 1 if you have the `setregid' function. */ +/* #define HAVE_SETREGID 1 */ + +/* Define to 1 if you have the `setresgid' function. */ +/* #undef HAVE_SETRESGID */ + +/* Define to 1 if you have the `setresuid' function. */ +/* #undef HAVE_SETRESUID */ + +/* Define to 1 if you have the `setreuid' function. */ +/* #define HAVE_SETREUID 1 */ + +/* Define to 1 if you have the `setsid' function. */ +/* #define HAVE_SETSID 1 */ + +/* Define to 1 if you have the `setsockopt' function. */ +#define HAVE_SETSOCKOPT 1 + +/* Define to 1 if you have the `setstate' function. */ +/* #define HAVE_SETSTATE 1 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SGTTY_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SHADOW_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SIAD_H */ + +/* Define to 1 if you have the `sigaction' function. */ +/* #define HAVE_SIGACTION 1 */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SIGNAL_H 1 + +/* define if you have a working snprintf */ +/* snprintf() and vsnprintf() do exist. But the implementations are + not C99 compliant. */ +/* #define HAVE_SNPRINTF 1 */ + +/* Define to 1 if the system has the type `socklen_t'. */ +#define HAVE_SOCKLEN_T 1 + +/* Define to 1 if the system has the type `ssize_t'. */ +/* #define HAVE_SSIZE_T 1 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STANDARDS_H */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_STDINT_H 1 */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define if you have the function `strcasecmp'. */ +#define HAVE_STRCASECMP 1 +#define strcasecmp _stricmp + +/* Define if you have the function `strdup'. */ +#define HAVE_STRDUP 1 + +/* Define if you have the function `strerror'. */ +#define HAVE_STRERROR 1 + +/* Define if you have the function `strftime'. */ +/* #define HAVE_STRFTIME 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_STRINGS_H 1 */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define if you have the function `strlcat'. */ +/* #define HAVE_STRLCAT 1 */ + +/* Define if you have the function `strlcpy'. */ +/* #define HAVE_STRLCPY 1 */ + +/* Define if you have the function `strlwr'. */ +#define HAVE_STRLWR 1 + +/* Define if you have the function `strncasecmp'. */ +#define HAVE_STRNCASECMP 1 +#define strncasecmp _strnicmp + +/* Define if you have the function `strndup'. */ +/* #define HAVE_STRNDUP 1 */ + +/* Define if you have the function `strnlen'. */ +#define HAVE_STRNLEN 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STROPTS_H */ + +/* Define if you have the function `strptime'. */ +/* #define HAVE_STRPTIME 1 */ + +/* Define if you have the function `strsep'. */ +/* #define HAVE_STRSEP 1 */ + +/* Define if you have the function `strsep_copy'. */ +/* #undef HAVE_STRSEP_COPY */ + +/* Define to 1 if you have the `strsvis' function. */ +/* #undef HAVE_STRSVIS */ + +/* Define if you have the function `strtok_r'. */ +/* #define HAVE_STRTOK_R 1 */ + +#if defined(__has_include) +# if __has_include() +# define HAVE_UCRT 1 +# endif +#endif + +#ifdef HAVE_UCRT +#define HAVE_STRTOLL 1 +#define HAVE_STRTOULL 1 +#endif + +/* Define to 1 if the system has the type `struct addrinfo'. */ +#define HAVE_STRUCT_ADDRINFO 1 + +/* Define to 1 if the system has the type `struct ifaddrs'. */ +/* #undef HAVE_STRUCT_IFADDRS */ + +/* Define to 1 if the system has the type `struct iovec'. */ +/* #define HAVE_STRUCT_IOVEC 1 */ + +/* Define to 1 if the system has the type `struct msghdr'. */ +/* #define HAVE_STRUCT_MSGHDR 1 */ + +/* Define to 1 if the system has the type `struct sockaddr'. */ +#define HAVE_STRUCT_SOCKADDR 1 + +/* Define if struct sockaddr has field sa_len. */ +/* #undef HAVE_STRUCT_SOCKADDR_SA_LEN */ + +/* Define to 1 if the system has the type `struct sockaddr_storage'. */ +#define HAVE_STRUCT_SOCKADDR_STORAGE 1 + +/* define if you have struct spwd */ +/* #undef HAVE_STRUCT_SPWD */ + +/* Define if struct tm has field tm_gmtoff. */ +/* #undef HAVE_STRUCT_TM_TM_GMTOFF */ + +/* Define if struct tm has field tm_zone. */ +/* #undef HAVE_STRUCT_TM_TM_ZONE */ + +/* define if struct winsize is declared in sys/termios.h */ +/* #define HAVE_STRUCT_WINSIZE 1 */ + +/* Define to 1 if you have the `strunvis' function. */ +/* #undef HAVE_STRUNVIS */ + +/* Define if you have the function `strupr'. */ +#define HAVE_STRUPR 1 + +/* Define to 1 if you have the `strvis' function. */ +/* #undef HAVE_STRVIS */ + +/* Define to 1 if you have the `strvisx' function. */ +/* #undef HAVE_STRVISX */ + +/* Define to 1 if you have the `svis' function. */ +/* #undef HAVE_SVIS */ + +/* Define if you have the function `swab'. */ +#define HAVE_SWAB 1 + +/* Define to 1 if you have the `sysconf' function. */ +/* #define HAVE_SYSCONF 1 */ + +/* Define to 1 if you have the `sysctl' function. */ +/* #undef HAVE_SYSCTL */ + +/* syslog is provided for _win32 in lib/roken */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYSLOG_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_BITYPES_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_BSWAP_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_CAPABILITY_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_CATEGORY_H */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SYS_FILE_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_FILIO_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_IOCCOM_H */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SYS_IOCTL_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SYS_MMAN_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SYS_PARAM_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_PROC_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_PTYIO_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_PTYVAR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_PTY_H */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SYS_RESOURCE_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SYS_SELECT_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SYS_SOCKET_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SOCKIO_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_STREAM_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_STROPTS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_STRTTY_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_STR_TTY_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SYSCALL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SYSCTL_H */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SYS_TERMIO_H 1 */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIMEB_H 1 + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SYS_TIMES_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SYS_TIME_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_TTY_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_UCRED_H */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SYS_UIO_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SYS_UN_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SYS_UTSNAME_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_SYS_WAIT_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_TERMCAP_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_TERMIOS_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_TERMIO_H 1 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_TERM_H */ + +/* Define to 1 if you have the `tgetent' function. */ +/* #define HAVE_TGETENT 1 */ + +/* Define if you have the function `timegm'. */ +/* #define HAVE_TIMEGM 1 */ + +/* Define if you have the `timezone' variable. */ +#define HAVE_TIMEZONE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_TIME_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_TMPDIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_UDB_H */ + +/* Define to 1 if the system has the type `uint16_t'. */ +/* #define HAVE_UINT16_T 1 */ + +/* Define to 1 if the system has the type `uint32_t'. */ +/* #define HAVE_UINT32_T 1 */ + +/* Define to 1 if the system has the type `uint64_t'. */ +/* #define HAVE_UINT64_T 1 */ + +/* Define to 1 if the system has the type `uint8_t'. */ +/* #define HAVE_UINT8_T 1 */ + +/* Define to 1 if the system has the type `uintptr_t'. */ +#define HAVE_UINTPTR_T 1 + +/* Define to 1 if you have the `uname' function. */ +/* #define HAVE_UNAME 1 */ + +/* Define to 1 if you have the header file. */ +/* #define HAVE_UNISTD_H 1 */ + +/* Define to 1 if you have the `unlockpt' function. */ +/* #define HAVE_UNLOCKPT 1 */ + +/* Define if you have the function `unsetenv'. */ +/* #define HAVE_UNSETENV 1 */ + +/* Define to 1 if you have the `unvis' function. */ +/* #undef HAVE_UNVIS */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_USERCONF_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_USERSEC_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_UTIL_H */ + +/* Define to 1 if the system has the type `u_int16_t'. */ +/* #define HAVE_U_INT16_T 1 */ + +/* Define to 1 if the system has the type `u_int32_t'. */ +/* #define HAVE_U_INT32_T 1 */ + +/* Define to 1 if the system has the type `u_int64_t'. */ +/* #define HAVE_U_INT64_T 1 */ + +/* Define to 1 if the system has the type `u_int8_t'. */ +/* #define HAVE_U_INT8_T 1 */ + +/* Define to 1 if you have the `vasnprintf' function. */ +/* #undef HAVE_VASNPRINTF */ + +/* Define to 1 if you have the `vasprintf' function. */ +/* #define HAVE_VASPRINTF 1 */ + +/* Define if you have the function `verr'. */ +/* #define HAVE_VERR 1 */ + +/* Define if you have the function `verrx'. */ +/* #define HAVE_VERRX 1 */ + +/* Define to 1 if you have the `vis' function. */ +/* #undef HAVE_VIS */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_VIS_H */ + +/* define if you have a working vsnprintf */ +/* snprintf() and vsnprintf() do exist. But the implementations are + not C99 compliant. */ +/* #define HAVE_VSNPRINTF 1 */ + +/* Define if you have the function `vsyslog'. */ +#define HAVE_VSYSLOG 1 + +/* Define if you have the function `vwarn'. */ +/* #define HAVE_VWARN 1 */ + +/* Define if you have the function `vwarnx'. */ +/* #define HAVE_VWARNX 1 */ + +/* Define if you have the function `warn'. */ +/* #define HAVE_WARN 1 */ + +/* Define if you have the function `warnx'. */ +/* #define HAVE_WARNX 1 */ + +/* Define if you have the function `writev'. */ +/* #define HAVE_WRITEV 1 */ + +/* Defined if we have WinSock */ +#define HAVE_WINSOCK 1 + +/* Defined if we have WinDNS */ +#define HAVE_WINDNS 1 + +/* define if struct winsize has ws_xpixel */ +/* #define HAVE_WS_XPIXEL 1 */ + +/* define if struct winsize has ws_ypixel */ +/* #define HAVE_WS_YPIXEL 1 */ + +/* Define if you have the `_res' variable. */ +/* #undef HAVE__RES */ + +/* Define to 1 if you have the `_scrsize' function. */ +/* #undef HAVE__SCRSIZE */ + +/* define if your compiler has __attribute__ */ +/* #define HAVE___ATTRIBUTE__ 1 */ + +/* Define if you have the `__progname' variable. */ +/* #define HAVE___PROGNAME 1 */ + +/* Define if you are running IRIX 4. */ +/* #undef IRIX4 */ + +/* define if the system is missing a prototype for asnprintf() */ +/* #define NEED_ASNPRINTF_PROTO 1 */ + +/* define if the system is missing a prototype for asprintf() */ +/* #undef NEED_ASPRINTF_PROTO */ + +/* define if the system is missing a prototype for crypt() */ +/* #undef NEED_CRYPT_PROTO */ + +/* define if the system is missing a prototype for daemon() */ +/* #undef NEED_DAEMON_PROTO */ + +/* define if the system is missing a prototype for gethostname() */ +/* #undef NEED_GETHOSTNAME_PROTO */ + +/* define if the system is missing a prototype for getusershell() */ +/* #undef NEED_GETUSERSHELL_PROTO */ + +/* define if the system is missing a prototype for glob() */ +/* #undef NEED_GLOB_PROTO */ + +/* define if the system is missing a prototype for hstrerror() */ +/* #undef NEED_HSTRERROR_PROTO */ + +/* define if the system is missing a prototype for inet_aton() */ +/* #undef NEED_INET_ATON_PROTO */ + +/* define if the system is missing a prototype for mkstemp() */ +/* #define NEED_MKSTEMP_PROTO 1 */ + +/* define if the system is missing a prototype for SecKeyGetCSPHandle() */ +/* #undef NEED_SECKEYGETCSPHANDLE_PROTO */ + +/* define if the system is missing a prototype for setenv() */ +#define NEED_SETENV_PROTO 1 + +/* define if the system is missing a prototype for snprintf() */ +/* #undef NEED_SNPRINTF_PROTO */ + +/* define if the system is missing a prototype for strndup() */ +/* #undef NEED_STRNDUP_PROTO */ + +/* define if the system is missing a prototype for strsep() */ +/* #undef NEED_STRSEP_PROTO */ + +/* define if the system is missing a prototype for strsvis() */ +/* #define NEED_STRSVIS_PROTO 1 */ + +/* define if the system is missing a prototype for strtok_r() */ +#define NEED_STRTOK_R_PROTO 1 + +/* define if the system is missing a prototype for strunvis() */ +/* #define NEED_STRUNVIS_PROTO 1 */ + +/* define if the system is missing a prototype for strvisx() */ +/* #define NEED_STRVISX_PROTO 1 */ + +/* define if the system is missing a prototype for strvis() */ +/* #define NEED_STRVIS_PROTO 1 */ + +/* define if the system is missing a prototype for svis() */ +/* #define NEED_SVIS_PROTO 1 */ + +/* define if the system is missing a prototype for unsetenv() */ +/* #undef NEED_UNSETENV_PROTO */ + +/* define if the system is missing a prototype for unvis() */ +/* #define NEED_UNVIS_PROTO 1 */ + +/* define if the system is missing a prototype for vasnprintf() */ +/* #define NEED_VASNPRINTF_PROTO 1 */ + +/* define if the system is missing a prototype for vasprintf() */ +/* #undef NEED_VASPRINTF_PROTO */ + +/* define if the system is missing a prototype for vis() */ +/* #define NEED_VIS_PROTO 1 */ + +/* define if the system is missing a prototype for vsnprintf() */ +/* #undef NEED_VSNPRINTF_PROTO */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Define if you don't want to use mmap. */ +#define NO_MMAP 1 + +/* Define if the Unix rand method is not defined */ +#define NO_RAND_UNIX_METHOD 1 + +/* Define if the Fortuna rand method is not defined */ +#define NO_RAND_FORTUNA_METHOD 1 + +/* Define if PID files should not be used. */ +#define NO_PIDFILES 1 + +/* Define if SIGPIPE is not supported */ +#define NO_SIGPIPE 1 + +/* Define if SIGXCPU is not supported */ +#define NO_SIGXCPU 1 + +/* Define if sleep() is not available */ +#define NO_SLEEP 1 + +/* Define to 1 if Unix sockets (AF_UNIX) are not available. */ +#define NO_UNIX_SOCKETS 1 + +/* Define to 1 if POSIX link/unlink operations should be avoided. + This may be because the behavior of links are not not consistent + with POSIX or because the filesystem may not support POSIX + links. */ +#define NO_POSIX_LINKS 1 + +/* Define this to enable old environment option in telnet. */ +/* #define OLD_ENVIRON 1 */ + +/* define if prototype of openlog is compatible with void openlog(const char + *, int, int) */ +#define OPENLOG_PROTO_COMPATIBLE 1 + +/* Define if getlogin has POSIX flavour (and not BSD). */ +/* #define POSIX_GETLOGIN 1 */ + +/* Define if getlogin_r has POSIX flavour (and not BSD). */ +/* #define POSIX_GETLOGIN_R 1 */ + +/* Define if getpwnam_r has POSIX flavour. */ +/* #define POSIX_GETPWNAM_R 1 */ + +/* Define if getpwnam_r has POSIX flavour. */ +/* #define POSIX_GETPWUID_R 1 */ + +/* Define if you have the readline package. */ +#define READLINE 1 + +/* Define if rename() does not unlink an existing file */ +#define RENAME_DOES_NOT_UNLINK 1 + +/* Define if you want to use samba socket wrappers. */ +/* #undef SOCKET_WRAPPER_REPLACE */ + +/* Define if a socket is not a file descriptor */ +#define SOCKET_IS_NOT_AN_FD 1 + +/* Define if FD_SETSIZE check does not apply to this platform */ +#define NO_LIMIT_FD_SETSIZE 1 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you have streams ptys. */ +/* #undef STREAMSPTY */ + +/* Define to 1 if you can safely include both and . */ +/* #define TIME_WITH_SYS_TIME 1 */ + +/* Define to 1 if your declares `struct tm'. */ +/* #undef TM_IN_SYS_TIME */ + +/* define if target is big endian */ +/* #undef WORDS_BIGENDIAN */ + +/* Define to 1 if the X Window System is missing or not being used. */ +#define X_DISPLAY_MISSING 1 + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +/* #undef YYTEXT_POINTER */ + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define to enable extensions on glibc-based systems such as Linux. */ +/* #define _GNU_SOURCE 1 */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Set this to the default system lead string for telnetd + * can contain %-escapes: %s=sysname, %m=machine, %r=os-release + * %v=os-version, %t=tty, %h=hostname, %d=date and time + */ +/* #undef USE_IM */ + +/* Used with login -p */ +/* #undef LOGIN_ARGS */ + +/* The size of `time_t', as computed by sizeof. */ +#if defined (_USE_64BIT_TIME_T) || !defined( _USE_32BIT_TIME_T) +#define SIZEOF_TIME_T 8 +#else +#define SIZEOF_TIME_T 4 +#endif + +#ifdef ROKEN_RENAME +#include "roken_rename.h" +#endif + +#if defined(ENCRYPTION) && !defined(AUTHENTICATION) +#define AUTHENTICATION 1 +#endif + + + +/* Paths */ + +#define SYSCONFDIR "%{COMMONCONFIG}" + +#define LIBDIR "%{LIBDIR}" + +#define CLIENT_KEYTAB_DEFAULT "FILE:%{LOCAL_APPDATA}\\Kerberos\\client.keytab" + +#endif /* RC_INVOKED */ + + +/* Version info */ + +#define PACKAGE "@PACKAGE@" + +#define PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@" + +#define PACKAGE_NAME "@PACKAGE_NAME@" + +#define PACKAGE_STRING "@PACKAGE_NAME@ @PACKAGE_VERSION@" + +#define PACKAGE_TARNAME "@PACKAGE@" + +#define PACKAGE_VERSION "@PACKAGE_VERSION@" + +#define PACKAGE_COMPANY "@PACKAGE_COMPANY@" + +#define PACKAGE_COPYRIGHT "@PACKAGE_COPYRIGHT@" + +#define VERSION "@PACKAGE_VERSION@" + +#define RC_PRODVER_MAJOR @MAJOR@ + +#define RC_PRODVER_MINOR @MINOR@ + +#define RC_PRODVER_AUX @AUX@ + +#define RC_PRODVER_PATCH @PATCH@ + +#define RC_PRODVER_C @MAJOR@,@MINOR@,@AUX@,@PATCH@ + +#define RC_PRODVER_CS "@MAJOR@,@MINOR@,@AUX@,@PATCH@" + +#define RC_PRODVER_DS "@MAJOR@.@MINOR@.@AUX@.@PATCH@" + +#define RC_PRODUCT_NAME_0409 PACKAGE_NAME + +#define RC_PRODUCT_VER_0409 PACKAGE_VERSION + +#define RC_COMPANY_0409 PACKAGE_COMPANY + +#define RC_COPYRIGHT_0409 PACKAGE_COPYRIGHT + +@VERSION_OPTDEFS@ + +#endif /* __CONFIG_H__ */ diff --git a/include/crypto-headers.h b/include/crypto-headers.h new file mode 100644 index 000000000..5c0b24223 --- /dev/null +++ b/include/crypto-headers.h @@ -0,0 +1,25 @@ +#ifndef __crypto_header__ +#define __crypto_header__ + +#ifndef PACKAGE_NAME +#error "need config.h" +#endif + +#ifdef KRB5 +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif /* __crypto_header__ */ diff --git a/include/gssapi/Makefile.am b/include/gssapi/Makefile.am index 024c20e45..c0b050864 100644 --- a/include/gssapi/Makefile.am +++ b/include/gssapi/Makefile.am @@ -2,5 +2,6 @@ include $(top_srcdir)/Makefile.am.common -CLEANFILES = gssapi.h gssapi_krb5.h gssapi_spnego.h +CLEANFILES = gssapi.h gssapi_krb5.h gssapi_spnego.h gssapi_ntlm.h gssapi_oid.h +EXTRA_DIST = NTMakefile diff --git a/include/gssapi/NTMakefile b/include/gssapi/NTMakefile new file mode 100644 index 000000000..2f0e83b33 --- /dev/null +++ b/include/gssapi/NTMakefile @@ -0,0 +1,34 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=include\gssapi + +!include ../../windows/NTMakefile.w32 diff --git a/include/hcrypto/Makefile.am b/include/hcrypto/Makefile.am index dadb2be59..e9a59fd38 100644 --- a/include/hcrypto/Makefile.am +++ b/include/hcrypto/Makefile.am @@ -8,10 +8,14 @@ CLEANFILES = \ des.h \ dh.h \ dsa.h \ + ec.h \ + ecdsa.h \ + ecdh.h \ engine.h \ evp.h \ + evp-hcrypto.h \ + evp-cc.h \ hmac.h \ - md2.h \ md4.h \ md5.h \ pkcs12.h \ @@ -20,4 +24,7 @@ CLEANFILES = \ rc4.h \ rsa.h \ sha.h \ - ui.h + ui.h \ + undef.h + +EXTRA_DIST = NTMakefile diff --git a/include/hcrypto/NTMakefile b/include/hcrypto/NTMakefile new file mode 100644 index 000000000..fd56cec73 --- /dev/null +++ b/include/hcrypto/NTMakefile @@ -0,0 +1,34 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=include\hcrypto + +!include ../../windows/NTMakefile.w32 diff --git a/include/heim_threads.h b/include/heim_threads.h index c4f841fb6..3ed06d926 100644 --- a/include/heim_threads.h +++ b/include/heim_threads.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 Kungliga Tekniska Högskolan + * Copyright (c) 2003-2016 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -46,6 +46,26 @@ #ifndef HEIM_THREADS_H #define HEIM_THREADS_H 1 +#include + +#ifdef _MSC_VER + +#define HEIMDAL_THREAD_LOCAL __declspec(thread) + +#else + +#if defined(__clang__) || defined(__GNUC__) || defined(__SUNPRO_C) +#define HEIMDAL_THREAD_LOCAL __thread +#else +#error "thread-local attribute not defined for your compiler" +#endif /* clang or gcc */ + +#endif /* _MSC_VER */ + +/* For testing the for-Windows implementation of thread keys on non-Windows */ +typedef unsigned long HEIM_PRIV_thread_key; + + /* assume headers already included */ #if defined(__NetBSD__) && __NetBSD_Version__ >= 106120000 && __NetBSD_Version__< 299001200 && defined(ENABLE_PTHREAD_SUPPORT) @@ -67,13 +87,13 @@ #define HEIMDAL_RWLOCK rwlock_t #define HEIMDAL_RWLOCK_INITIALIZER RWLOCK_INITIALIZER -#define HEIMDAL_RWLOCK_init(l) rwlock_init(l, NULL) -#define HEIMDAL_RWLOCK_rdlock(l) rwlock_rdlock(l) -#define HEIMDAL_RWLOCK_wrlock(l) rwlock_wrlock(l) -#define HEIMDAL_RWLOCK_tryrdlock(l) rwlock_tryrdlock(l) -#define HEIMDAL_RWLOCK_trywrlock(l) rwlock_trywrlock(l) -#define HEIMDAL_RWLOCK_unlock(l) rwlock_unlock(l) -#define HEIMDAL_RWLOCK_destroy(l) rwlock_destroy(l) +#define HEIMDAL_RWLOCK_init(l) rwlock_init(l, NULL) +#define HEIMDAL_RWLOCK_rdlock(l) rwlock_rdlock(l) +#define HEIMDAL_RWLOCK_wrlock(l) rwlock_wrlock(l) +#define HEIMDAL_RWLOCK_tryrdlock(l) rwlock_tryrdlock(l) +#define HEIMDAL_RWLOCK_trywrlock(l) rwlock_trywrlock(l) +#define HEIMDAL_RWLOCK_unlock(l) rwlock_unlock(l) +#define HEIMDAL_RWLOCK_destroy(l) rwlock_destroy(l) #define HEIMDAL_thread_key thread_key_t #define HEIMDAL_key_create(k,d,r) do { r = thr_keycreate(k,d); } while(0) @@ -81,6 +101,9 @@ #define HEIMDAL_getspecific(k) thr_getspecific(k) #define HEIMDAL_key_delete(k) thr_keydelete(k) +#define HEIMDAL_THREAD_ID thr_t +#define HEIMDAL_THREAD_create(t,f,a) thr_create((t), 0, (f), (a)) + #elif defined(ENABLE_PTHREAD_SUPPORT) && (!defined(__NetBSD__) || __NetBSD_Version__ >= 299001200) #include @@ -92,21 +115,182 @@ #define HEIMDAL_MUTEX_unlock(m) pthread_mutex_unlock(m) #define HEIMDAL_MUTEX_destroy(m) pthread_mutex_destroy(m) -#define HEIMDAL_RWLOCK rwlock_t -#define HEIMDAL_RWLOCK_INITIALIZER RWLOCK_INITIALIZER -#define HEIMDAL_RWLOCK_init(l) pthread_rwlock_init(l, NULL) -#define HEIMDAL_RWLOCK_rdlock(l) pthread_rwlock_rdlock(l) -#define HEIMDAL_RWLOCK_wrlock(l) pthread_rwlock_wrlock(l) -#define HEIMDAL_RWLOCK_tryrdlock(l) pthread_rwlock_tryrdlock(l) -#define HEIMDAL_RWLOCK_trywrlock(l) pthread_rwlock_trywrlock(l) -#define HEIMDAL_RWLOCK_unlock(l) pthread_rwlock_unlock(l) -#define HEIMDAL_RWLOCK_destroy(l) pthread_rwlock_destroy(l) +#define HEIMDAL_RWLOCK pthread_rwlock_t +#define HEIMDAL_RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER +#define HEIMDAL_RWLOCK_init(l) pthread_rwlock_init(l, NULL) +#define HEIMDAL_RWLOCK_rdlock(l) pthread_rwlock_rdlock(l) +#define HEIMDAL_RWLOCK_wrlock(l) pthread_rwlock_wrlock(l) +#define HEIMDAL_RWLOCK_tryrdlock(l) pthread_rwlock_tryrdlock(l) +#define HEIMDAL_RWLOCK_trywrlock(l) pthread_rwlock_trywrlock(l) +#define HEIMDAL_RWLOCK_unlock(l) pthread_rwlock_unlock(l) +#define HEIMDAL_RWLOCK_destroy(l) pthread_rwlock_destroy(l) +#ifdef HEIM_BASE_MAINTAINER +#define HEIMDAL_thread_key unsigned long +#define HEIM_PRIV_thread_key HEIMDAL_thread_key +#define HEIMDAL_key_create(k,d,r) do { r = heim_w32_key_create(k,d); } while(0) +#define HEIMDAL_setspecific(k,s,r) do { r = heim_w32_setspecific(k,s); } while(0) +#define HEIMDAL_getspecific(k) (heim_w32_getspecific(k)) +#define HEIMDAL_key_delete(k) (heim_w32_delete_key(k)) +#else #define HEIMDAL_thread_key pthread_key_t #define HEIMDAL_key_create(k,d,r) do { r = pthread_key_create(k,d); } while(0) #define HEIMDAL_setspecific(k,s,r) do { r = pthread_setspecific(k,s); } while(0) #define HEIMDAL_getspecific(k) pthread_getspecific(k) #define HEIMDAL_key_delete(k) pthread_key_delete(k) +#endif + +#define HEIMDAL_THREAD_ID pthread_t +#define HEIMDAL_THREAD_create(t,f,a) pthread_create((t), 0, (f), (a)) + +#elif defined(_WIN32) + +typedef struct heim_mutex { + HANDLE h; +} heim_mutex_t; + +static inline int +heim_mutex_init(heim_mutex_t *m) +{ + m->h = CreateSemaphore(NULL, 1, 1, NULL); + if (m->h == INVALID_HANDLE_VALUE) + return EAGAIN; + return 0; +} + +static inline int +heim_mutex_lock(heim_mutex_t *m) +{ + HANDLE h, new_h; + int created = 0; + + h = InterlockedCompareExchangePointer(&m->h, m->h, m->h); + if (h == INVALID_HANDLE_VALUE || h == NULL) { + created = 1; + new_h = CreateSemaphore(NULL, 0, 1, NULL); + if (new_h == INVALID_HANDLE_VALUE) + return EAGAIN; + if (InterlockedCompareExchangePointer(&m->h, new_h, h) != h) { + created = 0; + CloseHandle(new_h); + } + } + if (!created) + WaitForSingleObject(m->h, INFINITE); + return 0; +} + +static inline int +heim_mutex_unlock(heim_mutex_t *m) +{ + if (ReleaseSemaphore(m->h, 1, NULL) == FALSE) + return EPERM; + return 0; +} + +static inline int +heim_mutex_destroy(heim_mutex_t *m) +{ + HANDLE h; + + h = InterlockedCompareExchangePointer(&m->h, INVALID_HANDLE_VALUE, m->h); + if (h != INVALID_HANDLE_VALUE) + CloseHandle(h); + return 0; +} + +#define HEIMDAL_MUTEX heim_mutex_t +#define HEIMDAL_MUTEX_INITIALIZER { INVALID_HANDLE_VALUE } +#define HEIMDAL_MUTEX_init(m) heim_mutex_init((m)) +#define HEIMDAL_MUTEX_lock(m) heim_mutex_lock((m)) +#define HEIMDAL_MUTEX_unlock(m) heim_mutex_unlock((m)) +#define HEIMDAL_MUTEX_destroy(m) heim_mutex_destroy((m)) + +typedef struct heim_rwlock { + SRWLOCK lock; + int exclusive; +} heim_rwlock_t; + +static inline int +heim_rwlock_init(heim_rwlock_t *l) +{ + InitializeSRWLock(&l->lock); + l->exclusive = 0; + return 0; +} + +static inline int +heim_rwlock_rdlock(heim_rwlock_t *l) +{ + AcquireSRWLockShared(&l->lock); + return 0; +} + +static inline int +heim_rwlock_wrlock(heim_rwlock_t *l) +{ + AcquireSRWLockExclusive(&l->lock); + l->exclusive = 1; + return 0; +} + +static inline int +heim_rwlock_tryrdlock(heim_rwlock_t *l) +{ + if (TryAcquireSRWLockShared(&l->lock)) + return 0; + return EBUSY; +} + +static inline int +heim_rwlock_trywrlock(heim_rwlock_t *l) +{ + if (TryAcquireSRWLockExclusive(&l->lock)) + return 0; + return EBUSY; +} + +static inline int +heim_rwlock_unlock(heim_rwlock_t *l) +{ + if (l->exclusive) { + l->exclusive = 0; + ReleaseSRWLockExclusive(&(l)->lock); + } else { + ReleaseSRWLockShared(&(l)->lock); + } + return 0; +} + +static inline int +heim_rwlock_destroy(heim_rwlock_t *l) +{ + /* SRW locks cannot be destroyed so re-initialize */ + InitializeSRWLock(&l->lock); + l->exclusive = 0; + return 0; +} + +#define HEIMDAL_RWLOCK heim_rwlock_t +#define HEIMDAL_RWLOCK_INITIALIZER {SRWLOCK_INIT, 0} +#define HEIMDAL_RWLOCK_init(l) heim_rwlock_init((l)) +#define HEIMDAL_RWLOCK_rdlock(l) heim_rwlock_rdlock((l)) +#define HEIMDAL_RWLOCK_wrlock(l) heim_rwlock_wrlock((l)) +#define HEIMDAL_RWLOCK_tryrdlock(l) heim_rwlock_tryrdlock((l)) +#define HEIMDAL_RWLOCK_trywrlock(l) heim_rwlock_trywrlock((l)) +#define HEIMDAL_RWLOCK_unlock(l) heim_rwlock_unlock((l)) +#define HEIMDAL_RWLOCK_destroy(l) heim_rwlock_destroy((l)) + +#define HEIMDAL_thread_key unsigned long +#define HEIM_PRIV_thread_key HEIMDAL_thread_key +#define HEIMDAL_key_create(k,d,r) do { r = heim_w32_key_create(k,d); } while(0) +#define HEIMDAL_setspecific(k,s,r) do { r = heim_w32_setspecific(k,s); } while(0) +#define HEIMDAL_getspecific(k) (heim_w32_getspecific(k)) +#define HEIMDAL_key_delete(k) (heim_w32_delete_key(k)) + +#define HEIMDAL_THREAD_ID DWORD +#define HEIMDAL_THREAD_create(t,f,a) \ + ((CreateThread(0, 0, (f), (a), 0, (t)) == INVALID_HANDLE_VALUE) ? EINVAL : 0) #elif defined(HEIMDAL_DEBUG_THREADS) @@ -132,6 +316,9 @@ #define HEIMDAL_internal_thread_key 1 +#define HEIMDAL_THREAD_ID int +#define HEIMDAL_THREAD_create(t,f,a) abort() + #else /* no thread support, no debug case */ #define HEIMDAL_MUTEX int @@ -151,6 +338,9 @@ #define HEIMDAL_RWLOCK_unlock(l) do { } while(0) #define HEIMDAL_RWLOCK_destroy(l) do { } while(0) +#define HEIMDAL_THREAD_ID int +#define HEIMDAL_THREAD_create(t,f,a) abort() + #define HEIMDAL_internal_thread_key 1 #endif /* no thread support */ @@ -172,4 +362,9 @@ typedef struct heim_thread_key { #undef HEIMDAL_internal_thread_key #endif /* HEIMDAL_internal_thread_key */ +int heim_w32_key_create(HEIM_PRIV_thread_key *, void (*)(void *)); +int heim_w32_delete_key(HEIM_PRIV_thread_key); +int heim_w32_setspecific(HEIM_PRIV_thread_key, void *); +void *heim_w32_getspecific(HEIM_PRIV_thread_key); + #endif /* HEIM_THREADS_H */ diff --git a/include/heimqueue.h b/include/heimqueue.h new file mode 100644 index 000000000..5e922cfcb --- /dev/null +++ b/include/heimqueue.h @@ -0,0 +1,270 @@ +/* $NetBSD: queue.h,v 1.38 2004/04/18 14:12:05 lukem Exp $ */ +/* $Id$ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _HEIM_QUEUE_H_ +#define _HEIM_QUEUE_H_ + +/* + * Singly-linked List definitions. + */ +#define HEIM_SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define HEIM_SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define HEIM_SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define HEIM_SLIST_INIT(head) do { \ + (head)->slh_first = NULL; \ +} while (/*CONSTCOND*/0) + +#define HEIM_SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define HEIM_SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define HEIM_SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (/*CONSTCOND*/0) + +#define HEIM_SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + HEIM_SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = (head)->slh_first; \ + while(curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + } \ +} while (/*CONSTCOND*/0) + +#define HEIM_SLIST_FOREACH(var, head, field) \ + for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next) + +/* + * Singly-linked List access methods. + */ +#define HEIM_SLIST_EMPTY(head) ((head)->slh_first == NULL) +#define HEIM_SLIST_FIRST(head) ((head)->slh_first) +#define HEIM_SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +/* + * Singly-linked List atomic functions. + */ +#include "heimbase.h" + +#define HEIM_SLIST_ATOMIC_HEAD(name, type) \ +struct name { \ + heim_base_atomic(struct type *) slh_first; /* first element */ \ +} + +#define HEIM_SLIST_ATOMIC_ENTRY(type) \ +struct { \ + heim_base_atomic(struct type *) sle_next; /* next element */ \ +} + +#define HEIM_SLIST_ATOMIC_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = \ + heim_base_exchange_pointer(&(head)->slh_first, (elm)); \ +} while (/*CONSTCOND*/0) + +#define HEIM_SLIST_ATOMIC_FOREACH(var, head, field) \ + for ((var) = heim_base_atomic_load(&(head)->slh_first); \ + (var) != NULL; \ + (var) = heim_base_atomic_load(&(var)->field.sle_next)) +/* + * Tail queue definitions. + */ +#define HEIM_TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define HEIM_TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } +#define HEIM_TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * Tail queue functions. + */ +#if defined(_KERNEL) && defined(QUEUEDEBUG) +#define QUEUEDEBUG_HEIM_TAILQ_INSERT_HEAD(head, elm, field) \ + if ((head)->tqh_first && \ + (head)->tqh_first->field.tqe_prev != &(head)->tqh_first) \ + panic("HEIM_TAILQ_INSERT_HEAD %p %s:%d", (head), __FILE__, __LINE__); +#define QUEUEDEBUG_HEIM_TAILQ_INSERT_TAIL(head, elm, field) \ + if (*(head)->tqh_last != NULL) \ + panic("HEIM_TAILQ_INSERT_TAIL %p %s:%d", (head), __FILE__, __LINE__); +#define QUEUEDEBUG_HEIM_TAILQ_OP(elm, field) \ + if ((elm)->field.tqe_next && \ + (elm)->field.tqe_next->field.tqe_prev != \ + &(elm)->field.tqe_next) \ + panic("HEIM_TAILQ_* forw %p %s:%d", (elm), __FILE__, __LINE__);\ + if (*(elm)->field.tqe_prev != (elm)) \ + panic("HEIM_TAILQ_* back %p %s:%d", (elm), __FILE__, __LINE__); +#define QUEUEDEBUG_HEIM_TAILQ_PREREMOVE(head, elm, field) \ + if ((elm)->field.tqe_next == NULL && \ + (head)->tqh_last != &(elm)->field.tqe_next) \ + panic("HEIM_TAILQ_PREREMOVE head %p elm %p %s:%d", \ + (head), (elm), __FILE__, __LINE__); +#define QUEUEDEBUG_HEIM_TAILQ_POSTREMOVE(elm, field) \ + (elm)->field.tqe_next = (void *)1L; \ + (elm)->field.tqe_prev = (void *)1L; +#else +#define QUEUEDEBUG_HEIM_TAILQ_INSERT_HEAD(head, elm, field) +#define QUEUEDEBUG_HEIM_TAILQ_INSERT_TAIL(head, elm, field) +#define QUEUEDEBUG_HEIM_TAILQ_OP(elm, field) +#define QUEUEDEBUG_HEIM_TAILQ_PREREMOVE(head, elm, field) +#define QUEUEDEBUG_HEIM_TAILQ_POSTREMOVE(elm, field) +#endif + +#define HEIM_TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (/*CONSTCOND*/0) + +#define HEIM_TAILQ_INSERT_HEAD(head, elm, field) do { \ + QUEUEDEBUG_HEIM_TAILQ_INSERT_HEAD((head), (elm), field) \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (/*CONSTCOND*/0) + +#define HEIM_TAILQ_INSERT_TAIL(head, elm, field) do { \ + QUEUEDEBUG_HEIM_TAILQ_INSERT_TAIL((head), (elm), field) \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define HEIM_TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + QUEUEDEBUG_HEIM_TAILQ_OP((listelm), field) \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define HEIM_TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + QUEUEDEBUG_HEIM_TAILQ_OP((listelm), field) \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define HEIM_TAILQ_REMOVE(head, elm, field) do { \ + QUEUEDEBUG_HEIM_TAILQ_PREREMOVE((head), (elm), field) \ + QUEUEDEBUG_HEIM_TAILQ_OP((elm), field) \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + QUEUEDEBUG_HEIM_TAILQ_POSTREMOVE((elm), field); \ +} while (/*CONSTCOND*/0) + +#define HEIM_TAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->tqh_first); \ + (var); \ + (var) = ((var)->field.tqe_next)) + +#define HEIM_TAILQ_FOREACH_SAFE(var, head, field, next) \ + for ((var) = ((head)->tqh_first); \ + (var) != NULL && ((next) = HEIM_TAILQ_NEXT(var, field), 1); \ + (var) = (next)) + +#define HEIM_TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \ + (var); \ + (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last))) + +#define HEIM_TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, prev) \ + for ((var) = HEIM_TAILQ_LAST((head), headname); \ + (var) && ((prev) = HEIM_TAILQ_PREV((var), headname, field), 1);\ + (var) = (prev)) + +#define HEIM_TAILQ_CONCAT(head1, head2, field) do { \ + if (!HEIM_TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + HEIM_TAILQ_INIT((head2)); \ + } \ +} while (/*CONSTCOND*/0) + +/* + * Tail queue access methods. + */ +#define HEIM_TAILQ_EMPTY(head) ((head)->tqh_first == NULL) +#define HEIM_TAILQ_FIRST(head) ((head)->tqh_first) +#define HEIM_TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define HEIM_TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +#define HEIM_TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + + +#endif /* !_HEIM_QUEUE_H_ */ diff --git a/include/kadm5/Makefile.am b/include/kadm5/Makefile.am index c7bb38524..d0ce25d3f 100644 --- a/include/kadm5/Makefile.am +++ b/include/kadm5/Makefile.am @@ -2,4 +2,7 @@ include $(top_srcdir)/Makefile.am.common -CLEANFILES = admin.h kadm5_err.h private.h kadm5-private.h kadm5-protos.h +CLEANFILES = admin.h kadm5_err.h private.h +CLEANFILES += kadm5-private.h kadm5-protos.h kadm5-pwcheck.h + +EXTRA_DIST = NTMakefile diff --git a/include/kadm5/NTMakefile b/include/kadm5/NTMakefile new file mode 100644 index 000000000..26fc8d02b --- /dev/null +++ b/include/kadm5/NTMakefile @@ -0,0 +1,34 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=include\kadm5 + +!include ../../windows/NTMakefile.w32 diff --git a/include/krb5-types.cross b/include/krb5-types.cross new file mode 100644 index 000000000..4dc5c6aa8 --- /dev/null +++ b/include/krb5-types.cross @@ -0,0 +1,67 @@ +/* + * generic krb5-types.h for cross compiling, assume system is posix/sus + */ + +#ifndef __krb5_types_h__ +#define __krb5_types_h__ + +#include +#include +#include + +typedef socklen_t krb5_socklen_t; +#include +typedef ssize_t krb5_ssize_t; + +#if !defined(__has_extension) +#define __has_extension(x) 0 +#endif + +#define KRB5TYPES_REQUIRE_GNUC(m,n,p) \ + (((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) + __GNUC_PATCHLEVEL__) >= \ + (((m) * 10000) + ((n) * 100) + (p))) + + +#ifndef HEIMDAL_DEPRECATED +#if __has_extension(deprecated) || KRB5TYPES_REQUIRE_GNUC(3,1,0) +#define HEIMDAL_DEPRECATED __attribute__ ((__deprecated__)) +#elif defined(_MSC_VER) && (_MSC_VER>1200) +#define HEIMDAL_DEPRECATED __declspec(deprecated) +#else +#define HEIMDAL_DEPRECATED +#endif +#endif + +#ifndef HEIMDAL_PRINTF_ATTRIBUTE +#if __has_extension(format) || KRB5TYPES_REQUIRE_GNUC(3,1,0) +#define HEIMDAL_PRINTF_ATTRIBUTE(x) __attribute__ ((__format__ x)) +#else +#define HEIMDAL_PRINTF_ATTRIBUTE(x) +#endif +#endif + +#ifndef HEIMDAL_NORETURN_ATTRIBUTE +#if __has_extension(noreturn) || KRB5TYPES_REQUIRE_GNUC(3,1,0) +#define HEIMDAL_NORETURN_ATTRIBUTE __attribute__ ((__noreturn__)) +#else +#define HEIMDAL_NORETURN_ATTRIBUTE +#endif +#endif + +#ifndef HEIMDAL_UNUSED_ATTRIBUTE +#if __has_extension(unused) || KRB5TYPES_REQUIRE_GNUC(3,1,0) +#define HEIMDAL_UNUSED_ATTRIBUTE __attribute__ ((__unused__)) +#else +#define HEIMDAL_UNUSED_ATTRIBUTE +#endif +#endif + +#ifndef HEIMDAL_WARN_UNUSED_RESULT_ATTRIBUTE +#if __has_extension(__warn_unused_result__) || KRB5TYPES_REQUIRE_GNUC(3,3,0) +#define HEIMDAL_WARN_UNUSED_RESULT_ATTRIBUTE __attribute__ ((__warn_unused_result__)) +#endif +#endif + +typedef int krb5_socket_t; + +#endif /* __krb5_types_h__ */ diff --git a/include/make_crypto.c b/include/make_crypto.c deleted file mode 100644 index ee80e7005..000000000 --- a/include/make_crypto.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2002 - 2005 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -#include -RCSID("$Id$"); -#endif -#include -#include -#include -#include - -int -main(int argc, char **argv) -{ - char *p; - FILE *f; - if(argc != 2) { - fprintf(stderr, "Usage: make_crypto file\n"); - exit(1); - } - if (strcmp(argv[1], "--version") == 0) { - printf("some version"); - return 0; - } - f = fopen(argv[1], "w"); - if(f == NULL) { - perror(argv[1]); - exit(1); - } - for(p = argv[1]; *p; p++) - if(!isalnum((unsigned char)*p)) - *p = '_'; - fprintf(f, "#ifndef __%s__\n", argv[1]); - fprintf(f, "#define __%s__\n", argv[1]); -#ifdef HAVE_OPENSSL - fputs("#ifndef OPENSSL_DES_LIBDES_COMPATIBILITY\n", f); - fputs("#define OPENSSL_DES_LIBDES_COMPATIBILITY\n", f); - fputs("#endif\n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#ifndef BN_is_negative\n", f); - fputs("#define BN_set_negative(bn, flag) ((bn)->neg=(flag)?1:0)\n", f); - fputs("#define BN_is_negative(bn) ((bn)->neg != 0)\n", f); - fputs("#endif\n", f); -#else - fputs("#ifdef KRB5\n", f); - fputs("#include \n", f); - fputs("#endif\n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); - fputs("#include \n", f); -#endif - fprintf(f, "#endif /* __%s__ */\n", argv[1]); - fclose(f); - exit(0); -} diff --git a/kadmin/Makefile.am b/kadmin/Makefile.am index fda3bf795..d9b8fee1c 100644 --- a/kadmin/Makefile.am +++ b/kadmin/Makefile.am @@ -2,15 +2,13 @@ include $(top_srcdir)/Makefile.am.common -AM_CPPFLAGS += $(INCLUDE_libintl) $(INCLUDE_readline) $(INCLUDE_hcrypto) -I$(srcdir)/../lib/krb5 -I$(top_builddir)/include/gssapi +AM_CPPFLAGS += $(INCLUDE_libintl) $(INCLUDE_readline) -I$(srcdir)/../lib/krb5 -I$(top_builddir)/include/gssapi -sbin_PROGRAMS = kadmin +bin_PROGRAMS = kadmin libexec_PROGRAMS = kadmind -SLC = $(top_builddir)/lib/sl/slc - -man_MANS = kadmin.8 kadmind.8 +man_MANS = kadmin.1 kadmind.8 noinst_PROGRAMS = add_random_users @@ -28,6 +26,7 @@ dist_kadmin_SOURCES = \ kadmin.c \ load.c \ mod.c \ + prune.c \ rename.c \ stash.c \ util.c \ @@ -63,14 +62,14 @@ check_PROGRAMS = $(TESTS) LDADD_common = \ $(top_builddir)/lib/hdb/libhdb.la \ - $(LIB_openldap) \ $(top_builddir)/lib/krb5/libkrb5.la \ $(LIB_hcrypto) \ $(top_builddir)/lib/asn1/libasn1.la \ $(LIB_roken) \ - $(DBLIB) + $(DB3LIB) $(DB1LIB) $(LMDBLIB) $(NDBMLIB) kadmind_LDADD = $(top_builddir)/lib/kadm5/libkadm5srv.la \ + $(top_builddir)/lib/kadm5/libkadm5clnt.la \ ../lib/gssapi/libgssapi.la \ $(LDADD_common) \ $(LIB_pidfile) \ @@ -92,4 +91,9 @@ add_random_users_LDADD = \ test_util_LDADD = $(kadmin_LDADD) -EXTRA_DIST = $(man_MANS) kadmin-commands.in +EXTRA_DIST = \ + NTMakefile \ + kadmin-version.rc \ + kadmind-version.rc \ + $(man_MANS) \ + kadmin-commands.in diff --git a/kadmin/NTMakefile b/kadmin/NTMakefile new file mode 100644 index 000000000..c7f2b7f6b --- /dev/null +++ b/kadmin/NTMakefile @@ -0,0 +1,135 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=kadmin +cincdirs=-I$(OBJ) -I$(INCDIR)\gssapi + +!include ../windows/NTMakefile.w32 + +SBIN_PROGRAMS=$(SBINDIR)\kadmin.exe + +# Disable kadmind.exe since currently it doesn't build +#LIBEXEC_PROGRAMS=$(LIBEXECDIR)\kadmind.exe +# + +COMMON_LIBS= \ + $(LIBHDB) \ + $(LIBHEIMDAL) \ + $(LIBROKEN) + +KADMIN_OBJS= \ + $(OBJ)\ank.obj \ + $(OBJ)\add_enctype.obj \ + $(OBJ)\check.obj \ + $(OBJ)\cpw.obj \ + $(OBJ)\del.obj \ + $(OBJ)\del_enctype.obj \ + $(OBJ)\dump.obj \ + $(OBJ)\ext.obj \ + $(OBJ)\get.obj \ + $(OBJ)\init.obj \ + $(OBJ)\kadmin.obj \ + $(OBJ)\load.obj \ + $(OBJ)\mod.obj \ + $(OBJ)\prune.obj \ + $(OBJ)\rename.obj \ + $(OBJ)\stash.obj \ + $(OBJ)\util.obj \ + $(OBJ)\pw_quality.obj \ + $(OBJ)\random_password.obj \ + $(OBJ)\kadmin-commands.obj \ + $(OBJ)\kadmin-version.res + +KADMIN_LIBS= \ + $(LIBKADM5CLNT) \ + $(LIBKADM5SRV) \ + $(LIBSL) \ + $(COMMON_LIBS) \ + $(LIBVERS) \ + $(LIBCOMERR) + +INCFILES=$(OBJ)\kadmin-commands.h + +$(OBJ)\kadmin-commands.c $(OBJ)\kadmin-commands.h: kadmin-commands.in + cd $(OBJ) + $(CP) $(SRCDIR)\kadmin-commands.in $(OBJ) + $(BINDIR)\slc.exe kadmin-commands.in + cd $(SRCDIR) + +$(SBINDIR)\kadmin.exe: $(KADMIN_OBJS) $(KADMIN_LIBS) + $(EXECONLINK) Secur32.lib Shell32.lib + $(EXEPREP) + +KADMIND_OBJS= \ + $(OBJ)\rpc.obj \ + $(OBJ)\server.obj \ + $(OBJ)\kadmind.obj \ + $(OBJ)\kadm_conn.obj \ + $(OBJ)\kadmind-version.res + +KADMIND_LIBS=\ + $(LIBKADM5SRV) \ + $(LIBGSSAPI) \ + $(COMMON_LIBS) + +$(LIBEXECDIR)\kadmind.exe: $(KADMIND_OBJS) $(KADMIND_LIBS) + $(EXECONLINK) Secur32.lib Shell32.lib + $(EXEPREP) + +all:: $(INCFILES) $(SBIN_PROGRAMS) $(LIBEXEC_PROGRAMS) + +clean:: + -$(RM) $(SBIN_PROGRAMS:.exe=.*) + -$(RM) $(LIBEXEC_PROGRAMS:.exe=.*) + + + + +NOINST_PROGRAMS=$(OBJ)\add_random_users.exe + +$(OBJ)\add_random_users.exe: $(OBJ)\add_random_users.obj $(LIBKADM5SRV) $(LIBKADM5CLNT) $(COMMON_LIBS) + $(EXECONLINK) Secur32.lib Shell32.lib + $(EXEPREP_NODIST) + +#TEST_BINARIES=$(OBJ)\test_util.exe +# +#$(OBJ)\test_util.exe: $(OBJ)\test_util.obj $(OBJ)\util.obj $(KADMIN_LIBS) +# $(EXECONLINK) Secur32.lib Shell32.lib +# $(EXEPREP_NODIST) +# +#test-binaries: $(TEST_BINARIES) +# +#test-run: +# cd $(OBJ) +# test_util.exe +# cd $(SRCDIR) +# +test:: #test-binaries test-run diff --git a/kadmin/add-random-users.c b/kadmin/add-random-users.c index 43182ca1d..e2dc303b8 100644 --- a/kadmin/add-random-users.c +++ b/kadmin/add-random-users.c @@ -33,8 +33,6 @@ #include "kadmin_locl.h" -RCSID("$Id$"); - #define WORDS_FILENAME "/usr/share/dict/words" #define NUSERS 1000 @@ -60,7 +58,7 @@ read_words (const char *filename, char ***ret_w) buf[strcspn(buf, "\r\n")] = '\0'; if (n >= alloc) { alloc = max(alloc + 16, alloc * 2); - w = erealloc (w, alloc * sizeof(char **)); + w = erealloc (w, alloc * sizeof(char *)); } len = strlen(buf); if (wptr + len + 1 >= wend) { @@ -79,8 +77,7 @@ read_words (const char *filename, char ***ret_w) } static void -add_user (krb5_context context, void *kadm_handle, - unsigned nwords, char **words) +add_user (krb5_context ctx, void *hndl, unsigned nwords, char **words) { kadm5_principal_ent_rec princ; char name[64]; @@ -96,14 +93,14 @@ add_user (krb5_context context, void *kadm_handle, mask = KADM5_PRINCIPAL; memset(&princ, 0, sizeof(princ)); - ret = krb5_parse_name(context, name, &princ.principal); + ret = krb5_parse_name(ctx, name, &princ.principal); if (ret) - krb5_err(context, 1, ret, "krb5_parse_name"); + krb5_err(ctx, 1, ret, "krb5_parse_name"); - ret = kadm5_create_principal (kadm_handle, &princ, mask, name); + ret = kadm5_create_principal (hndl, &princ, mask, name); if (ret) - krb5_err (context, 1, ret, "kadm5_create_principal"); - kadm5_free_principal_ent(kadm_handle, &princ); + krb5_err (ctx, 1, ret, "kadm5_create_principal"); + kadm5_free_principal_ent(hndl, &princ); printf ("%s\n", name); } @@ -112,37 +109,38 @@ add_users (const char *filename, unsigned n) { krb5_error_code ret; int i; - void *kadm_handle; - krb5_context context; + void *hndl; + krb5_context ctx; unsigned nwords; char **words; - ret = krb5_init_context(&context); + ret = krb5_init_context(&ctx); if (ret) errx (1, "krb5_init_context failed: %d", ret); - ret = kadm5_s_init_with_password_ctx(context, + ret = kadm5_s_init_with_password_ctx(ctx, KADM5_ADMIN_SERVICE, NULL, KADM5_ADMIN_SERVICE, NULL, 0, 0, - &kadm_handle); + &hndl); if(ret) - krb5_err(context, 1, ret, "kadm5_init_with_password"); + krb5_err(ctx, 1, ret, "kadm5_init_with_password"); nwords = read_words (filename, &words); for (i = 0; i < n; ++i) - add_user (context, kadm_handle, nwords, words); - kadm5_destroy(kadm_handle); - krb5_free_context(context); + add_user (ctx, hndl, nwords, words); + kadm5_destroy(hndl); + krb5_free_context(ctx); + free(words); } static int version_flag = 0; static int help_flag = 0; static struct getargs args[] = { - { "version", 0, arg_flag, &version_flag }, - { "help", 0, arg_flag, &help_flag } + { "version", 0, arg_flag, &version_flag, NULL, NULL }, + { "help", 0, arg_flag, &help_flag, NULL, NULL } }; static void diff --git a/kadmin/add_enctype.c b/kadmin/add_enctype.c index 1d0d84b24..d128ab7f4 100644 --- a/kadmin/add_enctype.c +++ b/kadmin/add_enctype.c @@ -34,8 +34,6 @@ #include "kadmin_locl.h" #include "kadmin-commands.h" -RCSID("$Id$"); - /* * del_enctype principal enctypes... */ @@ -48,7 +46,7 @@ add_enctype(struct add_enctype_options*opt, int argc, char **argv) krb5_error_code ret; const char *princ_name; int i, j; - krb5_key_data *new_key_data; + krb5_key_data *new_key_data = NULL; int n_etypes; krb5_enctype *etypes; @@ -57,7 +55,7 @@ add_enctype(struct add_enctype_options*opt, int argc, char **argv) return 0; } - memset (&princ, 0, sizeof(princ)); + memset(&princ, 0, sizeof(princ)); princ_name = argv[0]; n_etypes = argc - 1; etypes = malloc (n_etypes * sizeof(*etypes)); @@ -67,7 +65,7 @@ add_enctype(struct add_enctype_options*opt, int argc, char **argv) } argv++; for (i = 0; i < n_etypes; ++i) { - ret = krb5_string_to_enctype (context, argv[i], &etypes[i]); + ret = krb5_string_to_enctype(context, argv[i], &etypes[i]); if (ret) { krb5_warnx (context, "bad enctype \"%s\"", argv[i]); goto out2; @@ -76,20 +74,27 @@ add_enctype(struct add_enctype_options*opt, int argc, char **argv) ret = krb5_parse_name(context, princ_name, &princ_ent); if (ret) { - krb5_warn (context, ret, "krb5_parse_name %s", princ_name); + krb5_warn(context, ret, "krb5_parse_name %s", princ_name); goto out2; } + /* The principal might have zero keys, but it will still have a kvno! */ ret = kadm5_get_principal(kadm_handle, princ_ent, &princ, - KADM5_PRINCIPAL | KADM5_KEY_DATA); + KADM5_KVNO | KADM5_PRINCIPAL | KADM5_KEY_DATA); if (ret) { - krb5_free_principal (context, princ_ent); - krb5_warnx (context, "no such principal: %s", princ_name); + krb5_free_principal(context, princ_ent); + krb5_warnx(context, "no such principal: %s", princ_name); goto out2; } - new_key_data = malloc((princ.n_key_data + n_etypes) - * sizeof(*new_key_data)); + /* Check that we got key data */ + if (kadm5_all_keys_are_bogus(princ.n_key_data, princ.key_data)) { + krb5_warnx(context, "user lacks get-keys privilege"); + goto out; + } + + new_key_data = calloc(princ.n_key_data + n_etypes, + sizeof(*new_key_data)); if (new_key_data == NULL) { krb5_warnx (context, "out of memory"); goto out; @@ -100,9 +105,9 @@ add_enctype(struct add_enctype_options*opt, int argc, char **argv) for (j = 0; j < n_etypes; ++j) { if (etypes[j] == key->key_data_type[0]) { + /* XXX Should this be an error? The admin can del_enctype... */ krb5_warnx(context, "enctype %d already exists", (int)etypes[j]); - free(new_key_data); goto out; } } @@ -115,7 +120,7 @@ add_enctype(struct add_enctype_options*opt, int argc, char **argv) memset(&new_key_data[n], 0, sizeof(new_key_data[n])); new_key_data[n].key_data_ver = 2; - new_key_data[n].key_data_kvno = 0; + new_key_data[n].key_data_kvno = princ.kvno; ret = krb5_generate_random_keyblock (context, etypes[i], &keyblock); if (ret) { @@ -157,6 +162,7 @@ add_enctype(struct add_enctype_options*opt, int argc, char **argv) if (ret) krb5_warn(context, ret, "kadm5_modify_principal"); out: + free(new_key_data); krb5_free_principal (context, princ_ent); kadm5_free_principal_ent(kadm_handle, &princ); out2: diff --git a/kadmin/ank.c b/kadmin/ank.c index 8846fa8b6..fba3450aa 100644 --- a/kadmin/ank.c +++ b/kadmin/ank.c @@ -34,28 +34,29 @@ #include "kadmin_locl.h" #include "kadmin-commands.h" -RCSID("$Id$"); +/* No useful password policies for namespaces */ +#define NSPOLICY "default" /* * fetch the default principal corresponding to `princ' */ static krb5_error_code -get_default (kadm5_server_context *context, +get_default (kadm5_server_context *contextp, krb5_principal princ, kadm5_principal_ent_t default_ent) { krb5_error_code ret; krb5_principal def_principal; - krb5_const_realm realm = krb5_principal_get_realm(context->context, princ); + krb5_const_realm realm = krb5_principal_get_realm(contextp->context, princ); - ret = krb5_make_principal (context->context, &def_principal, + ret = krb5_make_principal (contextp->context, &def_principal, realm, "default", NULL); if (ret) return ret; - ret = kadm5_get_principal (context, def_principal, default_ent, + ret = kadm5_get_principal (contextp, def_principal, default_ent, KADM5_PRINCIPAL_NORMAL_MASK); - krb5_free_principal (context->context, def_principal); + krb5_free_principal (contextp->context, def_principal); return ret; } @@ -65,25 +66,30 @@ get_default (kadm5_server_context *context, */ static krb5_error_code -add_one_principal (const char *name, - int rand_key, - int rand_password, - int use_defaults, - char *password, - krb5_key_data *key_data, - const char *max_ticket_life, - const char *max_renewable_life, - const char *attributes, - const char *expiration, - const char *pw_expiration) +add_one_principal(const char *name, + int rand_key, + int rand_password, + int use_defaults, + char *password, + char *policy, + size_t nkstuple, + krb5_key_salt_tuple *kstuple, + krb5_key_data *key_data, + const char *max_ticket_life, + const char *max_renewable_life, + const char *attributes, + const char *expiration, + const char *pw_expiration) { krb5_error_code ret; kadm5_principal_ent_rec princ, defrec; kadm5_principal_ent_rec *default_ent = NULL; krb5_principal princ_ent = NULL; + krb5_timestamp pw_expire; int mask = 0; int default_mask = 0; char pwbuf[1024]; + char *princ_name = NULL; memset(&princ, 0, sizeof(princ)); ret = krb5_parse_name(context, name, &princ_ent); @@ -91,12 +97,20 @@ add_one_principal (const char *name, krb5_warn(context, ret, "krb5_parse_name"); return ret; } + + if (rand_password) { + ret = krb5_unparse_name(context, princ_ent, &princ_name); + if (ret) { + krb5_warn(context, ret, "krb5_parse_name"); + goto out; + } + } princ.principal = princ_ent; mask |= KADM5_PRINCIPAL; ret = set_entry(context, &princ, &mask, max_ticket_life, max_renewable_life, - expiration, pw_expiration, attributes); + expiration, pw_expiration, attributes, policy); if (ret) goto out; @@ -124,13 +138,21 @@ add_one_principal (const char *name, random_password (pwbuf, sizeof(pwbuf)); password = pwbuf; } else if(password == NULL) { - char *princ_name; char *prompt; + int aret; - krb5_unparse_name(context, princ_ent, &princ_name); - asprintf (&prompt, "%s's Password: ", princ_name); - free (princ_name); - ret = UI_UTIL_read_pw_string (pwbuf, sizeof(pwbuf), prompt, 1); + ret = krb5_unparse_name(context, princ_ent, &princ_name); + if (ret) + goto out; + aret = asprintf (&prompt, "%s's Password: ", princ_name); + if (aret == -1) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "out of memory"); + goto out; + } + ret = UI_UTIL_read_pw_string (pwbuf, sizeof(pwbuf), prompt, + UI_UTIL_FLAG_VERIFY | + UI_UTIL_FLAG_VERIFY_SILENT); free (prompt); if (ret) { ret = KRB5_LIBOS_BADPWDMATCH; @@ -145,11 +167,13 @@ add_one_principal (const char *name, krb5_warn(context, ret, "kadm5_create_principal"); goto out; } - if(rand_key) { + /* Save requested password expiry before it's clobbered */ + pw_expire = princ.pw_expiration; + if (rand_key) { krb5_keyblock *new_keys; int n_keys, i; - ret = kadm5_randkey_principal(kadm_handle, princ_ent, - &new_keys, &n_keys); + ret = kadm5_randkey_principal_3(kadm_handle, princ_ent, 0, + nkstuple, kstuple, &new_keys, &n_keys); if(ret){ krb5_warn(context, ret, "kadm5_randkey_principal"); n_keys = 0; @@ -158,13 +182,26 @@ add_one_principal (const char *name, krb5_free_keyblock_contents(context, &new_keys[i]); if (n_keys > 0) free(new_keys); - kadm5_get_principal(kadm_handle, princ_ent, &princ, - KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES); + ret = kadm5_get_principal(kadm_handle, princ_ent, &princ, + KADM5_PRINCIPAL | KADM5_KVNO | + KADM5_ATTRIBUTES); + if (ret) { + krb5_warn(context, ret, "kadm5_get_principal"); + goto out; + } + krb5_free_principal(context, princ_ent); + princ_ent = princ.principal; princ.attributes &= (~KRB5_KDB_DISALLOW_ALL_TIX); + princ.pw_expiration = pw_expire; + /* + * Updating kvno w/o key data and vice-versa gives _kadm5_setup_entry() + * and _kadm5_set_keys2() headaches. But we used to, so we handle + * this in in those two functions. Might as well leave this code as + * it was then. + */ princ.kvno = 1; kadm5_modify_principal(kadm_handle, &princ, - KADM5_ATTRIBUTES | KADM5_KVNO); - kadm5_free_principal_ent(kadm_handle, &princ); + KADM5_PW_EXPIRATION | KADM5_ATTRIBUTES | KADM5_KVNO); } else if (key_data) { ret = kadm5_chpass_principal_with_key (kadm_handle, princ_ent, 3, key_data); @@ -173,23 +210,24 @@ add_one_principal (const char *name, } kadm5_get_principal(kadm_handle, princ_ent, &princ, KADM5_PRINCIPAL | KADM5_ATTRIBUTES); + krb5_free_principal(context, princ_ent); + princ_ent = princ.principal; princ.attributes &= (~KRB5_KDB_DISALLOW_ALL_TIX); - kadm5_modify_principal(kadm_handle, &princ, KADM5_ATTRIBUTES); - kadm5_free_principal_ent(kadm_handle, &princ); + princ.pw_expiration = pw_expire; + kadm5_modify_principal(kadm_handle, &princ, + KADM5_PW_EXPIRATION | KADM5_ATTRIBUTES); } else if (rand_password) { - char *princ_name; - - krb5_unparse_name(context, princ_ent, &princ_name); printf ("added %s with password \"%s\"\n", princ_name, password); - free (princ_name); } out: - if (princ_ent) - krb5_free_principal (context, princ_ent); + free(princ_name); + kadm5_free_principal_ent(kadm_handle, &princ); /* frees princ_ent */ if(default_ent) kadm5_free_principal_ent (kadm_handle, default_ent); - if (password != NULL) - memset (password, 0, strlen(password)); + if (password != NULL) { + size_t len = strlen(password); + memset_s(password, len, 0, len); + } return ret; } @@ -209,10 +247,12 @@ int add_new_key(struct add_options *opt, int argc, char **argv) { krb5_error_code ret = 0; - int i; - int num; + krb5_key_salt_tuple *kstuple = NULL; krb5_key_data key_data[3]; krb5_key_data *kdp = NULL; + const char *enctypes; + size_t i, nkstuple; + int num; num = 0; if (opt->random_key_flag) @@ -230,29 +270,46 @@ add_new_key(struct add_options *opt, int argc, char **argv) return 1; } + enctypes = opt->enctypes_string; + if (enctypes == NULL || enctypes[0] == '\0') + enctypes = krb5_config_get_string(context, NULL, "libdefaults", + "supported_enctypes", NULL); + if (enctypes == NULL || enctypes[0] == '\0') + enctypes = "aes128-cts-hmac-sha1-96"; + ret = krb5_string_to_keysalts2(context, enctypes, &nkstuple, &kstuple); + if (ret) { + fprintf(stderr, "enctype(s) unknown\n"); + return ret; + } + + if (opt->key_string) { const char *error; if (parse_des_key (opt->key_string, key_data, &error)) { - fprintf (stderr, "failed parsing key \"%s\": %s\n", - opt->key_string, error); + fprintf(stderr, "failed parsing key \"%s\": %s\n", + opt->key_string, error); + free(kstuple); return 1; } kdp = key_data; } for(i = 0; i < argc; i++) { - ret = add_one_principal (argv[i], - opt->random_key_flag, - opt->random_password_flag, - opt->use_defaults_flag, - opt->password_string, - kdp, - opt->max_ticket_life_string, - opt->max_renewable_life_string, - opt->attributes_string, - opt->expiration_time_string, - opt->pw_expiration_time_string); + ret = add_one_principal(argv[i], + opt->random_key_flag, + opt->random_password_flag, + opt->use_defaults_flag, + opt->password_string, + opt->policy_string, + nkstuple, + kstuple, + kdp, + opt->max_ticket_life_string, + opt->max_renewable_life_string, + opt->attributes_string, + opt->expiration_time_string, + opt->pw_expiration_time_string); if (ret) { krb5_warn (context, ret, "adding %s", argv[i]); break; @@ -262,5 +319,212 @@ add_new_key(struct add_options *opt, int argc, char **argv) int16_t dummy = 3; kadm5_free_key_data (kadm_handle, &dummy, key_data); } + free(kstuple); + return ret != 0; +} + +static krb5_error_code +kstuple2etypes(kadm5_principal_ent_rec *rec, + int *maskp, + size_t nkstuple, + krb5_key_salt_tuple *kstuple) +{ + krb5_error_code ret; + HDB_EncTypeList etypes; + krb5_data buf; + size_t len, i; + + etypes.len = 0; + if ((etypes.val = calloc(nkstuple, sizeof(etypes.val[0]))) == NULL) + return krb5_enomem(context); + for (i = 0; i < nkstuple; i++) + etypes.val[i] = kstuple[i].ks_enctype; + ASN1_MALLOC_ENCODE(HDB_EncTypeList, buf.data, buf.length, + &etypes, &len, ret); + if (ret == 0) + add_tl(rec, KRB5_TL_ETYPES, &buf); + free(etypes.val); + if (ret == 0) + (*maskp) |= KADM5_TL_DATA; + return ret; +} + +/* + * Add the namespace `name' to the database. + * Prompt for all data not given by the input parameters. + */ +static krb5_error_code +add_one_namespace(const char *name, + size_t nkstuple, + krb5_key_salt_tuple *kstuple, + const char *max_ticket_life, + const char *max_renewable_life, + const char *key_rotation_epoch, + const char *key_rotation_period, + const char *attributes) +{ + krb5_error_code ret; + kadm5_principal_ent_rec princ; + krb5_principal princ_ent = NULL; + int mask = 0; + int default_mask = 0; + HDB_extension ext; + krb5_data buf; + const char *comp0; + const char *comp1; + time_t kre; + char pwbuf[1024]; + krb5_deltat krp; + + if (!key_rotation_epoch) { + krb5_warnx(context, "key rotation epoch defaulted to \"now\""); + key_rotation_epoch = "now"; + } + if (!key_rotation_period) { + krb5_warnx(context, "key rotation period defaulted to \"5d\""); + key_rotation_period = "5d"; + } + if ((ret = str2time_t(key_rotation_epoch, &kre)) != 0) { + krb5_warn(context, ret, "invalid rotation epoch: %s", + key_rotation_epoch); + return ret; + } + if (ret == 0 && (ret = str2deltat(key_rotation_period, &krp)) != 0) { + krb5_warn(context, ret, "invalid rotation period: %s", + key_rotation_period); + return ret; + } + + if (ret == 0) { + memset(&princ, 0, sizeof(princ)); + princ.kvno = 1; + ret = krb5_parse_name(context, name, &princ_ent); + if (ret) + krb5_warn(context, ret, "krb5_parse_name"); + else + princ.principal = princ_ent; + } + if (ret != 0) + return ret; + + /* + * Check that namespace has exactly one component, and prepend + * WELLKNOWN/HOSTBASED-NAMESPACE + */ + if (krb5_principal_get_num_comp(context, princ_ent) != 2 + || (comp0 = krb5_principal_get_comp_string(context, princ_ent, 0)) == 0 + || (comp1 = krb5_principal_get_comp_string(context, princ_ent, 1)) == 0 + || *comp0 == 0 || *comp1 == 0 + || strcmp(comp0, "krbtgt") == 0) + krb5_warn(context, ret = EINVAL, + "namespaces must have exactly two non-empty components " + "like host-base principal names"); + if (ret == 0) + ret = krb5_principal_set_comp_string(context, princ_ent, 2, comp0); + if (ret == 0) + ret = krb5_principal_set_comp_string(context, princ_ent, 3, comp1); + if (ret == 0) + ret = krb5_principal_set_comp_string(context, princ_ent, 0, + "WELLKNOWN"); + if (ret == 0) + ret = krb5_principal_set_comp_string(context, princ_ent, 1, + HDB_WK_NAMESPACE); + + /* Set up initial key rotation extension */ + if (ret == 0) { + KeyRotation kr; + size_t size; + + /* Setup key rotation metadata in a convenient way */ + kr.flags = int2KeyRotationFlags(0); + kr.base_key_kvno = 1; + /* + * Avoid kvnos 0/1/2 which don't normally appear in fully created + * principals. + */ + kr.base_kvno = 3; + + /* XXX: Sanity check */ + kr.epoch = kre; + kr.period = krp; + + memset(&ext, 0, sizeof(ext)); + ext.mandatory = FALSE; + ext.data.element = choice_HDB_extension_data_key_rotation; + ext.data.u.key_rotation.len = 1; + ext.data.u.key_rotation.val = &kr; + + ASN1_MALLOC_ENCODE(HDB_extension, buf.data, buf.length, + &ext, &size, ret); + add_tl(&princ, KRB5_TL_EXTENSION, &buf); + mask |= KADM5_TL_DATA; + } + + if (ret == 0) { + mask |= KADM5_PRINCIPAL | KADM5_KVNO; + + ret = set_entry(context, &princ, &mask, + max_ticket_life, max_renewable_life, + "never", "never", attributes, NSPOLICY); + } + if (ret == 0) + ret = edit_entry(&princ, &mask, NULL, default_mask); + + if (ret == 0) + ret = kstuple2etypes(&princ, &mask, nkstuple, kstuple); + + /* XXX Shouldn't need a password for this */ + random_password(pwbuf, sizeof(pwbuf)); + if (ret == 0) { + ret = kadm5_create_principal_3(kadm_handle, &princ, mask, + nkstuple, kstuple, pwbuf); + if (ret) + krb5_warn(context, ret, "kadm5_create_principal_3"); + } + + kadm5_free_principal_ent(kadm_handle, &princ); /* frees princ_ent */ + memset(pwbuf, 0, sizeof(pwbuf)); + return ret; +} + +int +add_new_namespace(struct add_namespace_options *opt, int argc, char **argv) +{ + krb5_error_code ret = 0; + krb5_key_salt_tuple *kstuple = NULL; + const char *enctypes; + size_t i, nkstuple; + + if (argc < 1) { + fprintf(stderr, "at least one namespace name required\n"); + return 1; + } + + enctypes = opt->enctypes_string; + if (enctypes == NULL || enctypes[0] == '\0') + enctypes = krb5_config_get_string(context, NULL, "libdefaults", + "supported_enctypes", NULL); + if (enctypes == NULL || enctypes[0] == '\0') + enctypes = "aes128-cts-hmac-sha1-96"; + ret = krb5_string_to_keysalts2(context, enctypes, &nkstuple, &kstuple); + if (ret) { + fprintf(stderr, "enctype(s) unknown\n"); + return ret; + } + + for (i = 0; i < argc; i++) { + ret = add_one_namespace(argv[i], nkstuple, kstuple, + opt->max_ticket_life_string, + opt->max_renewable_life_string, + opt->key_rotation_epoch_string, + opt->key_rotation_period_string, + opt->attributes_string); + if (ret) { + krb5_warn(context, ret, "adding namespace %s", argv[i]); + break; + } + } + + free(kstuple); return ret != 0; } diff --git a/kadmin/check.c b/kadmin/check.c index 16a65a7fe..7a4350ada 100644 --- a/kadmin/check.c +++ b/kadmin/check.c @@ -38,8 +38,6 @@ #include "kadmin_locl.h" #include "kadmin-commands.h" -RCSID("$Id$"); - static int get_check_entry(const char *name, kadm5_principal_ent_rec *ent) { @@ -53,7 +51,7 @@ get_check_entry(const char *name, kadm5_principal_ent_rec *ent) } memset(ent, 0, sizeof(*ent)); - ret = kadm5_get_principal(kadm_handle, principal, ent, 0); + ret = kadm5_get_principal(kadm_handle, principal, ent, KADM5_ATTRIBUTES); krb5_free_principal(context, principal); if(ret) return 1; @@ -75,7 +73,7 @@ do_check_entry(krb5_principal principal, void *data) return 1; memset (&princ, 0, sizeof(princ)); - ret = kadm5_get_principal(kadm_handle, principal, &princ, + ret = kadm5_get_principal(data, principal, &princ, KADM5_PRINCIPAL | KADM5_KEY_DATA); if(ret) { krb5_warn(context, ret, "Failed to get principal: %s", name); @@ -88,16 +86,16 @@ do_check_entry(krb5_principal principal, void *data) ret = krb5_enctype_keysize(context, princ.key_data[i].key_data_type[0], &keysize); - if (ret == 0 && keysize != princ.key_data[i].key_data_length[0]) { + if (ret == 0 && keysize != (size_t)princ.key_data[i].key_data_length[0]) { krb5_warnx(context, - "Principal %s enctype %d, wrong length: %lu\n", + "Principal %s enctype %d, wrong length: %d\n", name, princ.key_data[i].key_data_type[0], - (unsigned long)princ.key_data[i].key_data_length); + princ.key_data[i].key_data_length[0]); } } free(name); - kadm5_free_principal_ent(kadm_handle, &princ); + kadm5_free_principal_ent(data, &princ); return 0; } @@ -108,6 +106,7 @@ check(void *opt, int argc, char **argv) kadm5_principal_ent_rec ent; krb5_error_code ret; char *realm = NULL, *p, *p2; + void *inner_kadm_handle = NULL; int found; if (argc == 0) { @@ -137,8 +136,9 @@ check(void *opt, int argc, char **argv) ret = get_check_entry(p, &ent); if (ret) { - printf("%s doesn't exist, are you sure %s is a realm in your database", - p, realm); + fprintf(stderr, + "%s does not exist, are you sure %s is a realm in your database?\n", + p, realm); free(p); goto fail; } @@ -157,8 +157,9 @@ check(void *opt, int argc, char **argv) ret = get_check_entry(p, &ent); if (ret) { - printf("%s doesn't exist, " - "there is no way to do remote administration", p); + fprintf(stderr, + "%s does not exist, there is no way to do remote administration.\n", + p); free(p); goto fail; } @@ -177,8 +178,9 @@ check(void *opt, int argc, char **argv) ret = get_check_entry(p, &ent); if (ret) { - printf("%s doesn't exist, " - "there is no way to do change password", p); + fprintf(stderr, + "%s does not exist, there is no way to do change password.\n", + p); free(p); goto fail; } @@ -186,6 +188,35 @@ check(void *opt, int argc, char **argv) kadm5_free_principal_ent(kadm_handle, &ent); + /* + * Check default@REALM + * + * Check that disallow-all-tix is set on the default principal + * (or that the entry does not exist) + */ + + if (asprintf(&p, "default@%s", realm) == -1) { + krb5_warn(context, errno, "asprintf"); + goto fail; + } + + ret = get_check_entry(p, &ent); + if (ret == 0) { + if ((ent.attributes & KRB5_KDB_DISALLOW_ALL_TIX) == 0) { + fprintf(stderr, "default template entry is not disabled\n"); + ret = EINVAL; + } + kadm5_free_principal_ent(kadm_handle, &ent); + + } else { + ret = 0; + } + + free(p); + + if (ret) + goto fail; + /* * Check for duplicate afs keys */ @@ -227,7 +258,15 @@ check(void *opt, int argc, char **argv) } } - foreach_principal("*", do_check_entry, "check", NULL); + ret = kadm5_dup_context(kadm_handle, &inner_kadm_handle); + if (ret == 0) + ret = foreach_principal("*", do_check_entry, "check", inner_kadm_handle); + if (inner_kadm_handle) + kadm5_destroy(inner_kadm_handle); + if (ret) { + krb5_warn(context, ret, "Could not iterate principals in realm"); + goto fail; + } free(realm); return 0; diff --git a/kadmin/cpw.c b/kadmin/cpw.c index 76dedb231..139731777 100644 --- a/kadmin/cpw.c +++ b/kadmin/cpw.c @@ -34,24 +34,25 @@ #include "kadmin_locl.h" #include "kadmin-commands.h" -RCSID("$Id$"); - struct cpw_entry_data { + int keepold; int random_key; int random_password; char *password; krb5_key_data *key_data; + void *kadm_handle; }; static int -set_random_key (krb5_principal principal) +set_random_key(void *dup_kadm_handle, krb5_principal principal, int keepold) { krb5_error_code ret; int i; krb5_keyblock *keys; int num_keys; - ret = kadm5_randkey_principal(kadm_handle, principal, &keys, &num_keys); + ret = kadm5_randkey_principal_3(dup_kadm_handle, principal, keepold, 0, + NULL, &keys, &num_keys); if(ret) return ret; for(i = 0; i < num_keys; i++) @@ -61,58 +62,75 @@ set_random_key (krb5_principal principal) } static int -set_random_password (krb5_principal principal) +set_random_password(void *dup_kadm_handle, + krb5_principal principal, + int keepold) { krb5_error_code ret; char pw[128]; + char *princ_name; - random_password (pw, sizeof(pw)); - ret = kadm5_chpass_principal(kadm_handle, principal, pw); - if (ret == 0) { - char *princ_name; - - krb5_unparse_name(context, principal, &princ_name); + ret = krb5_unparse_name(context, principal, &princ_name); + if (ret) + return ret; + random_password(pw, sizeof(pw)); + ret = kadm5_chpass_principal_3(dup_kadm_handle, principal, keepold, 0, + NULL, pw); + if (ret == 0) printf ("%s's password set to \"%s\"\n", princ_name, pw); - free (princ_name); - } - memset (pw, 0, sizeof(pw)); + free(princ_name); + memset_s(pw, sizeof(pw), 0, sizeof(pw)); return ret; } static int -set_password (krb5_principal principal, char *password) +set_password(void *dup_kadm_handle, + krb5_principal principal, + char *password, + int keepold) { krb5_error_code ret = 0; char pwbuf[128]; + int aret; if(password == NULL) { char *princ_name; char *prompt; - krb5_unparse_name(context, principal, &princ_name); - asprintf(&prompt, "%s's Password: ", princ_name); + ret = krb5_unparse_name(context, principal, &princ_name); + if (ret) + return ret; + aret = asprintf(&prompt, "%s's Password: ", princ_name); free (princ_name); - ret = UI_UTIL_read_pw_string(pwbuf, sizeof(pwbuf), prompt, 1); + if (aret == -1) + return ENOMEM; + ret = UI_UTIL_read_pw_string(pwbuf, sizeof(pwbuf), prompt, + UI_UTIL_FLAG_VERIFY | + UI_UTIL_FLAG_VERIFY_SILENT); free (prompt); if(ret){ - return 0; /* XXX error code? */ + return KRB5_LIBOS_BADPWDMATCH; } password = pwbuf; } if(ret == 0) - ret = kadm5_chpass_principal(kadm_handle, principal, password); - memset(pwbuf, 0, sizeof(pwbuf)); + ret = kadm5_chpass_principal_3(dup_kadm_handle, principal, keepold, 0, + NULL, password); + memset_s(pwbuf, sizeof(pwbuf), 0, sizeof(pwbuf)); return ret; } static int -set_key_data (krb5_principal principal, krb5_key_data *key_data) +set_key_data(void *dup_kadm_handle, + krb5_principal principal, + krb5_key_data *key_data, + int keepold) { krb5_error_code ret; - ret = kadm5_chpass_principal_with_key (kadm_handle, principal, - 3, key_data); + ret = kadm5_chpass_principal_with_key_3(dup_kadm_handle, principal, keepold, + 3, key_data); return ret; } @@ -122,13 +140,13 @@ do_cpw_entry(krb5_principal principal, void *data) struct cpw_entry_data *e = data; if (e->random_key) - return set_random_key (principal); + return set_random_key(e->kadm_handle, principal, e->keepold); else if (e->random_password) - return set_random_password (principal); + return set_random_password(e->kadm_handle, principal, e->keepold); else if (e->key_data) - return set_key_data (principal, e->key_data); + return set_key_data(e->kadm_handle, principal, e->key_data, e->keepold); else - return set_password (principal, e->password); + return set_password(e->kadm_handle, principal, e->password, e->keepold); } int @@ -138,13 +156,42 @@ cpw_entry(struct passwd_options *opt, int argc, char **argv) int i; struct cpw_entry_data data; int num; + int16_t n_key_data = 0; krb5_key_data key_data[3]; + memset(key_data, 0, sizeof(key_data)); + data.kadm_handle = NULL; + ret = kadm5_dup_context(kadm_handle, &data.kadm_handle); + if (ret) + krb5_err(context, 1, ret, "Could not duplicate kadmin connection"); data.random_key = opt->random_key_flag; data.random_password = opt->random_password_flag; data.password = opt->password_string; data.key_data = NULL; + /* + * --keepold is the the default, and it should mean "prune all old keys not + * needed to decrypt extant tickets". + */ + num = 0; + data.keepold = 1; + if (opt->keepold_flag) { + data.keepold = 1; + num++; + } + if (opt->keepallold_flag) { + data.keepold = 2; + num++; + } + if (opt->pruneall_flag) { + data.keepold = 0; + num++; + } + if (num > 1) { + fprintf(stderr, "use only one of --keepold, --keepallold, and --pruneall\n"); + return 1; + } + num = 0; if (data.random_key) ++num; @@ -160,7 +207,7 @@ cpw_entry(struct passwd_options *opt, int argc, char **argv) "--random-key, --random-password, --password, --key\n"); return 1; } - + if (opt->key_string) { const char *error; @@ -169,16 +216,17 @@ cpw_entry(struct passwd_options *opt, int argc, char **argv) opt->key_string, error); return 1; } + n_key_data = sizeof(key_data)/sizeof(key_data[0]); data.key_data = key_data; } for(i = 0; i < argc; i++) ret = foreach_principal(argv[i], do_cpw_entry, "cpw", &data); - if (data.key_data) { - int16_t dummy; - kadm5_free_key_data (kadm_handle, &dummy, key_data); - } + kadm5_destroy(data.kadm_handle); + + if (opt->key_string) + kadm5_free_key_data(kadm_handle, &n_key_data, key_data); return ret != 0; } diff --git a/kadmin/del.c b/kadmin/del.c index 470471db8..320fe6e8e 100644 --- a/kadmin/del.c +++ b/kadmin/del.c @@ -34,12 +34,10 @@ #include "kadmin_locl.h" #include "kadmin-commands.h" -RCSID("$Id$"); - static int do_del_entry(krb5_principal principal, void *data) { - return kadm5_delete_principal(kadm_handle, principal); + return kadm5_delete_principal(data, principal); } int @@ -47,11 +45,176 @@ del_entry(void *opt, int argc, char **argv) { int i; krb5_error_code ret = 0; + void *dup_kadm_handle = NULL; - for(i = 0; i < argc; i++) { - ret = foreach_principal(argv[i], do_del_entry, "del", NULL); - if (ret) - break; - } + ret = kadm5_dup_context(kadm_handle, &dup_kadm_handle); + + for (i = 0; ret == 0 && i < argc; i++) + ret = foreach_principal(argv[i], do_del_entry, "del", dup_kadm_handle); + + if (dup_kadm_handle) + kadm5_destroy(dup_kadm_handle); return ret != 0; } + +static int +do_del_ns_entry(krb5_principal nsp, void *data) +{ + krb5_error_code ret; + krb5_principal p = NULL; + const char *comp0 = krb5_principal_get_comp_string(context, nsp, 0); + const char *comp1 = krb5_principal_get_comp_string(context, nsp, 1); + + if (krb5_principal_get_num_comp(context, nsp) != 2) { + char *unsp = NULL; + + ret = krb5_unparse_name(context, nsp, &unsp); + krb5_warn(context, ret, + "Not a valid namespace name (component count is not 2): %s", + unsp ? unsp : ""); + free(unsp); + return EINVAL; + } + + ret = krb5_make_principal(context, &p, + krb5_principal_get_realm(context, nsp), + "WELLKNOWN", HDB_WK_NAMESPACE, NULL); + if (ret == 0) + ret = krb5_principal_set_comp_string(context, p, 2, comp0); + if (ret == 0) + ret = krb5_principal_set_comp_string(context, p, 3, comp1); + if (ret == 0) + ret = kadm5_delete_principal(kadm_handle, p); + krb5_free_principal(context, p); + return ret; +} + +int +del_namespace(void *opt, int argc, char **argv) +{ + int i; + krb5_error_code ret = 0; + void *dup_kadm_handle = NULL; + + ret = kadm5_dup_context(kadm_handle, &dup_kadm_handle); + for (i = 0; ret == 0 && i < argc; i++) + ret = foreach_principal(argv[i], do_del_ns_entry, "del_ns", + dup_kadm_handle); + if (dup_kadm_handle) + kadm5_destroy(dup_kadm_handle); + return ret != 0; +} + +int +del_alias(void *opt, int argc, char **argv) +{ + krb5_error_code ret; + size_t i; + + + if (argc < 1) { + krb5_warnx(context, "No aliases given"); + return 1; + } + + for (; argc; argc--, argv++) { + kadm5_principal_ent_rec princ; + krb5_principal p; + HDB_Ext_Aliases *a; + HDB_extension ext; + krb5_tl_data *tl; + krb5_data d; + + if ((ret = krb5_parse_name(context, argv[0], &p))) { + krb5_warn(context, ret, "Invalid principal: %s", argv[0]); + return 1; + } + + memset(&princ, 0, sizeof(princ)); + ret = kadm5_get_principal(kadm_handle, p, &princ, + KADM5_PRINCIPAL_NORMAL_MASK | KADM5_TL_DATA); + if (ret) { + krb5_warn(context, ret, "Principal alias not found %s", argv[0]); + continue; + } + + if (krb5_principal_compare(context, p, princ.principal)) { + krb5_warn(context, ret, "Not deleting principal %s because it is " + "not an alias; use 'delete' to delete the principal", + argv[0]); + continue; + } + + a = &ext.data.u.aliases; + a->case_insensitive = 0; + a->aliases.len = 0; + a->aliases.val = 0; + if ((tl = get_tl(&princ, KRB5_TL_ALIASES)) == NULL) { + krb5_warnx(context, "kadm5_get_principal() found principal %s but " + "not its aliases", argv[0]); + kadm5_free_principal_ent(kadm_handle, &princ); + krb5_free_principal(context, p); + return 1; + } + + ret = decode_HDB_Ext_Aliases(tl->tl_data_contents, tl->tl_data_length, + a, NULL); + if (ret) { + krb5_warn(context, ret, "Principal alias list could not be decoded"); + kadm5_free_principal_ent(kadm_handle, &princ); + krb5_free_principal(context, p); + return 1; + } + + /* + * Remove alias, but also, don't assume it appears only once in aliases + * list. + */ + i = 0; + while (i < a->aliases.len) { + if (!krb5_principal_compare(context, p, &a->aliases.val[i])) { + i++; + continue; + } + free_Principal(&a->aliases.val[i]); + if (i + 1 < a->aliases.len) + memmove(&a->aliases.val[i], + &a->aliases.val[i + 1], + sizeof(a->aliases.val[i]) * (a->aliases.len - (i + 1))); + if (a->aliases.len) + a->aliases.len--; + continue; + } + + krb5_data_zero(&d); + ext.data.element = choice_HDB_extension_data_aliases; + ext.mandatory = 0; + if (ret == 0) + ASN1_MALLOC_ENCODE(HDB_extension, d.data, d.length, &ext, &i, ret); + free_HDB_Ext_Aliases(a); + if (ret == 0) { + int16_t len = d.length; + + if (len < 0 || d.length != (size_t)len) { + krb5_warnx(context, "Too many aliases; does not fit in 32767 bytes"); + ret = EOVERFLOW; + } else { + add_tl(&princ, KRB5_TL_EXTENSION, &d); + krb5_data_zero(&d); + } + } + if (ret == 0) { + ret = kadm5_modify_principal(kadm_handle, &princ, + KADM5_PRINCIPAL | KADM5_TL_DATA); + if (ret) + krb5_warn(context, ret, "kadm5_modify_principal"); + } + + kadm5_free_principal_ent(kadm_handle, &princ); + krb5_free_principal(context, p); + krb5_data_free(&d); + p = NULL; + } + + return ret == 0 ? 0 : 1; +} diff --git a/kadmin/del_enctype.c b/kadmin/del_enctype.c index f8509e2fe..c32ce14c1 100644 --- a/kadmin/del_enctype.c +++ b/kadmin/del_enctype.c @@ -34,8 +34,6 @@ #include "kadmin_locl.h" #include "kadmin-commands.h" -RCSID("$Id$"); - /* * del_enctype principal enctypes... */ @@ -51,6 +49,7 @@ del_enctype(void *opt, int argc, char **argv) krb5_key_data *new_key_data; int n_etypes; krb5_enctype *etypes; + krb5_key_data *key; memset (&princ, 0, sizeof(princ)); princ_name = argv[0]; @@ -83,21 +82,27 @@ del_enctype(void *opt, int argc, char **argv) goto out2; } + if (kadm5_all_keys_are_bogus(princ.n_key_data, princ.key_data)) { + krb5_warnx(context, "user lacks get-keys privilege"); + goto out; + } + new_key_data = malloc(princ.n_key_data * sizeof(*new_key_data)); - if (new_key_data == NULL) { + if (new_key_data == NULL && princ.n_key_data != 0) { krb5_warnx (context, "out of memory"); goto out; } for (i = 0, j = 0; i < princ.n_key_data; ++i) { - krb5_key_data *key = &princ.key_data[i]; int docopy = 1; + key = &princ.key_data[i]; - for (k = 0; k < n_etypes; ++k) + for (k = 0; k < n_etypes; ++k) { if (etypes[k] == key->key_data_type[0]) { docopy = 0; break; } + } if (docopy) { new_key_data[j++] = *key; } else { @@ -108,6 +113,10 @@ del_enctype(void *opt, int argc, char **argv) } free (princ.key_data); + if (j == 0) { + free(new_key_data); + new_key_data = NULL; + } princ.n_key_data = j; princ.key_data = new_key_data; diff --git a/kadmin/dump.c b/kadmin/dump.c index 29d2b2706..0f2ed7445 100644 --- a/kadmin/dump.c +++ b/kadmin/dump.c @@ -35,8 +35,6 @@ #include "kadmin-commands.h" #include -RCSID("$Id$"); - extern int local_flag; int @@ -44,32 +42,42 @@ dump(struct dump_options *opt, int argc, char **argv) { krb5_error_code ret; FILE *f; + struct hdb_print_entry_arg parg; HDB *db = NULL; - if(!local_flag) { + if (!local_flag) { krb5_warnx(context, "dump is only available in local (-l) mode"); return 0; } db = _kadm5_s_get_db(kadm_handle); - if(argc == 0) + if (argc == 0) f = stdout; else f = fopen(argv[0], "w"); - if(f == NULL) { + if (f == NULL) { krb5_warn(context, errno, "open: %s", argv[0]); goto out; } ret = db->hdb_open(context, db, O_RDONLY, 0600); - if(ret) { + if (ret) { krb5_warn(context, ret, "hdb_open"); goto out; } + if (!opt->format_string || strcmp(opt->format_string, "Heimdal") == 0) { + parg.fmt = HDB_DUMP_HEIMDAL; + } else if (opt->format_string && strcmp(opt->format_string, "MIT") == 0) { + parg.fmt = HDB_DUMP_MIT; + fprintf(f, "kdb5_util load_dump version 5\n"); /* 5||6, either way */ + } else { + krb5_errx(context, 1, "Supported dump formats: Heimdal and MIT"); + } + parg.out = f; hdb_foreach(context, db, opt->decrypt_flag ? HDB_F_DECRYPT : 0, - hdb_print_entry, f); + hdb_print_entry, &parg); db->hdb_close(context, db); out: diff --git a/kadmin/ext.c b/kadmin/ext.c index 3f014ee19..5a8281a09 100644 --- a/kadmin/ext.c +++ b/kadmin/ext.c @@ -34,10 +34,13 @@ #include "kadmin_locl.h" #include "kadmin-commands.h" -RCSID("$Id$"); - struct ext_keytab_data { krb5_keytab keytab; + int keep; + int random_key_flag; + size_t nkstuple; + krb5_key_salt_tuple *kstuple; + void *kadm_handle; }; static int @@ -48,43 +51,77 @@ do_ext_keytab(krb5_principal principal, void *data) struct ext_keytab_data *e = data; krb5_keytab_entry *keys = NULL; krb5_keyblock *k = NULL; - int i, n_k; + size_t i; + int n_k = 0; + uint32_t mask; + char *unparsed = NULL; - ret = kadm5_get_principal(kadm_handle, principal, &princ, - KADM5_PRINCIPAL|KADM5_KVNO|KADM5_KEY_DATA); - if(ret) + mask = KADM5_PRINCIPAL; + if (!e->random_key_flag) + mask |= KADM5_KVNO | KADM5_KEY_DATA; + + ret = kadm5_get_principal(e->kadm_handle, principal, &princ, mask); + if (ret) return ret; - if (princ.n_key_data) { - keys = malloc(sizeof(*keys) * princ.n_key_data); + ret = krb5_unparse_name(context, principal, &unparsed); + if (ret) + goto out; + + if (!e->random_key_flag) { + if (princ.n_key_data == 0) { + krb5_warnx(context, "principal has no keys, or user lacks " + "get-keys privilege for %s", unparsed); + goto out; + } + /* + * kadmin clients and servers from master between 1.5 and 1.6 + * can have corrupted a principal's keys in the HDB. If some + * are bogus but not all are, then that must have happened. + * + * If all keys are bogus then the server may be a pre-1.6, + * post-1.5 server and the client lacks get-keys privilege, or + * the keys are corrupted. We can't tell here. + */ + if (kadm5_all_keys_are_bogus(princ.n_key_data, princ.key_data)) { + krb5_warnx(context, "user lacks get-keys privilege for %s", + unparsed); + goto out; + } + if (kadm5_some_keys_are_bogus(princ.n_key_data, princ.key_data)) { + krb5_warnx(context, "some keys for %s are corrupted in the HDB", + unparsed); + } + keys = calloc(princ.n_key_data, sizeof(*keys)); if (keys == NULL) { - kadm5_free_principal_ent(kadm_handle, &princ); - krb5_clear_error_message(context); - return ENOMEM; + ret = krb5_enomem(context); + goto out; } for (i = 0; i < princ.n_key_data; i++) { krb5_key_data *kd = &princ.key_data[i]; + /* Don't extract bogus keys */ + if (kadm5_all_keys_are_bogus(1, kd)) + continue; + keys[i].principal = princ.principal; keys[i].vno = kd->key_data_kvno; keys[i].keyblock.keytype = kd->key_data_type[0]; keys[i].keyblock.keyvalue.length = kd->key_data_length[0]; keys[i].keyblock.keyvalue.data = kd->key_data_contents[0]; keys[i].timestamp = time(NULL); + n_k++; } + } else if (e->random_key_flag) { + ret = kadm5_randkey_principal_3(e->kadm_handle, principal, e->keep, + e->nkstuple, e->kstuple, &k, &n_k); + if (ret) + goto out; - n_k = princ.n_key_data; - } else { - ret = kadm5_randkey_principal(kadm_handle, principal, &k, &n_k); - if (ret) { - kadm5_free_principal_ent(kadm_handle, &princ); - return ret; - } - keys = malloc(sizeof(*keys) * n_k); + keys = calloc(n_k, sizeof(*keys)); if (keys == NULL) { - kadm5_free_principal_ent(kadm_handle, &princ); - krb5_clear_error_message(context); - return ENOMEM; + ret = krb5_enomem(context); + goto out; } for (i = 0; i < n_k; i++) { keys[i].principal = principal; @@ -94,28 +131,59 @@ do_ext_keytab(krb5_principal principal, void *data) } } - for(i = 0; i < n_k; i++) { + if (n_k == 0) + krb5_warn(context, ret, "no keys written to keytab for %s", unparsed); + + for (i = 0; i < n_k; i++) { ret = krb5_kt_add_entry(context, e->keytab, &keys[i]); - if(ret) - krb5_warn(context, ret, "krb5_kt_add_entry(%d)", i); + if (ret) + krb5_warn(context, ret, "krb5_kt_add_entry(%lu)", (unsigned long)i); } + out: + kadm5_free_principal_ent(e->kadm_handle, &princ); if (k) { - memset(k, 0, n_k * sizeof(*k)); + for (i = 0; i < n_k; i++) + memset(k[i].keyvalue.data, 0, k[i].keyvalue.length); free(k); } - if (keys) - free(keys); - kadm5_free_principal_ent(kadm_handle, &princ); - return 0; + free(unparsed); + free(keys); + return ret; } int ext_keytab(struct ext_keytab_options *opt, int argc, char **argv) { krb5_error_code ret; - int i; struct ext_keytab_data data; + const char *enctypes; + size_t i; + + data.kadm_handle = NULL; + ret = kadm5_dup_context(kadm_handle, &data.kadm_handle); + if (ret) + krb5_err(context, 1, ret, "Could not duplicate kadmin connection"); + data.random_key_flag = opt->random_key_flag; + data.keep = 1; + i = 0; + if (opt->keepallold_flag) { + data.keep = 2; + i++; + } + if (opt->keepold_flag) { + data.keep = 1; + i++; + } + if (opt->pruneall_flag) { + data.keep = 0; + i++; + } + if (i > 1) { + fprintf(stderr, + "use only one of --keepold, --keepallold, or --pruneall\n"); + return EINVAL; + } if (opt->keytab_string == NULL) ret = krb5_kt_default(context, &data.keytab); @@ -126,6 +194,19 @@ ext_keytab(struct ext_keytab_options *opt, int argc, char **argv) krb5_warn(context, ret, "krb5_kt_resolve"); return 1; } + enctypes = opt->enctypes_string; + if (enctypes == NULL || enctypes[0] == '\0') + enctypes = krb5_config_get_string(context, NULL, "libdefaults", + "supported_enctypes", NULL); + if (enctypes == NULL || enctypes[0] == '\0') + enctypes = "aes128-cts-hmac-sha1-96"; + ret = krb5_string_to_keysalts2(context, enctypes, &data.nkstuple, + &data.kstuple); + if (ret) { + fprintf(stderr, "enctype(s) unknown\n"); + krb5_kt_close(context, data.keytab); + return ret; + } for(i = 0; i < argc; i++) { ret = foreach_principal(argv[i], do_ext_keytab, "ext", &data); @@ -133,7 +214,8 @@ ext_keytab(struct ext_keytab_options *opt, int argc, char **argv) break; } + kadm5_destroy(data.kadm_handle); krb5_kt_close(context, data.keytab); - + free(data.kstuple); return ret != 0; } diff --git a/kadmin/get.c b/kadmin/get.c index be65d8dbf..1942d6389 100644 --- a/kadmin/get.c +++ b/kadmin/get.c @@ -36,8 +36,6 @@ #include #include -RCSID("$Id$"); - static struct field_name { const char *fieldname; unsigned int fieldvalue; @@ -62,11 +60,14 @@ static struct field_name { { "last_failed", KADM5_LAST_FAILED, 0, 0, "Last fail", "Last failed login", 0 }, { "fail_auth_count", KADM5_FAIL_AUTH_COUNT, 0, 0, "Fail count", "Failed login count", RTBL_ALIGN_RIGHT }, { "policy", KADM5_POLICY, 0, 0, "Policy", "Policy", 0 }, - { "keytypes", KADM5_KEY_DATA, 0, KADM5_PRINCIPAL, "Keytypes", "Keytypes", 0 }, + { "keytypes", KADM5_KEY_DATA, 0, KADM5_PRINCIPAL | KADM5_KVNO, "Keytypes", "Keytypes", 0 }, + { "server-keytypes", KADM5_TL_DATA, KRB5_TL_ETYPES, 0, "Server keytypes", "Supported keytypes (servers)", 0 }, { "password", KADM5_TL_DATA, KRB5_TL_PASSWORD, KADM5_KEY_DATA, "Password", "Password", 0 }, { "pkinit-acl", KADM5_TL_DATA, KRB5_TL_PKINIT_ACL, 0, "PK-INIT ACL", "PK-INIT ACL", 0 }, { "aliases", KADM5_TL_DATA, KRB5_TL_ALIASES, 0, "Aliases", "Aliases", 0 }, - { NULL } + { "hist-kvno-diff-clnt", KADM5_TL_DATA, KRB5_TL_HIST_KVNO_DIFF_CLNT, 0, "Clnt hist keys", "Historic keys allowed for client", 0 }, + { "hist-kvno-diff-svc", KADM5_TL_DATA, KRB5_TL_HIST_KVNO_DIFF_SVC, 0, "Svc hist keys", "Historic keys allowed for service", 0 }, + { NULL, 0, 0, 0, NULL, NULL, 0 } }; struct field_info { @@ -81,6 +82,10 @@ struct get_entry_data { uint32_t mask; uint32_t extra_mask; struct field_info *chead, **ctail; + const char *krb5_config_fname; + void *kadm_handle; + uint32_t n; + int upto; }; static int @@ -112,9 +117,9 @@ add_column(struct get_entry_data *data, struct field_name *ff, const char *heade static int cmp_salt (const krb5_salt *salt, const krb5_key_data *k) { - if (salt->salttype != k->key_data_type[1]) + if (salt->salttype != (size_t)k->key_data_type[1]) return 1; - if (salt->saltvalue.length != k->key_data_length[1]) + if (salt->saltvalue.length != (size_t)k->key_data_length[1]) return 1; return memcmp (salt->saltvalue.data, k->key_data_contents[1], salt->saltvalue.length); @@ -125,12 +130,17 @@ format_keytype(krb5_key_data *k, krb5_salt *def_salt, char *buf, size_t buf_len) { krb5_error_code ret; char *s; + int aret; + buf[0] = '\0'; ret = krb5_enctype_to_string (context, k->key_data_type[0], &s); - if (ret) - asprintf (&s, "unknown(%d)", k->key_data_type[0]); + if (ret) { + aret = asprintf (&s, "unknown(%d)", k->key_data_type[0]); + if (aret == -1) + return; /* Nothing to do here, we have no way to pass the err */ + } strlcpy(buf, s, buf_len); free(s); @@ -140,28 +150,91 @@ format_keytype(krb5_key_data *k, krb5_salt *def_salt, char *buf, size_t buf_len) k->key_data_type[0], k->key_data_type[1], &s); - if (ret) - asprintf (&s, "unknown(%d)", k->key_data_type[1]); + if (ret) { + aret = asprintf (&s, "unknown(%d)", k->key_data_type[1]); + if (aret == -1) + return; /* Again, nothing else to do... */ + } strlcat(buf, s, buf_len); free(s); + aret = 0; if (cmp_salt(def_salt, k) == 0) s = strdup(""); else if(k->key_data_length[1] == 0) s = strdup("()"); else - asprintf (&s, "(%.*s)", k->key_data_length[1], - (char *)k->key_data_contents[1]); + aret = asprintf (&s, "(%.*s)", k->key_data_length[1], + (char *)k->key_data_contents[1]); + if (aret == -1 || s == NULL) + return; /* Again, nothing else we can do... */ strlcat(buf, s, buf_len); free(s); - + aret = asprintf (&s, "[%d]", k->key_data_kvno); + if (aret == -1) + return; strlcat(buf, ")", buf_len); + + strlcat(buf, s, buf_len); + free(s); +} + +static int +is_special_file(const char *fname) +{ +#ifdef WIN32 + if (strcasecmp(fname, "con") == 0 || strcasecmp(fname, "nul") == 0 || + strcasecmp(fname, "aux") == 0 || strcasecmp(fname, "prn") == 0) + return 1; + if ((strncasecmp(fname, "com", sizeof("com") - 1) == 0 || + strncasecmp(fname, "lpt", sizeof("lpt") - 1) == 0) && + fname[sizeof("lpt")] >= '0' && fname[sizeof("lpt")] <= '9' && + fname[sizeof("lpt") + 1] == '\0') + return 1; +#else + if (strncmp(fname, "/dev/", sizeof("/dev/") - 1) == 0) + return 1; +#endif + return 0; +} + +static char * +write_krb5_config(krb5_tl_data *tl, + const char *fn, + uint32_t i) +{ + char *s = NULL; + FILE *f = NULL; + + if (fn == NULL) + return NULL; + if (i == 0 || is_special_file(fn)) + s = strdup(fn); + else if (asprintf(&s, "%s-%u", fn, i) == -1) + s = NULL; + if (s == NULL) + krb5_err(context, 1, errno, "Out of memory"); + + /* rk_dumpdata() doesn't allow error checking :( */ + if ((f = fopen(s, "w")) && + fwrite(tl->tl_data_contents, tl->tl_data_length, 1, f) != 1) + krb5_warn(context, errno, "Could not write to %s", fn); + if (f && fclose(f)) + krb5_warn(context, errno, "Could not write to %s", fn); + return s; } static void -format_field(kadm5_principal_ent_t princ, unsigned int field, - unsigned int subfield, char *buf, size_t buf_len, int condensed) +format_field(struct get_entry_data *data, + kadm5_principal_ent_t princ, + unsigned int field, + unsigned int subfield, + char *buf, + size_t buf_len, + int condensed) { + krb5_error_code ret; + switch(field) { case KADM5_PRINCIPAL: if(condensed) @@ -173,23 +246,23 @@ format_field(kadm5_principal_ent_t princ, unsigned int field, case KADM5_PRINC_EXPIRE_TIME: time_t2str(princ->princ_expire_time, buf, buf_len, !condensed); break; - + case KADM5_PW_EXPIRATION: time_t2str(princ->pw_expiration, buf, buf_len, !condensed); break; - + case KADM5_LAST_PWD_CHANGE: time_t2str(princ->last_pwd_change, buf, buf_len, !condensed); break; - + case KADM5_MAX_LIFE: deltat2str(princ->max_life, buf, buf_len); break; - + case KADM5_MAX_RLIFE: deltat2str(princ->max_renewable_life, buf, buf_len); break; - + case KADM5_MOD_TIME: time_t2str(princ->mod_date, buf, buf_len, !condensed); break; @@ -209,7 +282,8 @@ format_field(kadm5_principal_ent_t princ, unsigned int field, snprintf(buf, buf_len, "%d", princ->kvno); break; case KADM5_MKVNO: - snprintf(buf, buf_len, "%d", princ->mkvno); + /* XXX libkadm5srv decrypts the keys, so mkvno is always 0. */ + strlcpy(buf, "unknown", buf_len); break; case KADM5_LAST_SUCCESS: time_t2str(princ->last_success, buf, buf_len, !condensed); @@ -230,7 +304,10 @@ format_field(kadm5_principal_ent_t princ, unsigned int field, krb5_salt def_salt; int i; char buf2[1024]; - krb5_get_pw_salt (context, princ->principal, &def_salt); + + ret = krb5_get_pw_salt(context, princ->principal, &def_salt); + if (ret) + krb5_err(context, 1, ret, "krb5_get_pw_salt"); *buf = '\0'; for (i = 0; i < princ->n_key_data; ++i) { @@ -246,7 +323,7 @@ format_field(kadm5_principal_ent_t princ, unsigned int field, krb5_tl_data *tl; for (tl = princ->tl_data; tl != NULL; tl = tl->tl_data_next) - if (tl->tl_data_type == subfield) + if ((unsigned)tl->tl_data_type == subfield) break; if (tl == NULL) { strlcpy(buf, "", buf_len); @@ -259,10 +336,35 @@ format_field(kadm5_principal_ent_t princ, unsigned int field, (int)tl->tl_data_length, (const char *)tl->tl_data_contents); break; + case KRB5_TL_ETYPES: { + HDB_EncTypeList etypes; + size_t i, size; + char *str; + + ret = decode_HDB_EncTypeList(tl->tl_data_contents, + tl->tl_data_length, + &etypes, &size); + if (ret) { + snprintf(buf, buf_len, "failed to decode server etypes"); + break; + } + buf[0] = '\0'; + for (i = 0; i < etypes.len; i++) { + ret = krb5_enctype_to_string(context, etypes.val[i], &str); + if (ret == 0) { + if (i) + strlcat(buf, ",", buf_len); + strlcat(buf, str, buf_len); + krb5_xfree(str); + } + } + free_HDB_EncTypeList(&etypes); + break; + } case KRB5_TL_PKINIT_ACL: { HDB_Ext_PKINIT_acl acl; size_t size; - int i, ret; + size_t i; ret = decode_HDB_Ext_PKINIT_acl(tl->tl_data_contents, tl->tl_data_length, @@ -291,10 +393,20 @@ format_field(kadm5_principal_ent_t princ, unsigned int field, free_HDB_Ext_PKINIT_acl(&acl); break; } + case KRB5_TL_KRB5_CONFIG: { + char *fname; + + fname = write_krb5_config(tl, data->krb5_config_fname, data->n); + if (fname) { + strlcat(buf, fname, buf_len); + free(fname); + } + break; + } case KRB5_TL_ALIASES: { HDB_Ext_Aliases alias; size_t size; - int i, ret; + size_t i; ret = decode_HDB_Ext_Aliases(tl->tl_data_contents, tl->tl_data_length, @@ -310,7 +422,7 @@ format_field(kadm5_principal_ent_t princ, unsigned int field, ret = krb5_unparse_name(context, &alias.aliases.val[i], &p); if (ret) break; - if (i < 0) + if (i > 0) strlcat(buf, " ", buf_len); strlcat(buf, p, buf_len); free(p); @@ -337,7 +449,8 @@ print_entry_short(struct get_entry_data *data, kadm5_principal_ent_t princ) struct field_info *f; for(f = data->chead; f != NULL; f = f->next) { - format_field(princ, f->ff->fieldvalue, f->ff->subvalue, buf, sizeof(buf), 1); + format_field(data, princ, f->ff->fieldvalue, f->ff->subvalue, buf, + sizeof(buf), 1); rtbl_add_column_entry_by_id(data->table, f->ff->fieldvalue, buf); } } @@ -355,7 +468,8 @@ print_entry_long(struct get_entry_data *data, kadm5_principal_ent_t princ) width = w; } for(f = data->chead; f != NULL; f = f->next) { - format_field(princ, f->ff->fieldvalue, f->ff->subvalue, buf, sizeof(buf), 0); + format_field(data, princ, f->ff->fieldvalue, f->ff->subvalue, buf, + sizeof(buf), 0); printf("%*s: %s\n", width, f->header ? f->header : f->ff->def_longheader, buf); } printf("\n"); @@ -368,17 +482,22 @@ do_get_entry(krb5_principal principal, void *data) krb5_error_code ret; struct get_entry_data *e = data; + if (e->upto == 0) + return EINTR; + if (e->upto > 0) + e->upto--; + memset(&princ, 0, sizeof(princ)); - ret = kadm5_get_principal(kadm_handle, principal, + ret = kadm5_get_principal(e->kadm_handle, principal, &princ, e->mask | e->extra_mask); - if(ret) - return ret; - else { - (e->format)(e, &princ); - kadm5_free_principal_ent(kadm_handle, &princ); + if (ret == 0) { + (e->format)(e, &princ); + kadm5_free_principal_ent(e->kadm_handle, &princ); } - return 0; + + e->n++; + return ret; } static void @@ -420,9 +539,41 @@ setup_columns(struct get_entry_data *data, const char *column_info) return 0; } +static int +do_list_entry(krb5_principal principal, void *data) +{ + char buf[1024]; + int *upto = data; + krb5_error_code ret; + + if (*upto == 0) + return EINTR; + if (*upto > 0) + (*upto)--; + + ret = krb5_unparse_name_fixed_short(context, principal, buf, sizeof(buf)); + if (ret != 0) + return ret; + printf("%s\n", buf); + return 0; +} + +static int +listit(const char *funcname, int upto, int argc, char **argv) +{ + int i; + krb5_error_code ret, saved_ret = 0; + + for (i = 0; i < argc; i++) { + ret = foreach_principal(argv[i], do_list_entry, funcname, &upto); + if (saved_ret == 0 && ret != 0) + saved_ret = ret; + } + return saved_ret != 0; +} + #define DEFAULT_COLUMNS_SHORT "principal,princ_expire_time,pw_expiration,last_pwd_change,max_life,max_rlife" -#define DEFAULT_COLUMNS_LONG "principal,princ_expire_time,pw_expiration,last_pwd_change,max_life,max_rlife,kvno,mkvno,last_success,last_failed,fail_auth_count,mod_time,mod_name,attributes,keytypes,pkinit-acl,aliases" -#define DEFAULT_COLUMNS_TERSE "principal=" +#define DEFAULT_COLUMNS_LONG "principal,princ_expire_time,pw_expiration,last_pwd_change,max_life,max_rlife,kvno,mkvno,last_success,last_failed,fail_auth_count,mod_time,mod_name,attributes,server-keytypes,keytypes,pkinit-acl,aliases" static int getit(struct get_options *opt, const char *name, int argc, char **argv) @@ -440,13 +591,23 @@ getit(struct get_options *opt, const char *name, int argc, char **argv) if(opt->long_flag == 0 && opt->short_flag == 0 && opt->terse_flag == 0) opt->short_flag = 1; + if (opt->terse_flag) + return listit(name, opt->upto_integer, argc, argv); + + data.kadm_handle = NULL; + ret = kadm5_dup_context(kadm_handle, &data.kadm_handle); + if (ret) + krb5_err(context, 1, ret, "Could not duplicate kadmin connection"); data.table = NULL; data.chead = NULL; data.ctail = &data.chead; data.mask = 0; data.extra_mask = 0; + data.krb5_config_fname = opt->krb5_config_file_string; + data.upto = opt->upto_integer; + data.n = 0; - if(opt->short_flag || opt->terse_flag) { + if(opt->short_flag) { data.table = rtbl_create(); rtbl_set_separator(data.table, " "); data.format = print_entry_short; @@ -455,15 +616,11 @@ getit(struct get_options *opt, const char *name, int argc, char **argv) if(opt->column_info_string == NULL) { if(opt->long_flag) ret = setup_columns(&data, DEFAULT_COLUMNS_LONG); - else if(opt->short_flag) + else ret = setup_columns(&data, DEFAULT_COLUMNS_SHORT); - else { - ret = setup_columns(&data, DEFAULT_COLUMNS_TERSE); - rtbl_set_flags(data.table, RTBL_HEADER_STYLE_NONE); - } } else ret = setup_columns(&data, opt->column_info_string); - + if(ret != 0) { if(data.table != NULL) rtbl_destroy(data.table); @@ -471,7 +628,9 @@ getit(struct get_options *opt, const char *name, int argc, char **argv) } for(i = 0; i < argc; i++) - ret = foreach_principal(argv[i], do_get_entry, "get", &data); + ret = foreach_principal(argv[i], do_get_entry, name, &data); + + kadm5_destroy(data.kadm_handle); if(data.table != NULL) { rtbl_format(data.table, stdout); @@ -490,9 +649,17 @@ get_entry(struct get_options *opt, int argc, char **argv) int list_princs(struct list_options *opt, int argc, char **argv) { + struct get_options get_opt; + if(sizeof(struct get_options) != sizeof(struct list_options)) { krb5_warnx(context, "programmer error: sizeof(struct get_options) != sizeof(struct list_options)"); return 0; } - return getit((struct get_options*)opt, "list", argc, argv); + memset(&get_opt, 0, sizeof(get_opt)); + get_opt.long_flag = opt->long_flag; + get_opt.short_flag = opt->short_flag; + get_opt.terse_flag = opt->terse_flag; + get_opt.column_info_string = opt->column_info_string; + get_opt.upto_integer = opt->upto_integer; + return getit(&get_opt, "list", argc, argv); } diff --git a/kadmin/init.c b/kadmin/init.c index 62ff55ded..8a3725e3c 100644 --- a/kadmin/init.c +++ b/kadmin/init.c @@ -3,6 +3,8 @@ * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -35,13 +37,14 @@ #include "kadmin-commands.h" #include -RCSID("$Id$"); +#define CRE_DUP_OK 1 static kadm5_ret_t create_random_entry(krb5_principal princ, unsigned max_life, unsigned max_rlife, - uint32_t attributes) + uint32_t attributes, + unsigned flags) { kadm5_principal_ent_rec ent; kadm5_ret_t ret; @@ -49,11 +52,6 @@ create_random_entry(krb5_principal princ, krb5_keyblock *keys; int n_keys, i; char *name; - const char *password; - char pwbuf[512]; - - random_password(pwbuf, sizeof(pwbuf)); - password = pwbuf; ret = krb5_unparse_name(context, princ, &name); if (ret) { @@ -73,12 +71,27 @@ create_random_entry(krb5_principal princ, mask |= KADM5_MAX_RLIFE; } ent.attributes |= attributes | KRB5_KDB_DISALLOW_ALL_TIX; - mask |= KADM5_ATTRIBUTES; + mask |= KADM5_ATTRIBUTES | KADM5_KEY_DATA; - /* Create the entry with a random password */ - ret = kadm5_create_principal(kadm_handle, &ent, mask, password); + /* + * Create the entry with no keys or password. + * + * XXX Note that using kadm5_s_*() here means that `kadmin init` must + * always be local (`kadmin -l init`). This might seem like a very + * obvious thing, but since our KDC daemons support multiple realms + * there is no reason that `init SOME.REALM.EXAMPLE` couldn't be + * remoted. + * + * Granted, one might want all such operations to be local anyways -- + * perhaps for authorization reasons, since we don't really have that + * great a story for authorization in kadmind at this time, especially + * for realm creation. + */ + ret = kadm5_s_create_principal_with_key(kadm_handle, &ent, mask); if(ret) { - krb5_warn(context, ret, "create_random_entry(%s): randkey failed", + if (ret == KADM5_DUP && (flags & CRE_DUP_OK)) + goto out; + krb5_warn(context, ret, "create_random_entry(%s): create failed", name); goto out; } @@ -123,25 +136,25 @@ init(struct init_options *opt, int argc, char **argv) kadm5_ret_t ret; int i; HDB *db; - krb5_deltat max_life, max_rlife; + krb5_deltat max_life = 0, max_rlife = 0; - if(!local_flag) { + if (!local_flag) { krb5_warnx(context, "init is only available in local (-l) mode"); - return 0; + return 1; } if (opt->realm_max_ticket_life_string) { if (str2deltat (opt->realm_max_ticket_life_string, &max_life) != 0) { krb5_warnx (context, "unable to parse \"%s\"", opt->realm_max_ticket_life_string); - return 0; + return 1; } } if (opt->realm_max_renewable_life_string) { if (str2deltat (opt->realm_max_renewable_life_string, &max_rlife) != 0) { krb5_warnx (context, "unable to parse \"%s\"", opt->realm_max_renewable_life_string); - return 0; + return 1; } } @@ -150,84 +163,164 @@ init(struct init_options *opt, int argc, char **argv) ret = db->hdb_open(context, db, O_RDWR | O_CREAT, 0600); if(ret){ krb5_warn(context, ret, "hdb_open"); - return 0; + return 1; } + ret = kadm5_log_reinit(kadm_handle, 0); + if (ret) { + krb5_warn(context, ret, "Failed iprop log initialization"); + return 1; + } + ret = kadm5_log_end(kadm_handle); db->hdb_close(context, db); + if (ret) { + krb5_warn(context, ret, "Failed iprop log initialization"); + return 1; + } + for(i = 0; i < argc; i++){ - krb5_principal princ; + krb5_principal princ = NULL; const char *realm = argv[i]; - /* Create `krbtgt/REALM' */ - ret = krb5_make_principal(context, &princ, realm, - KRB5_TGS_NAME, realm, NULL); - if(ret) - return 0; if (opt->realm_max_ticket_life_string == NULL) { max_life = 0; if(edit_deltat ("Realm max ticket life", &max_life, NULL, 0)) { - krb5_free_principal(context, princ); - return 0; + return 1; } } if (opt->realm_max_renewable_life_string == NULL) { max_rlife = 0; if(edit_deltat("Realm max renewable ticket life", &max_rlife, NULL, 0)) { - krb5_free_principal(context, princ); - return 0; + return 1; } } - create_random_entry(princ, max_life, max_rlife, 0); + + /* Create `krbtgt/REALM' */ + ret = krb5_make_principal(context, &princ, realm, + KRB5_TGS_NAME, realm, NULL); + if (ret == 0) + ret = create_random_entry(princ, max_life, max_rlife, 0, 0); krb5_free_principal(context, princ); + if (ret) { + krb5_warn(context, ret, "Failed to create %s@%s", KRB5_TGS_NAME, + realm); + return 1; + } + + if (opt->bare_flag) + continue; /* Create `kadmin/changepw' */ - krb5_make_principal(context, &princ, realm, - "kadmin", "changepw", NULL); + ret = krb5_make_principal(context, &princ, realm, "kadmin", + "changepw", NULL); /* * The Windows XP (at least) password changing protocol * request the `kadmin/changepw' ticket with `renewable_ok, * renewable, forwardable' and so fails if we disallow * forwardable here. */ - create_random_entry(princ, 5*60, 5*60, - KRB5_KDB_DISALLOW_TGT_BASED| - KRB5_KDB_PWCHANGE_SERVICE| - KRB5_KDB_DISALLOW_POSTDATED| - KRB5_KDB_DISALLOW_RENEWABLE| - KRB5_KDB_DISALLOW_PROXIABLE| - KRB5_KDB_REQUIRES_PRE_AUTH); + if (ret == 0) + ret = create_random_entry(princ, 5*60, 5*60, + KRB5_KDB_DISALLOW_TGT_BASED| + KRB5_KDB_PWCHANGE_SERVICE| + KRB5_KDB_DISALLOW_POSTDATED| + KRB5_KDB_DISALLOW_RENEWABLE| + KRB5_KDB_DISALLOW_PROXIABLE| + KRB5_KDB_REQUIRES_PRE_AUTH, + 0); krb5_free_principal(context, princ); + if (ret) { + krb5_warn(context, ret, "Failed to create kadmin/changepw@%s", + realm); + return 1; + } /* Create `kadmin/admin' */ - krb5_make_principal(context, &princ, realm, - "kadmin", "admin", NULL); - create_random_entry(princ, 60*60, 60*60, KRB5_KDB_REQUIRES_PRE_AUTH); + ret = krb5_make_principal(context, &princ, realm, + "kadmin", "admin", NULL); + if (ret == 0) + ret = create_random_entry(princ, 60*60, 60*60, + KRB5_KDB_REQUIRES_PRE_AUTH, 0); krb5_free_principal(context, princ); + if (ret) { + krb5_warn(context, ret, "Failed to create kadmin/admin@%s", realm); + return 1; + } /* Create `changepw/kerberos' (for v4 compat) */ - krb5_make_principal(context, &princ, realm, - "changepw", "kerberos", NULL); - create_random_entry(princ, 60*60, 60*60, - KRB5_KDB_DISALLOW_TGT_BASED| - KRB5_KDB_PWCHANGE_SERVICE); - + ret = krb5_make_principal(context, &princ, realm, + "changepw", "kerberos", NULL); + if (ret == 0) + ret = create_random_entry(princ, 60*60, 60*60, + KRB5_KDB_DISALLOW_TGT_BASED| + KRB5_KDB_PWCHANGE_SERVICE, 0); krb5_free_principal(context, princ); + if (ret) { + krb5_warn(context, ret, "Failed to create changepw/kerberos@%s", + realm); + return 1; + } /* Create `kadmin/hprop' for database propagation */ - krb5_make_principal(context, &princ, realm, - "kadmin", "hprop", NULL); - create_random_entry(princ, 60*60, 60*60, - KRB5_KDB_REQUIRES_PRE_AUTH| - KRB5_KDB_DISALLOW_TGT_BASED); + ret = krb5_make_principal(context, &princ, realm, + "kadmin", "hprop", NULL); + if (ret == 0) + ret = create_random_entry(princ, 60*60, 60*60, + KRB5_KDB_REQUIRES_PRE_AUTH| + KRB5_KDB_DISALLOW_TGT_BASED, 0); krb5_free_principal(context, princ); + if (ret) { + krb5_warn(context, ret, "Failed to create kadmin/hprop@%s", realm); + return 1; + } /* Create `WELLKNOWN/ANONYMOUS' for anonymous as-req */ - krb5_make_principal(context, &princ, realm, - KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME, NULL); - create_random_entry(princ, 60*60, 60*60, - KRB5_KDB_REQUIRES_PRE_AUTH); + ret = krb5_make_principal(context, &princ, realm, KRB5_WELLKNOWN_NAME, + KRB5_ANON_NAME, NULL); + if (ret == 0) + ret = create_random_entry(princ, 60*60, 60*60, + KRB5_KDB_REQUIRES_PRE_AUTH, 0); krb5_free_principal(context, princ); + if (ret) { + krb5_warn(context, ret, "Failed to create %s/%s@%s", + KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME, realm); + return 1; + } + /* Create `WELLKNOWN/FEDERATED' for GSS preauth */ + ret = krb5_make_principal(context, &princ, realm, + KRB5_WELLKNOWN_NAME, KRB5_FEDERATED_NAME, NULL); + if (ret == 0) + ret = create_random_entry(princ, 60*60, 60*60, + KRB5_KDB_REQUIRES_PRE_AUTH, 0); + krb5_free_principal(context, princ); + if (ret) { + krb5_warn(context, ret, "Failed to create %s/%s@%s", + KRB5_WELLKNOWN_NAME, KRB5_FEDERATED_NAME, realm); + return 1; + } + + /* + * Create `WELLKNONW/org.h5l.fast-cookie@WELLKNOWN:ORG.H5L' for FAST cookie. + * + * There can be only one. + */ + if (i == 0) { + ret = krb5_make_principal(context, &princ, KRB5_WELLKNOWN_ORG_H5L_REALM, + KRB5_WELLKNOWN_NAME, "org.h5l.fast-cookie", NULL); + if (ret == 0) + ret = create_random_entry(princ, 60*60, 60*60, + KRB5_KDB_REQUIRES_PRE_AUTH| + KRB5_KDB_DISALLOW_TGT_BASED| + KRB5_KDB_DISALLOW_ALL_TIX, CRE_DUP_OK); + krb5_free_principal(context, princ); + if (ret && ret != KADM5_DUP) { + krb5_warn(context, ret, + "Failed to create %s/org.h5l.fast-cookie@%s", + KRB5_WELLKNOWN_NAME, KRB5_WELLKNOWN_ORG_H5L_REALM); + return 1; + } + } /* Create `default' */ { @@ -236,18 +329,20 @@ init(struct init_options *opt, int argc, char **argv) memset (&ent, 0, sizeof(ent)); mask |= KADM5_PRINCIPAL; - krb5_make_principal(context, &ent.principal, realm, - "default", NULL); mask |= KADM5_MAX_LIFE; - ent.max_life = 24 * 60 * 60; mask |= KADM5_MAX_RLIFE; + mask |= KADM5_ATTRIBUTES; + ent.max_life = 24 * 60 * 60; ent.max_renewable_life = 7 * ent.max_life; ent.attributes = KRB5_KDB_DISALLOW_ALL_TIX; - mask |= KADM5_ATTRIBUTES; - - ret = kadm5_create_principal(kadm_handle, &ent, mask, ""); - if (ret) - krb5_err (context, 1, ret, "kadm5_create_principal"); + ret = krb5_make_principal(context, &ent.principal, realm, + "default", NULL); + if (ret == 0) + ret = kadm5_create_principal(kadm_handle, &ent, mask, ""); + if (ret) { + krb5_warn(context, ret, "Failed to create default@%s", realm); + return 1; + } krb5_free_principal(context, ent.principal); } diff --git a/kadmin/kadm_conn.c b/kadmin/kadm_conn.c index 393a6c1eb..ccd89211d 100644 --- a/kadmin/kadm_conn.c +++ b/kadmin/kadm_conn.c @@ -36,7 +36,7 @@ #include #endif -RCSID("$Id$"); +extern int daemon_child; struct kadm_port { char *port; @@ -45,12 +45,12 @@ struct kadm_port { } *kadm_ports; static void -add_kadm_port(krb5_context context, const char *service, unsigned int port) +add_kadm_port(krb5_context contextp, const char *service, unsigned int port) { struct kadm_port *p; p = malloc(sizeof(*p)); if(p == NULL) { - krb5_warnx(context, "failed to allocate %lu bytes\n", + krb5_warnx(contextp, "failed to allocate %lu bytes\n", (unsigned long)sizeof(*p)); return; } @@ -63,9 +63,13 @@ add_kadm_port(krb5_context context, const char *service, unsigned int port) } static void -add_standard_ports (krb5_context context) +add_standard_ports (krb5_context contextp) { - add_kadm_port(context, "kerberos-adm", 749); + if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns", + NULL)) + add_kadm_port(contextp, "749", 749); + else + add_kadm_port(contextp, "kerberos-adm", 749); } /* @@ -75,15 +79,15 @@ add_standard_ports (krb5_context context) */ void -parse_ports(krb5_context context, const char *str) +parse_ports(krb5_context contextp, const char *str) { char p[128]; while(strsep_copy(&str, " \t", p, sizeof(p)) != -1) { if(strcmp(p, "+") == 0) - add_standard_ports(context); + add_standard_ports(contextp); else - add_kadm_port(context, p, 0); + add_kadm_port(contextp, p, 0); } } @@ -94,7 +98,12 @@ static RETSIGTYPE sigchld(int sig) { int status; - waitpid(-1, &status, 0); + /* + * waitpid() is async safe. will return -1 or 0 on no more zombie + * children + */ + while ((waitpid(-1, &status, WNOHANG)) > 0) + ; SIGRETURN(0); } @@ -117,73 +126,77 @@ terminate(int sig) } static int -spawn_child(krb5_context context, int *socks, +spawn_child(krb5_context contextp, int *socks, unsigned int num_socks, int this_sock) { - int e, i; + int e; + size_t i; struct sockaddr_storage __ss; struct sockaddr *sa = (struct sockaddr *)&__ss; socklen_t sa_size = sizeof(__ss); - int s; + krb5_socket_t s; pid_t pid; krb5_address addr; char buf[128]; size_t buf_len; s = accept(socks[this_sock], sa, &sa_size); - if(s < 0) { - krb5_warn(context, errno, "accept"); + if(rk_IS_BAD_SOCKET(s)) { + krb5_warn(contextp, rk_SOCK_ERRNO, "accept"); return 1; } - e = krb5_sockaddr2address(context, sa, &addr); + e = krb5_sockaddr2address(contextp, sa, &addr); if(e) - krb5_warn(context, e, "krb5_sockaddr2address"); + krb5_warn(contextp, e, "krb5_sockaddr2address"); else { e = krb5_print_address (&addr, buf, sizeof(buf), &buf_len); if(e) - krb5_warn(context, e, "krb5_print_address"); + krb5_warn(contextp, e, "krb5_print_address"); else - krb5_warnx(context, "connection from %s", buf); - krb5_free_address(context, &addr); + krb5_warnx(contextp, "connection from %s", buf); + krb5_free_address(contextp, &addr); } pid = fork(); if(pid == 0) { for(i = 0; i < num_socks; i++) - close(socks[i]); + rk_closesocket(socks[i]); dup2(s, STDIN_FILENO); dup2(s, STDOUT_FILENO); if(s != STDIN_FILENO && s != STDOUT_FILENO) - close(s); + rk_closesocket(s); return 0; } else { - close(s); + rk_closesocket(s); } return 1; } -static int -wait_for_connection(krb5_context context, - int *socks, unsigned int num_socks) +static void +wait_for_connection(krb5_context contextp, + krb5_socket_t *socks, unsigned int num_socks) { unsigned int i; int e; fd_set orig_read_set, read_set; - int max_fd = -1; + int status, max_fd = -1; FD_ZERO(&orig_read_set); for(i = 0; i < num_socks; i++) { +#ifdef FD_SETSIZE if (socks[i] >= FD_SETSIZE) errx (1, "fd too large"); +#endif FD_SET(socks[i], &orig_read_set); max_fd = max(max_fd, socks[i]); } pgrp = getpid(); - if(setpgid(0, pgrp) < 0) + /* systemd may cause setpgid to fail with EPERM */ + if(setpgid(0, pgrp) < 0 && errno != EPERM) err(1, "setpgid"); signal(SIGTERM, terminate); @@ -193,41 +206,43 @@ wait_for_connection(krb5_context context, while (term_flag == 0) { read_set = orig_read_set; e = select(max_fd + 1, &read_set, NULL, NULL, NULL); - if(e < 0) { - if(errno != EINTR) - krb5_warn(context, errno, "select"); + if(rk_IS_SOCKET_ERROR(e)) { + if(rk_SOCK_ERRNO != EINTR) + krb5_warn(contextp, rk_SOCK_ERRNO, "select"); } else if(e == 0) - krb5_warnx(context, "select returned 0"); + krb5_warnx(contextp, "select returned 0"); else { for(i = 0; i < num_socks; i++) { if(FD_ISSET(socks[i], &read_set)) - if(spawn_child(context, socks, num_socks, i) == 0) - return 0; + if(spawn_child(contextp, socks, num_socks, i) == 0) + return; } } } signal(SIGCHLD, SIG_IGN); - while(1) { - int status; - pid_t pid; - pid = waitpid(-1, &status, 0); - if(pid == -1 && errno == ECHILD) - break; - } + + while ((waitpid(-1, &status, WNOHANG)) > 0) + ; + exit(0); } -int -start_server(krb5_context context) +void +start_server(krb5_context contextp, const char *port_str) { int e; struct kadm_port *p; - int *socks = NULL, *tmp; + krb5_socket_t *socks = NULL, *tmp; unsigned int num_socks = 0; int i; + if (port_str == NULL) + port_str = "+"; + + parse_ports(contextp, port_str); + for(p = kadm_ports; p; p = p->next) { struct addrinfo hints, *ai, *ap; char portstr[32]; @@ -235,6 +250,11 @@ start_server(krb5_context context) hints.ai_flags = AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; + if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns", + NULL)) { + hints.ai_flags &= ~AI_CANONNAME; + hints.ai_flags |= AI_NUMERICHOST|AI_NUMERICSERV; + } e = getaddrinfo(NULL, p->port, &hints, &ai); if(e) { snprintf(portstr, sizeof(portstr), "%u", p->def_port); @@ -242,7 +262,7 @@ start_server(krb5_context context) } if(e) { - krb5_warn(context, krb5_eai_to_heim_errno(e, errno), + krb5_warn(contextp, krb5_eai_to_heim_errno(e, errno), "%s", portstr); continue; } @@ -250,37 +270,41 @@ start_server(krb5_context context) for(ap = ai; ap; ap = ap->ai_next) i++; tmp = realloc(socks, (num_socks + i) * sizeof(*socks)); - if(tmp == NULL) { - krb5_warnx(context, "failed to reallocate %lu bytes", - (unsigned long)(num_socks + i) * sizeof(*socks)); - continue; - } + if(tmp == NULL) + krb5_err(contextp, 1, errno, "failed to reallocate %lu bytes", + (unsigned long)(num_socks + i) * sizeof(*socks)); socks = tmp; for(ap = ai; ap; ap = ap->ai_next) { - int s = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol); - if(s < 0) { - krb5_warn(context, errno, "socket"); + krb5_socket_t s = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol); + if(rk_IS_BAD_SOCKET(s)) { + krb5_warn(contextp, rk_SOCK_ERRNO, "socket"); continue; } socket_set_reuseaddr(s, 1); socket_set_ipv6only(s, 1); - if (bind (s, ap->ai_addr, ap->ai_addrlen) < 0) { - krb5_warn(context, errno, "bind"); - close(s); + if (rk_IS_SOCKET_ERROR(bind (s, ap->ai_addr, ap->ai_addrlen))) { + krb5_warn(contextp, rk_SOCK_ERRNO, "bind"); + rk_closesocket(s); continue; } - if (listen (s, SOMAXCONN) < 0) { - krb5_warn(context, errno, "listen"); - close(s); + if (rk_IS_SOCKET_ERROR(listen (s, SOMAXCONN))) { + krb5_warn(contextp, rk_SOCK_ERRNO, "listen"); + rk_closesocket(s); continue; } + + socket_set_keepalive(s, 1); socks[num_socks++] = s; } freeaddrinfo (ai); } if(num_socks == 0) - krb5_errx(context, 1, "no sockets to listen to - exiting"); - return wait_for_connection(context, socks, num_socks); + krb5_errx(contextp, 1, "no sockets to listen to - exiting"); + + roken_detach_finish(NULL, daemon_child); + + wait_for_connection(contextp, socks, num_socks); + free(socks); } diff --git a/kadmin/kadmin-commands.in b/kadmin/kadmin-commands.in index 5760a52d8..0872b47a4 100644 --- a/kadmin/kadmin-commands.in +++ b/kadmin/kadmin-commands.in @@ -54,6 +54,11 @@ command = { type = "flag" help = "just convert keyfile to new format" } + option = { + long = "random-password" + type = "flag" + help = "use a random password (and print the password to stdout)" + } option = { long = "master-key-fd" type = "integer" @@ -71,6 +76,12 @@ command = { type = "flag" help = "decrypt keys" } + option = { + long = "format" + short = "f" + type = "string" + help = "dump format, mit or heimdal (default: heimdal)" + } argument = "[dump-file]" min_args = "0" max_args = "1" @@ -89,6 +100,11 @@ command = { type = "string" help = "realm max renewable lifetime" } + option = { + long = "bare" + type = "flag" + help = "only create krbtgt for realm" + } argument = "realm..." min_args = "1" help = "Initializes the default principals for a realm. Creates the database\nif necessary. Local (-l) mode only." @@ -123,6 +139,12 @@ command = { type = "flag" help = "set random password" } + option = { + long = "enctypes" + short = "e" + type = "string" + help = "encryption type(s)" + } option = { long = "password" short = "p" @@ -164,15 +186,157 @@ command = { argument = "time" help = "password expiration time" } + option = { + long = "hist-kvno-diff-clnt" + type = "integer" + argument = "kvno diff" + help = "historic keys allowed for client" + default = "-1" + } + option = { + long = "hist-kvno-diff-svc" + type = "integer" + argument = "kvno diff" + help = "historic keys allowed for service" + default = "-1" + } option = { long = "use-defaults" type = "flag" help = "use default values" } + option = { + long = "policy" + type = "string" + argument = "policy" + help = "policy name" + } argument = "principal..." min_args = "1" help = "Adds a principal to the database." } +command = { + name = "add_namespace" + name = "add_ns" + function = "add_new_namespace" + option = { + long = "enctypes" + short = "e" + type = "string" + help = "encryption type(s)" + } + option = { + long = "max-ticket-life" + type = "string" + argument ="lifetime" + help = "max ticket lifetime" + } + option = { + long = "max-renewable-life" + type = "string" + argument = "lifetime" + help = "max renewable life" + } + option = { + long = "key-rotation-epoch" + type = "string" + argument = "time" + help = "absolute start time (or +timespec for relative to now with default unit of month)" + } + option = { + long = "key-rotation-period" + type = "string" + argument = "time" + help = "automatic key rotation period" + } + option = { + long = "attributes" + type = "string" + argument = "attributes" + help = "principal attributes" + } + argument = "principal..." + min_args = "1" + help = "Adds a namespace of virtual principals with derived keys to the database." +} +command = { + name = "modify_namespace" + name = "mod_ns" + function = "modify_namespace" + option = { + long = "enctypes" + short = "e" + type = "strings" + help = "encryption type(s)" + } + option = { + long = "max-ticket-life" + type = "string" + argument ="lifetime" + help = "max ticket lifetime" + } + option = { + long = "max-renewable-life" + type = "string" + argument = "lifetime" + help = "max renewable life" + } + option = { + long = "attributes" + type = "string" + argument = "attributes" + help = "principal attributes" + } + option = { + long = "krb5-config-file" + short = "C" + type = "string" + help = "filename to save the principal's krb5.confg in" + } + argument = "principal..." + min_args = "1" + help = "Modifies a namespace of virtual principals with derived keys to the database." +} +command = { + name = "modify_namespace_key_rotation" + name = "mod_ns_kr" + function = "modify_ns_kr" + option = { + long = "force" + short = "f" + type = "flag" + help = "change schedule even if it would revoke some extant tickets" + } + option = { + long = "keep-base-key" + short = "k" + type = "flag" + help = "keep current base key for new key rotation schedule" + } + option = { + long = "revoke-old" + short = "r" + type = "string" + argument = "time" + help = "delete base keys older than this to revoke old tickets" + } + option = { + long = "new-key-rotation-epoch" + type = "string" + argument = "time" + help = "new start time relative to now" + } + option = { + long = "new-key-rotation-period" + type = "string" + argument = "time" + help = "new automatic key rotation period" + } + argument = "principal..." + min_args = "1" + max_args = "1" + help = "Adds or changes new key rotation schedule for the given namespace." +} command = { name = "passwd" name = "cpw" @@ -189,17 +353,38 @@ command = { type = "flag" help = "set random password" } + option = { + long = "enctypes" + short = "e" + type = "string" + help = "encryption type(s)" + } option = { long = "password" short = "p" type = "string" - help = "princial's password" + help = "principal's password" } option = { long = "key" type = "string" help = "DES key in hex" } + option = { + long = "keepold" + type = "flag" + help = "keep old keys/password needed to decrypt extant tickets (default)" + } + option = { + long = "keepallold" + type = "flag" + help = "keep all old keys/password" + } + option = { + long = "pruneall" + type = "flag" + help = "delete all old keys" + } argument = "principal..." min_args = "1" help = "Changes the password of one or more principals matching the expressions." @@ -213,6 +398,14 @@ command = { min_args = "1" help = "Deletes all principals matching the expressions." } +command = { + name = "delete_namespace" + name = "del_ns" + function = "del_namespace" + argument = "principal..." + min_args = "1" + help = "Deletes the given virtual principal namespaces" +} command = { name = "del_enctype" argument = "principal enctype..." @@ -238,6 +431,34 @@ command = { short = "k" type = "string" help = "keytab to use" + argument = "keytab" + } + option = { + long = "random-key" + short = "r" + type = "flag" + help = "set random key" + } + option = { + long = "enctypes" + short = "e" + type = "string" + help = "encryption type(s)" + } + option = { + long = "keepold" + type = "flag" + help = "keep old keys/password needed to decrypt extant tickets (default)" + } + option = { + long = "keepallold" + type = "flag" + help = "keep all old keys/password" + } + option = { + long = "pruneall" + type = "flag" + help = "delete all old keys" } argument = "principal..." min_args = "1" @@ -247,7 +468,7 @@ command = { name = "get" name = "get_entry" function = "get_entry" - /* XXX sync options with "list" */ + /* Options added to list should be added here; not the reverse */ option = { long = "long" short = "l" @@ -273,6 +494,18 @@ command = { type = "string" help = "columns to print for short output" } + option = { + long = "krb5-config-file" + short = "C" + type = "string" + help = "filename to save the principal's krb5.conf in" + } + option = { + long = "upto" + type = "integer" + default = "-1" + help = "maximum number of principals to get/list" + } argument = "principal..." min_args = "1" help = "Shows information about principals matching the expressions." @@ -287,6 +520,7 @@ command = { } command = { name = "modify" + name = "mod" function = "mod_entry" option = { long = "max-ticket-life" @@ -343,11 +577,71 @@ command = { argument = "subject dn" help = "aliases" } + option = { + long = "policy" + type = "string" + argument = "policy" + help = "policy name" + } + option = { + long = "service-enctypes" + short = "e" + type = "strings" + argument = "enctype" + help = "set enctypes supported by service" + } + option = { + long = "hist-kvno-diff-clnt" + type = "integer" + argument = "kvno diff" + help = "historic keys allowed for client" + default = "-1" + } + option = { + long = "hist-kvno-diff-svc" + type = "integer" + argument = "kvno diff" + help = "historic keys allowed for service" + default = "-1" + } + option = { + long = "krb5-config-file" + short = "C" + type = "string" + help = "krb5.conf to save in principal record" + } argument = "principal" min_args = "1" max_args = "1" help = "Modifies some attributes of the specified principal." } +command = { + name = "add_alias" + function = "add_alias" + argument = "principal" + min_args = "2" + help = "Add one or more aliases to the given principal." +} +command = { + name = "del_alias" + function = "del_alias" + argument = "principal" + min_args = "1" + help = "Delete one or more aliases without deleting their canonical principals." +} +command = { + name = "prune" + argument = "principal" + option = { + long = "kvno" + type = "integer" + help = "key version number" + default = "0" + } + min_args = "1" + max_args = "1" + help = "Delete keys from history by max-ticket-life or kvno." +} command = { name = "privileges" name = "privs" @@ -383,6 +677,17 @@ command = { type = "string" help = "columns to print for short output" } + option = { + long = "krb5-config-file" + type = "string" + help = "only use this option with the get command" + } + option = { + long = "upto" + type = "integer" + default = "-1" + help = "maximum number of principals to get/list" + } argument = "principal..." min_args = "1" help = "Lists principals in a terse format. Equivalent to \"get -t\"." @@ -404,6 +709,22 @@ command = { max_args = "1" help = "Check the realm (if not given, the default realm) for configuration errors." } +command = { + name = "lock" + function = "lock" + argument = "" + min_args = "0" + max_args = "0" + help = "Lock the database for writing (use with care)." +} +command = { + name = "unlock" + function = "unlock" + argument = "" + min_args = "0" + max_args = "0" + help = "Unlock the database." +} command = { name = "help" name = "?" diff --git a/kadmin/kadmin-version.rc b/kadmin/kadmin-version.rc new file mode 100644 index 000000000..d04058864 --- /dev/null +++ b/kadmin/kadmin-version.rc @@ -0,0 +1,36 @@ +/*********************************************************************** + * Copyright (c) 2010, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#define RC_FILE_TYPE VFT_APP +#define RC_FILE_DESC_0409 "Kerberos Administration Tool" +#define RC_FILE_ORIG_0409 "kadmin.exe" + +#include "../windows/version.rc" diff --git a/kadmin/kadmin.1 b/kadmin/kadmin.1 new file mode 100644 index 000000000..8b9f75e70 --- /dev/null +++ b/kadmin/kadmin.1 @@ -0,0 +1,741 @@ +.\" Copyright (c) 2000 - 2007 Kungliga Tekniska Högskolan +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id$ +.\" +.Dd Feb 22, 2007 +.Dt KADMIN 1 +.Os HEIMDAL +.Sh NAME +.Nm kadmin +.Nd Kerberos administration utility +.Sh SYNOPSIS +.Nm +.Bk -words +.Op Fl p Ar string \*(Ba Fl Fl principal= Ns Ar string +.Op Fl K Ar string \*(Ba Fl Fl keytab= Ns Ar string +.Op Fl c Ar file \*(Ba Fl Fl config-file= Ns Ar file +.Op Fl k Ar file \*(Ba Fl Fl key-file= Ns Ar file +.Op Fl r Ar realm \*(Ba Fl Fl realm= Ns Ar realm +.Op Fl a Ar host \*(Ba Fl Fl admin-server= Ns Ar host +.Op Fl s Ar port number \*(Ba Fl Fl server-port= Ns Ar port number +.Op Fl l | Fl Fl local +.Op Fl h | Fl Fl help +.Op Fl v | Fl Fl version +.Op Ar command +.Ek +.Sh DESCRIPTION +The +.Nm +program is used to make modifications to the Kerberos database, either remotely via the +.Xr kadmind 8 +daemon, or locally (with the +.Fl l +option). +.Pp +Supported options: +.Bl -tag -width Ds +.It Fl p Ar string , Fl Fl principal= Ns Ar string +principal to authenticate as +.It Fl K Ar string , Fl Fl keytab= Ns Ar string +keytab for authentication principal +.It Fl c Ar file , Fl Fl config-file= Ns Ar file +location of config file +.It Fl H Ar HDB , Fl Fl hdb= Ns Ar HDB +location of HDB +.It Fl k Ar file , Fl Fl key-file= Ns Ar file +location of master key file +.It Fl r Ar realm , Fl Fl realm= Ns Ar realm +realm to use +.It Fl a Ar host , Fl Fl admin-server= Ns Ar host +server to contact +.It Fl s Ar port number , Fl Fl server-port= Ns Ar port number +port to use +.It Fl l , Fl Fl local +local admin mode +.El +.Pp +If no +.Ar command +is given on the command line, +.Nm +will prompt for commands to process. Some of the commands that take +one or more principals as argument +.Ns ( Nm delete , +.Nm ext_keytab , +.Nm get , +.Nm modify , +and +.Nm passwd ) +will accept a glob style wildcard, and perform the operation on all +matching principals. +.Pp +Commands include: +.\" not using a list here, since groff apparently gets confused +.\" with nested Xo/Xc +.Pp +.Nm add +.Op Fl r | Fl Fl random-key +.Op Fl Fl enctypes= Ns Ar string +.Op Fl Fl random-password +.Op Fl p Ar string \*(Ba Fl Fl password= Ns Ar string +.Op Fl Fl key= Ns Ar string +.Op Fl Fl max-ticket-life= Ns Ar lifetime +.Op Fl Fl max-renewable-life= Ns Ar lifetime +.Op Fl Fl attributes= Ns Ar attributes +.Op Fl Fl expiration-time= Ns Ar time +.Op Fl Fl pw-expiration-time= Ns Ar time +.Op Fl Fl policy= Ns Ar policy-name +.Op Fl Fl use-defaults +.Ar principal... +.Bd -ragged -offset indent +Adds a new principal to the database. The options not passed on the +command line will be promped for. +If enctypes to use are not given, then the +.Ar [libdefaults] supported_enctypes +configuration parameter will be used on the client side to select +enctypes, defaulting to +.Ar aes128-cts-hmac-sha1-96. +For compatibility with MIT, the enctypes string is a space- or +comma-separated list of enctype:salttype. +If +.Fl Fl keepold +is given, then old keys needed to decrypt extant tickets are +kept, and all other old keys are deleted. +If +.Fl Fl keepallold +is given then all old keys are kept. If +.Fl Fl pruneall is given then all old keys are removed. +The +.Fl Fl keepold +behavior is the default if none of these are given. +The only policy supported by Heimdal servers is +.Ql default . +.Pp +If some parameters are not given then they will be prompted for +unless the +.Fl Fl use-defaults +option is given, in which case defaults will be taken from the +principal named +.Dq default . +.Pp +This command has the following aliases: +.Nm ank , +.Nm add_new_key . +.Ed +.Pp +.Nm add_alias +.Ar principal +.Ar alias... +.Bd -ragged -offset indent +Adds one or more aliases to the given principal. +.Pp +There are two types of aliases: hard, and soft. +A soft alias is an alias of a principal of the form +.Ar WELLKNOWN/REFERRALS/TARGET@target_realm +or +.Ar WELLKNOWN/REFERRALS/TARGET/arbitrary-component@target_realm . +A hard alias is an alias of any normal principal, even if in a +different realm. +.Pp +Hard aliases are treated as distinct principals sharing +attributes and keys with their canonical principals. +If a client requests canonicalization of a hard alias name, the +KDC will use the canonical name in the ticket issued as long as +the alias and canonical names are in the same realm. +Conversely, if a client does not request canonicalization, or if +the hard alias and the canonical name have different realms, then +the KDC will issue a ticket for the alias name. +.Pp +Soft aliases can only be used to configure the production of +referrals by the KDC. +When a client requests a ticket for a principal that turns out to +be a soft alias, the KDC will respond with a referral to the +alias' canonical name's realm. +.Pp +Soft aliasing compares favorably to using +.Ar [domain_realm] +entries in the KDC's +.Ar krb5.conf : +soft aliases may be managed via the +.Nm kadmin +command and its +.Nm add_alias +and +.Nm del_alias +sub-commands rather than having to edit the KDC's configuration +file and having to restart the KDC. +.Pp +There are two methods for configuring the issuance of referrals +for entire namespaces of hostnames. +A soft alias of the form +.Ar WELLKNOWN/HOSTBASED-NAMESPACE/service/namespace-fqdn@REALM +(see +.Nm add_namespace +below) will cause all requests for host-based principals in the +given namespace to be referred to the given realm. +Alternatively, the KDC will issue referrals for all host-based +service principals whose hostname component matches a +.Ar [domain_realm] +entry in the KDC's +.Ar krb5.conf +file referring to a different realm. +.Ed +.Pp +.Nm add_namespace +.Ar Fl Fl key-rotation-epoch= Ns Ar time +.Ar Fl Fl key-rotation-period= Ns Ar time +.Op Fl Fl enctypes= Ns Ar string +.Op Fl Fl max-ticket-life= Ns Ar lifetime +.Op Fl Fl max-renewable-life= Ns Ar lifetime +.Op Fl Fl attributes= Ns Ar attributes +.Ar host-based-principal... +.Bd -ragged -offset indent +Adds a new namespace of virtual host-based or domain-based +principals to the database, whose keys will be automatically +derived from base keys stored in the namespace record, and which +keys will be rotated automatically. +The namespace names are of the same form as host-based principal +names: +.Ar service/hostname@REALM +and these will match all host-based or domain-based service names +where hostname component of such a principal ends in the labels +of the hostname in the namespace name. +.Pp +The service name component may be a wild-card (underscore, +.Ar _ ), +in which case it will match any service. +.Pp +For example, +.Ar bar.baz.example@BAZ.EXAMPLE +will match +.Ar host/foo.bar.baz.example@BAZ.EXAMPLE +but not +.Ar host/foobar.baz.example@BAZ.EXAMPLE . +.Pp +Note well that services are expected to +.Ar ext_keytab +or otherwise re-fetch their keytabs at least as often as one +quarter of the key rotation period, otherwise they risk not +having keys they need to decrypt tickets with. +.Pp +The epoch must be given as either an absolute time, +.Ar "now", +or as +.Ar "+[]" +where +.Ar N +is a natural and +.Ar unit +is one "s", "m", "h", "day", "week", "month", defaulting to +"month". +The default key rotation period is +.Ar 7d . +The default enctypes is as for the +.Nm add +command. +.Pp +Note that namespaces are stored as principals whose names are of the form +.Ar WELLKNOWN/HOSTBASED-NAMESPACE/service/namespace.fqdn@REALM , +with the +.Ar service +.Pp +This command has the following alias: +.Nm add_ns . +.Ed +.Pp +.Nm add_enctype +.Op Fl r | Fl Fl random-key +.Ar principal enctypes... +.Pp +.Bd -ragged -offset indent +Adds a new encryption type to the principal, only random key are +supported. +.Ed +.Pp +.Nm delete +.Ar principal... +.Bd -ragged -offset indent +Removes a principal. +It is an error to delete an alias. +To remove a principal's alias or aliases, use the +.Nm del_alias +command. +To remove a principal given an alias, first +.Nm get +the principal to get its canonical name and then delete that. +.Ed +.Pp +.Nm del_alias +.Ar alias... +.Bd -ragged -offset indent +Deletes the given aliases, but not their canonical principals. +.Pp +This command has the following aliases: +.Nm del , +.Nm del_entry . +.Ed +.Pp +.Nm del_enctype +.Ar principal enctypes... +.Bd -ragged -offset indent +Removes some enctypes from a principal; this can be useful if the +service belonging to the principal is known to not handle certain +enctypes. +.Ed +.Pp +.Nm prune +.Oo Fl Fl kvno= Ns Ar number +.Oc +.Ar principal +.Bd -ragged -offset indent +Deletes the named principal's keys of the given kvno. If a kvno is +not given then this deletes all the named principal's keys that are +too old to be needed for decrypting tickets issued using those keys +(i.e., any such tickets are necessarily expired). The determination +of "too old" is made using the max-ticket-life attribute of the +principal; though in practice that max ticket life is also constrained +by the max-ticket-life of the client principals and the krbtgt +principals, those are not consulted here. +.Ed +.Pp +.Nm ext_keytab +.Oo Fl k Ar keytab \*(Ba Xo +.Op Fl Fl random-key +.Op Fl Fl keepold | Fl Fl keepallold | Fl Fl pruneall +.Op Fl Fl enctypes= Ns Ar string +.Fl Fl keytab= Ns Ar string +.Xc +.Oc +.Ar principal... +.Bd -ragged -offset indent +Creates a keytab with the keys of the specified principals. Requires +get-keys rights, otherwise the principal's keys are changed and saved in +the keytab. +.Pp +If the +.Fl Fl random-key +option is given then new randomly-generated keys will be set on +the principal. +.Pp +If enctypes to use are not given, then the +.Ar [libdefaults] supported_enctypes +configuration parameter will be used on the client side to select +enctypes, defaulting to +.Ar aes128-cts-hmac-sha1-96. +For compatibility with MIT, the enctypes string is a space- or +comma-separated list of enctype:salttype. +If +.Fl Fl keepold +is given, then old keys needed to decrypt extant tickets are +kept, and all other old keys are deleted. +If +.Fl Fl keepallold +is given then all old keys are kept. If +.Fl Fl pruneall is given then all old keys are removed. +The +.Fl Fl keepold +behavior is the default if none of these are given. +.Ed +.Pp +.Nm get +.Op Fl l | Fl Fl long +.Op Fl s | Fl Fl short +.Op Fl t | Fl Fl terse +.Op Fl o Ar string | Fl Fl column-info= Ns Ar string +.Op Fl C Ar path | Fl Fl krb5-config-file= Ns Ar path +.Op Fl Fl upto= Ns Ar number +.Ar principal... +.Bd -ragged -offset indent +Lists the matching principals, short prints the result as a table, +while long format produces a more verbose output. +If the +.Fl Fl upto= Ns Ar number +option is given, then only up to that many principals will be +listed. +.Pp +Which columns to print can be selected with the +.Fl o +option. The argument is a comma separated list of column names +optionally appended with an equal sign +.Pq Sq = +and a column header. Which columns are printed by default differ +slightly between short and long output. +.Pp +The default terse output format is similar to +.Fl s o Ar principal= , +just printing the names of matched principals. +.Pp +If +.Fl C +or +.Fl Fl krb5-config-file +is given and the principal has krb5 config file contents saved +in its HDB entry, then that will be saved in the given file. +Note that if multiple principals are requested, then the second, +third, and so on will have -1, -2, and so on appended to the +given filename unless the given filename is a device name. +.Pp +Possible column names include: +.Li principal , +.Li princ_expire_time , +.Li pw_expiration , +.Li last_pwd_change , +.Li max_life , +.Li max_rlife , +.Li mod_time , +.Li mod_name , +.Li attributes , +.Li kvno , +.Li mkvno , +.Li last_success , +.Li last_failed , +.Li fail_auth_count , +.Li policy , +and +.Li keytypes . +.Ed +.Pp +.Nm modify +.Oo Fl a Ar attributes \*(Ba Xo +.Fl Fl attributes= Ns Ar attributes +.Xc +.Oc +.Op Fl Fl max-ticket-life= Ns Ar lifetime +.Op Fl Fl max-renewable-life= Ns Ar lifetime +.Op Fl Fl expiration-time= Ns Ar time +.Op Fl Fl pw-expiration-time= Ns Ar time +.Op Fl Fl kvno= Ns Ar number +.Op Fl Fl policy= Ns Ar policy-name +.Op Fl Fl alias= Ns Ar alias-name +.Op Fl Fl constrained-delegation= Ns Ar principal-name +.Op Fl Fl pkinit-acl= Ns Ar subject-name +.Op Fl Fl service-enctypes= Ns Ar enctype +.Op Fl C Ar path | Fl Fl krb5-config-file= Ns Ar path +.Ar principal... +.Bd -ragged -offset indent +Modifies certain attributes of a principal. If run without command +line options, you will be prompted. With command line options, it will +only change the ones specified. +.Pp +The +.Fl Fl alias= Ns Ar alias-name +option may be given multiple times. +If this option is used at all, the complete list of aliases must +be given, with one option per-alias. +If the list given has fewer aliases than the principal had prior +to the modification, then the missing aliases will be deleted. +.Pp +Use the +.Nm add_alias +command instead to add an alias to avoid having to list all +existing aliases to keep. +.Pp +The +.Fl Fl alias= +option without a value allows the user to set an empty list of +aliases. +Use the +.Nm del_alias +command to delete one or more aliases. +.Pp +The only policy supported by Heimdal is +.Ql default . +.Pp +If a krb5 config file is given, it will be saved in the entry. +.Pp +Possible attributes are: +.Bl -tag -width Ds +.It new-princ +not used +.It support-desmd5 +not used +.It pwchange-service +for kadmin/admin style service principals +.It requires-pw-change +force the user to change their password +.It requires-hw-auth +.It requires-pre-auth +.It allow-digest +allow NTLM for this user in the KDC's digest service +.It trusted-for-delegation +.It ok-as-delegate +allow forwarding of tickets to this service principal +.It disallow-client +disallow issuance of tickets for this principal as a client +.It disallow-svr +disallow issuance of tickets for this principal as a server +.It disallow-all-tix +disallow issuance of tickets for this principal as a client or +server +.It disallow-dup-skey +not used +.It disallow-proxiable +disallow proxiable tickets +.It disallow-renewable , +disallow reneable tickets +.It disallow-tgt-based , +require initial tickets for this service, such as password +changing services +.It disallow-forwardable +disallow forwardable tickets +.It disallow-postdated +disallow postdated tickets +.It no-auth-data-reqd +do not include a PAC in tickets issued to this service +.It auth-data-reqd +do include a PAC in tickets issued to this service even if the +.Li disable_pac +KDC configuration parameter is set to true +.El +.Pp +Attributes may be negated with a "-", e.g., +.Pp +kadmin -l modify -a -disallow-proxiable user +.Pp +The +.Fl Fl constrained-delegation= Ns Ar principal-name +option is not currently implemented. +.Pp +The +.Fl Fl pkinit-acl= Ns Ar subject-name +option authorizes clients with certificates with the given +subject distinguished name to get tickets for the principal using +PKINIT. +This option can be given multiple times. +The PKINIT ACLs set with this option will replace the existing +ones. +.Pp +The +.Fl Fl service-enctypes= Ns Ar enctype +option indicates that the service supports the given enctype +regardless of whether the service has long-term keys of that +enctype. +This option can be given multiple times and will replace the +existing set of enctypes supported by the service. +If a service principal does not have any supported enctypes then +the KDC will assume that it supports only the enctypes of all of +its long-term keys. +.Pp +This command has the following alias: +.Nm mod . +.Ed +.Pp +.Nm passwd +.Op Fl Fl keepold | Fl Fl keepallold | Fl Fl pruneall +.Op Fl Fl enctypes= Ns Ar string +.Op Fl r | Fl Fl random-key +.Op Fl Fl random-password +.Oo Fl p Ar string \*(Ba Xo +.Fl Fl password= Ns Ar string +.Xc +.Oc +.Op Fl Fl key= Ns Ar string +.Ar principal... +.Bd -ragged -offset indent +Changes the password of an existing principal. +If enctypes to use are not given, then the +.Ar [libdefaults] supported_enctypes +configuration parameter will be used on the client side to select +enctypes, defaulting to +.Ar aes128-cts-hmac-sha1-96. +For compatibility with MIT, the enctypes string is a space- or +comma-separated list of enctype:salttype. +If +.Fl Fl keepold +is given, then old keys needed to decrypt extant tickets are +kept, and all other old keys are deleted. +If +.Fl Fl keepallold +is given then all old keys are kept. If +.Fl Fl pruneall is given then all old keys are removed. +The +.Fl Fl keepold +behavior is the default if none of these are given. +.Pp +This command has the following aliases: +.Nm cpw , +.Nm change_password . +.Ed +.Pp +.Nm verify-password-quality +.Ar principal +.Ar password +.Bd -ragged -offset indent +Run the password quality check function locally. +You can run this on the host that is configured to run the kadmind +process to verify that your configuration file is correct. +The verification is done locally, if kadmin is run in remote mode, +no rpc call is done to the server. NOTE: if the environment has +verify-password-quality configured to use a back-end that stores +password history (such as heimdal-history), running +verify-quality-password will cause an update to the password +database meaning that merely verifying the quality of the password +using verify-quality-password invalidates the use of that +principal/password in the future. +.Pp +This command has the following alias: +.Nm pwq . +.Ed +.Pp +.Nm privileges +.Bd -ragged -offset indent +Lists the operations you are allowed to perform. These include +.Li add , +.Li add_enctype , +.Li change-password , +.Li delete , +.Li del_enctype , +.Li get , +.Li get-keys , +.Li list , +and +.Li modify . +.Pp +This command has the following alias: +.Nm privs . +.Ed +.Pp +.Nm rename +.Ar from to +.Bd -ragged -offset indent +Renames a principal. This is normally transparent, but since keys are +salted with the principal name, they will have a non-standard salt, +and clients which are unable to cope with this will fail. Kerberos 4 +suffers from this. +.Ed +.Pp +.Nm check +.Op Ar realm +.Pp +.Bd -ragged -offset indent +Check database for strange configurations on important principals. If +no realm is given, the default realm is used. +.Ed +.Pp +When running in local mode, the following commands can also be used: +.Pp +.Nm dump +.Op Fl d | Fl Fl decrypt +.Op Fl f Ns Ar format | Fl Fl format= Ns Ar format +.Op Ar dump-file +.Bd -ragged -offset indent +Writes the database in +.Dq machine readable text +form to the specified file, or standard out. If the database is +encrypted, the dump will also have encrypted keys, unless +.Fl Fl decrypt +is used. If +.Fl Fl format=MIT +is used then the dump will be in MIT format. Otherwise it will be in +Heimdal format. +.Ed +.Pp +.Nm init +.Op Fl Fl realm-max-ticket-life= Ns Ar string +.Op Fl Fl realm-max-renewable-life= Ns Ar string +.Op Fl Fl bare +.Ar realm +.Bd -ragged -offset indent +Initializes the Kerberos database with entries for a new realm. +It's possible to have more than one realm served by one server +with the same database. +.Pp +If the +.Fl Fl bare +option is given, then only the root krbtgt principal for that +realm will be created. +.Ed +.Pp +.Nm load +.Ar file +.Bd -ragged -offset indent +Reads a previously dumped database, and re-creates that database from +scratch. +.Ed +.Pp +.Nm merge +.Ar file +.Bd -ragged -offset indent +Similar to +.Nm load +but just modifies the database with the entries in the dump file. +.Ed +.Pp +.Nm stash +.Oo Fl e Ar enctype \*(Ba Xo +.Fl Fl enctype= Ns Ar enctype +.Xc +.Oc +.Oo Fl k Ar keyfile \*(Ba Xo +.Fl Fl key-file= Ns Ar keyfile +.Xc +.Oc +.Op Fl Fl convert-file +.Op Fl Fl master-key-fd= Ns Ar fd +.Op Fl Fl random-password +.Bd -ragged -offset indent +Writes the Kerberos master key to a file used by the KDC. +.Pp +If the +.Fl Fl convert-file +option is given then convert an existing file to the new format. +If the +.Fl Fl master-key-fd= Ns Ar fd +option is given the the password will be read from the given file +descriptor. +If the +.Fl Fl random-password +option is given then a password will be generated randomly. +.Pp +This command has the following alias: +.Nm kstash . +.Ed +.Pp +.Nm exit +.Bd -ragged -offset indent +Exits +.Nm kadmin . +.Pp +This command has the following alias: +.Nm quit . +.Ed +.\".Sh ENVIRONMENT +.\".Sh FILES +.\".Sh EXAMPLES +.\".Sh DIAGNOSTICS +.Sh SEE ALSO +.Xr kadmind 8 , +.Xr kdc 8 +.\".Sh STANDARDS +.\".Sh HISTORY +.\".Sh AUTHORS +.\".Sh BUGS diff --git a/kadmin/kadmin.8 b/kadmin/kadmin.8 deleted file mode 100644 index 02a65e1a9..000000000 --- a/kadmin/kadmin.8 +++ /dev/null @@ -1,414 +0,0 @@ -.\" Copyright (c) 2000 - 2007 Kungliga Tekniska Högskolan -.\" (Royal Institute of Technology, Stockholm, Sweden). -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" 3. Neither the name of the Institute nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" $Id$ -.\" -.Dd Feb 22, 2007 -.Dt KADMIN 8 -.Os HEIMDAL -.Sh NAME -.Nm kadmin -.Nd Kerberos administration utility -.Sh SYNOPSIS -.Nm -.Bk -words -.Oo Fl p Ar string \*(Ba Xo -.Fl -principal= Ns Ar string -.Xc -.Oc -.Oo Fl K Ar string \*(Ba Xo -.Fl -keytab= Ns Ar string -.Xc -.Oc -.Oo Fl c Ar file \*(Ba Xo -.Fl -config-file= Ns Ar file -.Xc -.Oc -.Oo Fl k Ar file \*(Ba Xo -.Fl -key-file= Ns Ar file -.Xc -.Oc -.Oo Fl r Ar realm \*(Ba Xo -.Fl -realm= Ns Ar realm -.Xc -.Oc -.Oo Fl a Ar host \*(Ba Xo -.Fl -admin-server= Ns Ar host -.Xc -.Oc -.Oo Fl s Ar port number \*(Ba Xo -.Fl -server-port= Ns Ar port number -.Xc -.Oc -.Op Fl l | Fl -local -.Op Fl h | Fl -help -.Op Fl v | Fl -version -.Op Ar command -.Ek -.Sh DESCRIPTION -The -.Nm -program is used to make modifications to the Kerberos database, either remotely via the -.Xr kadmind 8 -daemon, or locally (with the -.Fl l -option). -.Pp -Supported options: -.Bl -tag -width Ds -.It Xo -.Fl p Ar string , -.Fl -principal= Ns Ar string -.Xc -principal to authenticate as -.It Xo -.Fl K Ar string , -.Fl -keytab= Ns Ar string -.Xc -keytab for authentication principal -.It Xo -.Fl c Ar file , -.Fl -config-file= Ns Ar file -.Xc -location of config file -.It Xo -.Fl k Ar file , -.Fl -key-file= Ns Ar file -.Xc -location of master key file -.It Xo -.Fl r Ar realm , -.Fl -realm= Ns Ar realm -.Xc -realm to use -.It Xo -.Fl a Ar host , -.Fl -admin-server= Ns Ar host -.Xc -server to contact -.It Xo -.Fl s Ar port number , -.Fl -server-port= Ns Ar port number -.Xc -port to use -.It Xo -.Fl l , -.Fl -local -.Xc -local admin mode -.El -.Pp -If no -.Ar command -is given on the command line, -.Nm -will prompt for commands to process. Some of the commands that take -one or more principals as argument -.Ns ( Nm delete , -.Nm ext_keytab , -.Nm get , -.Nm modify , -and -.Nm passwd ) -will accept a glob style wildcard, and perform the operation on all -matching principals. -.Pp -Commands include: -.\" not using a list here, since groff apparently gets confused -.\" with nested Xo/Xc -.Bd -ragged -offset indent -.Nm add -.Op Fl r | Fl -random-key -.Op Fl -random-password -.Oo Fl p Ar string \*(Ba Xo -.Fl -password= Ns Ar string -.Xc -.Oc -.Op Fl -key= Ns Ar string -.Op Fl -max-ticket-life= Ns Ar lifetime -.Op Fl -max-renewable-life= Ns Ar lifetime -.Op Fl -attributes= Ns Ar attributes -.Op Fl -expiration-time= Ns Ar time -.Op Fl -pw-expiration-time= Ns Ar time -.Ar principal... -.Pp -.Bd -ragged -offset indent -Adds a new principal to the database. The options not passed on the -command line will be promped for. -.Ed -.Pp -.Nm add_enctype -.Op Fl r | Fl -random-key -.Ar principal enctypes... -.Pp -.Bd -ragged -offset indent -Adds a new encryption type to the principal, only random key are -supported. -.Ed -.Pp -.Nm delete -.Ar principal... -.Pp -.Bd -ragged -offset indent -Removes a principal. -.Ed -.Pp -.Nm del_enctype -.Ar principal enctypes... -.Pp -.Bd -ragged -offset indent -Removes some enctypes from a principal; this can be useful if the -service belonging to the principal is known to not handle certain -enctypes. -.Ed -.Pp -.Nm ext_keytab -.Oo Fl k Ar string \*(Ba Xo -.Fl -keytab= Ns Ar string -.Xc -.Oc -.Ar principal... -.Pp -.Bd -ragged -offset indent -Creates a keytab with the keys of the specified principals. -.Ed -.Pp -.Nm get -.Op Fl l | Fl -long -.Op Fl s | Fl -short -.Op Fl t | Fl -terse -.Op Fl o Ar string | Fl -column-info= Ns Ar string -.Ar principal... -.Pp -.Bd -ragged -offset indent -Lists the matching principals, short prints the result as a table, -while long format produces a more verbose output. Which columns to -print can be selected with the -.Fl o -option. The argument is a comma separated list of column names -optionally appended with an equal sign -.Pq Sq = -and a column header. Which columns are printed by default differ -slightly between short and long output. -.Pp -The default terse output format is similar to -.Fl s o Ar principal= , -just printing the names of matched principals. -.Pp -Possible column names include: -.Li principal , -.Li princ_expire_time , -.Li pw_expiration , -.Li last_pwd_change , -.Li max_life , -.Li max_rlife , -.Li mod_time , -.Li mod_name , -.Li attributes , -.Li kvno , -.Li mkvno , -.Li last_success , -.Li last_failed , -.Li fail_auth_count , -.Li policy , -and -.Li keytypes . -.Ed -.Pp -.Nm modify -.Oo Fl a Ar attributes \*(Ba Xo -.Fl -attributes= Ns Ar attributes -.Xc -.Oc -.Op Fl -max-ticket-life= Ns Ar lifetime -.Op Fl -max-renewable-life= Ns Ar lifetime -.Op Fl -expiration-time= Ns Ar time -.Op Fl -pw-expiration-time= Ns Ar time -.Op Fl -kvno= Ns Ar number -.Ar principal... -.Pp -.Bd -ragged -offset indent -Modifies certain attributes of a principal. If run without command -line options, you will be prompted. With command line options, it will -only change the ones specified. -.Pp -Possible attributes are: -.Li new-princ , -.Li support-desmd5 , -.Li pwchange-service , -.Li disallow-svr , -.Li requires-pw-change , -.Li requires-hw-auth , -.Li requires-pre-auth , -.Li disallow-all-tix , -.Li disallow-dup-skey , -.Li disallow-proxiable , -.Li disallow-renewable , -.Li disallow-tgt-based , -.Li disallow-forwardable , -.Li disallow-postdated -.Pp -Attributes may be negated with a "-", e.g., -.Pp -kadmin -l modify -a -disallow-proxiable user -.Ed -.Pp -.Nm passwd -.Op Fl r | Fl -random-key -.Op Fl -random-password -.Oo Fl p Ar string \*(Ba Xo -.Fl -password= Ns Ar string -.Xc -.Oc -.Op Fl -key= Ns Ar string -.Ar principal... -.Pp -.Bd -ragged -offset indent -Changes the password of an existing principal. -.Ed -.Pp -.Nm password-quality -.Ar principal -.Ar password -.Pp -.Bd -ragged -offset indent -Run the password quality check function locally. -You can run this on the host that is configured to run the kadmind -process to verify that your configuration file is correct. -The verification is done locally, if kadmin is run in remote mode, -no rpc call is done to the server. -.Ed -.Pp -.Nm privileges -.Pp -.Bd -ragged -offset indent -Lists the operations you are allowed to perform. These include -.Li add , -.Li add_enctype , -.Li change-password , -.Li delete , -.Li del_enctype , -.Li get , -.Li list , -and -.Li modify . -.Ed -.Pp -.Nm rename -.Ar from to -.Pp -.Bd -ragged -offset indent -Renames a principal. This is normally transparent, but since keys are -salted with the principal name, they will have a non-standard salt, -and clients which are unable to cope with this will fail. Kerberos 4 -suffers from this. -.Ed -.Pp -.Nm check -.Op Ar realm -.Pp -.Bd -ragged -offset indent -Check database for strange configurations on important principals. If -no realm is given, the default realm is used. -.Ed -.Pp -.Ed -.Pp -When running in local mode, the following commands can also be used: -.Bd -ragged -offset indent -.Nm dump -.Op Fl d | Fl -decrypt -.Op Ar dump-file -.Pp -.Bd -ragged -offset indent -Writes the database in -.Dq human readable -form to the specified file, or standard out. If the database is -encrypted, the dump will also have encrypted keys, unless -.Fl -decrypt -is used. -.Ed -.Pp -.Nm init -.Op Fl -realm-max-ticket-life= Ns Ar string -.Op Fl -realm-max-renewable-life= Ns Ar string -.Ar realm -.Pp -.Bd -ragged -offset indent -Initializes the Kerberos database with entries for a new realm. It's -possible to have more than one realm served by one server. -.Ed -.Pp -.Nm load -.Ar file -.Pp -.Bd -ragged -offset indent -Reads a previously dumped database, and re-creates that database from -scratch. -.Ed -.Pp -.Nm merge -.Ar file -.Pp -.Bd -ragged -offset indent -Similar to -.Nm load -but just modifies the database with the entries in the dump file. -.Ed -.Pp -.Nm stash -.Oo Fl e Ar enctype \*(Ba Xo -.Fl -enctype= Ns Ar enctype -.Xc -.Oc -.Oo Fl k Ar keyfile \*(Ba Xo -.Fl -key-file= Ns Ar keyfile -.Xc -.Oc -.Op Fl -convert-file -.Op Fl -master-key-fd= Ns Ar fd -.Pp -.Bd -ragged -offset indent -Writes the Kerberos master key to a file used by the KDC. -.Ed -.Pp -.Ed -.\".Sh ENVIRONMENT -.\".Sh FILES -.\".Sh EXAMPLES -.\".Sh DIAGNOSTICS -.Sh SEE ALSO -.Xr kadmind 8 , -.Xr kdc 8 -.\".Sh STANDARDS -.\".Sh HISTORY -.\".Sh AUTHORS -.\".Sh BUGS diff --git a/kadmin/kadmin.c b/kadmin/kadmin.c index faebef9d6..607ba03e2 100644 --- a/kadmin/kadmin.c +++ b/kadmin/kadmin.c @@ -35,14 +35,13 @@ #include "kadmin-commands.h" #include -RCSID("$Id$"); - static char *config_file; static char *keyfile; int local_flag; static int ad_flag; static int help_flag; static int version_flag; +static char *hdb; static char *realm; static char *admin_server; static int server_port = 0; @@ -54,9 +53,9 @@ static getarg_strings policy_libraries = { 0, NULL }; static struct getargs args[] = { { "principal", 'p', arg_string, &client_name, - "principal to authenticate as" }, + "principal to authenticate as", NULL }, { "keytab", 'K', arg_string, &keytab, - "keytab for authentication principal" }, + "keytab for authentication principal", NULL }, { "config-file", 'c', arg_string, &config_file, "location of config file", "file" @@ -65,19 +64,24 @@ static struct getargs args[] = { "key-file", 'k', arg_string, &keyfile, "location of master key file", "file" }, - { + { + "hdb", 'H', arg_string, &hdb, + "HDB to use", "hdb" + }, + { "realm", 'r', arg_string, &realm, "realm to use", "realm" }, - { + { "admin-server", 'a', arg_string, &admin_server, "server to contact", "host" }, - { + { "server-port", 's', arg_integer, &server_port, "port to use", "port number" }, - { "ad", 0, arg_flag, &ad_flag, "active directory admin mode" }, + { "ad", 0, arg_flag, &ad_flag, "active directory admin mode", + NULL }, #ifdef HAVE_DLOPEN { "check-library", 0, arg_string, &check_library, "library to load password check function from", "library" }, @@ -86,9 +90,9 @@ static struct getargs args[] = { { "policy-libraries", 0, arg_strings, &policy_libraries, "password check function to load", "function" }, #endif - { "local", 'l', arg_flag, &local_flag, "local admin mode" }, - { "help", 'h', arg_flag, &help_flag }, - { "version", 'v', arg_flag, &version_flag } + { "local", 'l', arg_flag, &local_flag, "local admin mode", NULL }, + { "help", 'h', arg_flag, &help_flag, NULL, NULL }, + { "version", 'v', arg_flag, &version_flag, NULL, NULL } }; static int num_args = sizeof(args) / sizeof(args[0]); @@ -113,6 +117,18 @@ exit_kadmin (void *opt, int argc, char **argv) return 0; } +int +lock(void *opt, int argc, char **argv) +{ + return kadm5_lock(kadm_handle); +} + +int +unlock(void *opt, int argc, char **argv) +{ + return kadm5_unlock(kadm_handle); +} + static void usage(int ret) { @@ -148,6 +164,7 @@ main(int argc, char **argv) kadm5_config_params conf; int optidx = 0; int exit_status = 0; + int aret; setprogname(argv[0]); @@ -170,8 +187,8 @@ main(int argc, char **argv) argv += optidx; if (config_file == NULL) { - asprintf(&config_file, "%s/kdc.conf", hdb_db_dir(context)); - if (config_file == NULL) + aret = asprintf(&config_file, "%s/kdc.conf", hdb_db_dir(context)); + if (aret == -1) errx(1, "out of memory"); } @@ -192,6 +209,11 @@ main(int argc, char **argv) conf.mask |= KADM5_CONFIG_REALM; } + if (hdb) { + conf.dbname = hdb; + conf.mask |= KADM5_CONFIG_DBNAME; + } + if (admin_server) { conf.admin_server = admin_server; conf.mask |= KADM5_CONFIG_ADMIN_SERVER; @@ -212,7 +234,7 @@ main(int argc, char **argv) kadm5_setup_passwd_quality_check (context, check_library, check_function); - + for (i = 0; i < policy_libraries.num_strings; i++) { ret = kadm5_add_passwd_quality_verifier(context, policy_libraries.strings[i]); @@ -222,7 +244,7 @@ main(int argc, char **argv) ret = kadm5_add_passwd_quality_verifier(context, NULL); if (ret) krb5_err(context, 1, ret, "kadm5_add_passwd_quality_verifier"); - + ret = kadm5_s_init_with_password_ctx(context, KADM5_ADMIN_SERVICE, NULL, @@ -266,7 +288,7 @@ main(int argc, char **argv) if (argc != 0) { ret = sl_command (commands, argc, argv); if(ret == -1) - krb5_warnx (context, "unrecognized command: %s", argv[0]); + sl_did_you_mean(commands, argv[0]); else if (ret == -2) ret = 0; if(ret != 0) @@ -274,10 +296,13 @@ main(int argc, char **argv) } else { while(!exit_seen) { ret = sl_command_loop(commands, "kadmin> ", NULL); - if (ret == -2) + if (ret == -2) { exit_seen = 1; - else if (ret != 0) + } else if (ret != 0) { exit_status = 1; + if (!isatty(STDIN_FILENO)) + exit_seen = 1; + } } } diff --git a/kadmin/kadmin_locl.h b/kadmin/kadmin_locl.h index 28733dd08..6ad36b909 100644 --- a/kadmin/kadmin_locl.h +++ b/kadmin/kadmin_locl.h @@ -98,6 +98,7 @@ extern krb5_context context; extern void * kadm_handle; +extern int list_chunk_size; #undef ALLOC #define ALLOC(X) ((X) = malloc(sizeof(*(X)))) @@ -109,6 +110,9 @@ int str2attributes(const char *, krb5_flags *); int parse_attributes (const char *, krb5_flags *, int *, int); int edit_attributes (const char *, krb5_flags *, int *, int); +int parse_policy (const char *, char **, int *, int); +int edit_policy (const char *, char **, int *, int); + void time_t2str(time_t, char *, size_t, int); int str2time_t (const char *, time_t *); int parse_timet (const char *, krb5_timestamp *, int *, int); @@ -124,7 +128,7 @@ int edit_entry(kadm5_principal_ent_t, int *, kadm5_principal_ent_t, int); void set_defaults(kadm5_principal_ent_t, int *, kadm5_principal_ent_t, int); int set_entry(krb5_context, kadm5_principal_ent_t, int *, const char *, const char *, const char *, - const char *, const char *); + const char *, const char *, const char *); int foreach_principal(const char *, int (*)(krb5_principal, void*), const char *, void *); @@ -141,17 +145,24 @@ random_password(char *, size_t); extern sig_atomic_t term_flag, doing_useful_work; void parse_ports(krb5_context, const char*); -int start_server(krb5_context); +void start_server(krb5_context, const char*); /* server.c */ krb5_error_code -kadmind_loop (krb5_context, krb5_keytab, int); +kadmind_loop (krb5_context, krb5_keytab, int, int); /* rpc.c */ int -handle_mit(krb5_context, void *, size_t, int); +handle_mit(krb5_context, void *, size_t, int, int); +/* mod.c */ + +void +add_tl(kadm5_principal_ent_rec *, int, krb5_data *); + +krb5_tl_data * +get_tl(kadm5_principal_ent_rec *, int); #endif /* __ADMIN_LOCL_H__ */ diff --git a/kadmin/kadmind-version.rc b/kadmin/kadmind-version.rc new file mode 100644 index 000000000..090bc816d --- /dev/null +++ b/kadmin/kadmind-version.rc @@ -0,0 +1,36 @@ +/*********************************************************************** + * Copyright (c) 2010, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#define RC_FILE_TYPE VFT_APP +#define RC_FILE_DESC_0409 "Kerberos Administration Server" +#define RC_FILE_ORIG_0409 "kadmind.exe" + +#include "../windows/version.rc" diff --git a/kadmin/kadmind.8 b/kadmin/kadmind.8 index bb81b6394..9ff1f52ce 100644 --- a/kadmin/kadmind.8 +++ b/kadmin/kadmind.8 @@ -1,34 +1,34 @@ .\" Copyright (c) 2002 - 2004 Kungliga Tekniska Högskolan -.\" (Royal Institute of Technology, Stockholm, Sweden). -.\" All rights reserved. +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. .\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: .\" -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. .\" -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. .\" -.\" 3. Neither the name of the Institute nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. .\" -.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" .\" $Id$ .\" .Dd December 8, 2004 @@ -41,21 +41,21 @@ .Nm .Bk -words .Oo Fl c Ar file \*(Ba Xo -.Fl -config-file= Ns Ar file +.Fl Fl config-file= Ns Ar file .Xc .Oc .Oo Fl k Ar file \*(Ba Xo -.Fl -key-file= Ns Ar file +.Fl Fl key-file= Ns Ar file .Xc .Oc -.Op Fl -keytab= Ns Ar keytab +.Op Fl Fl keytab= Ns Ar keytab .Oo Fl r Ar realm \*(Ba Xo -.Fl -realm= Ns Ar realm +.Fl Fl realm= Ns Ar realm .Xc .Oc -.Op Fl d | Fl -debug +.Op Fl d | Fl Fl debug .Oo Fl p Ar port \*(Ba Xo -.Fl -ports= Ns Ar port +.Fl Fl ports= Ns Ar port .Xc .Oc .Ek @@ -67,7 +67,7 @@ assumes that it has been started by .Xr inetd 8 , otherwise it behaves as a daemon, forking processes for each new connection. The -.Fl -debug +.Fl Fl debug option causes .Nm to accept exactly one connection, which is useful for debugging. @@ -76,8 +76,7 @@ The .Xr kpasswdd 8 daemon is responsible for the Kerberos 5 password changing protocol (used by -.Xr kpasswd 1 ) -. +.Xr kpasswd 1 ) . .Pp This daemon should only be run on the master server, and not on any slaves. @@ -108,7 +107,9 @@ add .It get .It -all +get-keys +.It +all (everything except get-keys) .El .Pp And the optional @@ -118,34 +119,17 @@ glob-style pattern. .Pp Supported options: .Bl -tag -width Ds -.It Xo -.Fl c Ar file , -.Fl -config-file= Ns Ar file -.Xc +.It Fl c Ar file , Fl Fl config-file= Ns Ar file location of config file -.It Xo -.Fl k Ar file , -.Fl -key-file= Ns Ar file -.Xc +.It Fl k Ar file , Fl Fl key-file= Ns Ar file location of master key file -.It Xo -.Fl -keytab= Ns Ar keytab -.Xc +.It Fl Fl keytab= Ns Ar keytab what keytab to use -.It Xo -.Fl r Ar realm , -.Fl -realm= Ns Ar realm -.Xc +.It Fl r Ar realm , Fl Fl realm= Ns Ar realm realm to use -.It Xo -.Fl d , -.Fl -debug -.Xc +.It Fl d , Fl Fl debug enable debugging -.It Xo -.Fl p Ar port , -.Fl -ports= Ns Ar port -.Xc +.It Fl p Ar port , Fl Fl ports= Ns Ar port ports to listen to. By default, if run as a daemon, it listens to port 749, but you can add any number of ports with this option. The port string is a whitespace separated list of port specifications, with the @@ -162,17 +146,49 @@ This will cause to listen to port 4711 in addition to any compiled in defaults: .Pp -.D1 Nm Fl -ports Ns Li "=\*[q]+ 4711\*[q] &" +.D1 Nm Fl Fl ports Ns Li "=\*[q]+ 4711\*[q] &" .Pp This acl file will grant Joe all rights, and allow Mallory to view and -add host principals. +add host principals, as well as extract host principal keys (e.g., into +keytabs). .Bd -literal -offset indent joe/admin@EXAMPLE.COM all -mallory/admin@EXAMPLE.COM add,get host/*@EXAMPLE.COM +mallory/admin@EXAMPLE.COM add,get-keys host/*@EXAMPLE.COM .Ed -.\".Sh DIAGNOSTICS +.Sh CONFIGURATION FILE +kadmind uses the following configuration parameters from the +.Ar [kadmin] +section of +.Ar krb5.conf: +.Bl -tag -width Ds -offset indent +.It password_lifetime +.El +.Pp +kadmind uses the following configuration parameters from the per-realm entries +in the +.Ar [realms] +section of +.Ar krb5.conf: +.Bl -tag -width Ds -offset indent +.It supported_enctypes +.El +.Pp +kadmind uses the following configuration parameters from the +.Ar [password_quality] +section of +.Ar krb5.conf: +.Bl -tag -width Ds -offset indent +.It enforce_on_admin_set +.It min_length +.It min_classes +.It external_program +.It check_library +.It check_function +.It policy_libraries +.It policies +.El .Sh SEE ALSO .Xr kpasswd 1 , -.Xr kadmin 8 , +.Xr kadmin 1 , .Xr kdc 8 , .Xr kpasswdd 8 diff --git a/kadmin/kadmind.c b/kadmin/kadmind.c index 318989adf..4ea513e08 100644 --- a/kadmin/kadmind.c +++ b/kadmin/kadmind.c @@ -32,19 +32,32 @@ */ #include "kadmin_locl.h" - -RCSID("$Id$"); +#include "heim_threads.h" +#include "krb5-protos.h" static char *check_library = NULL; static char *check_function = NULL; static getarg_strings policy_libraries = { 0, NULL }; static char *config_file; -static char *keytab_str = "HDB:"; +static char sHDB[] = "HDBGET:"; +static char *keytab_str = sHDB; +#ifndef WIN32 +static char *fuzz_file; +static char *fuzz_client_name; +static char *fuzz_keytab_name; +static char *fuzz_service_name; +static char *fuzz_admin_server; +#endif static int help_flag; static int version_flag; static int debug_flag; +static int readonly_flag; static char *port_str; char *realm; +int list_chunk_size = -1; + +static int detach_from_console = -1; +int daemon_child = -1; static struct getargs args[] = { { @@ -67,12 +80,35 @@ static struct getargs args[] = { "password check function to load", "function" }, #endif { "debug", 'd', arg_flag, &debug_flag, - "enable debugging" + "enable debugging", NULL + }, + { "list-chunk-size", 0, arg_integer,&list_chunk_size, + "set the LIST streaming count of names per chunk", "NUMBER" + }, + { + "detach", 0 , arg_flag, &detach_from_console, + "detach from console", NULL + }, + { + "daemon-child", 0 , arg_integer, &daemon_child, + "private argument, do not use", NULL }, { "ports", 'p', arg_string, &port_str, "ports to listen to", "port" }, - { "help", 'h', arg_flag, &help_flag }, - { "version", 'v', arg_flag, &version_flag } + { "read-only", 0, arg_flag, &readonly_flag, + "read-only operations", NULL }, +#ifndef WIN32 + { "fuzz-file", 0, arg_string, &fuzz_file, + "Kadmin RPC body for fuzzing", "FILE" }, + { "fuzz-client", 0, arg_string, &fuzz_client_name, + "Client name for fuzzing", "PRINCIPAL" }, + { "fuzz-keytab", 0, arg_string, &fuzz_keytab_name, + "Keytab for fuzzing", "KEYTAB" }, + { "fuzz-server", 0, arg_string, &fuzz_admin_server, + "Name of kadmind self instance", "HOST:PORT" }, +#endif + { "help", 'h', arg_flag, &help_flag, NULL, NULL }, + { "version", 'v', arg_flag, &version_flag, NULL, NULL } }; static int num_args = sizeof(args) / sizeof(args[0]); @@ -86,6 +122,8 @@ usage(int ret) exit (ret); } +static void *fuzz_thread(void *); + int main(int argc, char **argv) { @@ -95,13 +133,10 @@ main(int argc, char **argv) int i; krb5_log_facility *logfacility; krb5_keytab keytab; + krb5_socket_t sfd = rk_INVALID_SOCKET; setprogname(argv[0]); - ret = krb5_init_context(&context); - if (ret) - errx (1, "krb5_init_context failed: %d", ret); - if (getarg(args, num_args, argc, argv, &optidx)) { warnx("error at argument `%s'", argv[optidx]); usage(1); @@ -115,12 +150,23 @@ main(int argc, char **argv) exit(0); } + if (detach_from_console > 0 && daemon_child == -1) + daemon_child = roken_detach_prep(argc, argv, "--daemon-child"); + + ret = krb5_init_context(&context); + if (ret) + errx (1, "krb5_init_context failed: %d", ret); + argc -= optidx; argv += optidx; + if (argc != 0) + usage(1); if (config_file == NULL) { - asprintf(&config_file, "%s/kdc.conf", hdb_db_dir(context)); - if (config_file == NULL) + int aret; + + aret = asprintf(&config_file, "%s/kdc.conf", hdb_db_dir(context)); + if (aret == -1) errx(1, "out of memory"); } @@ -140,7 +186,7 @@ main(int argc, char **argv) if (ret) krb5_err(context, 1, ret, "krb5_set_warn_dest"); - ret = krb5_kt_register(context, &hdb_kt_ops); + ret = krb5_kt_register(context, &hdb_get_kt_ops); if(ret) krb5_err(context, 1, ret, "krb5_kt_register"); @@ -162,14 +208,17 @@ main(int argc, char **argv) if(debug_flag) { int debug_port; - + if(port_str == NULL) debug_port = krb5_getportbyname (context, "kerberos-adm", "tcp", 749); else debug_port = htons(atoi(port_str)); - mini_inetd(debug_port); + mini_inetd(debug_port, &sfd); } else { +#ifdef _WIN32 + start_server(context, port_str); +#else struct sockaddr_storage __ss; struct sockaddr *sa = (struct sockaddr *)&__ss; socklen_t sa_size = sizeof(__ss); @@ -178,19 +227,92 @@ main(int argc, char **argv) * Check if we are running inside inetd or not, if not, start * our own server. */ - + if(roken_getsockname(STDIN_FILENO, sa, &sa_size) < 0 && - errno == ENOTSOCK) { - parse_ports(context, port_str ? port_str : "+"); - pidfile(NULL); - start_server(context); + rk_SOCK_ERRNO == ENOTSOCK) { + start_server(context, port_str); } +#endif /* _WIN32 */ + sfd = STDIN_FILENO; + + socket_set_keepalive(sfd, 1); } - + if(realm) krb5_set_default_realm(context, realm); /* XXX */ - kadmind_loop(context, keytab, STDIN_FILENO); +#ifndef WIN32 + if (fuzz_file) { + HEIMDAL_THREAD_ID tid; + + if (fuzz_admin_server == NULL) + errx(1, "If --fuzz-file is given then --fuzz-server must be too"); + HEIMDAL_THREAD_create(&tid, fuzz_thread, NULL); + } +#endif + + kadmind_loop(context, keytab, sfd, readonly_flag); return 0; } + +#ifndef WIN32 +static void * +fuzz_thread(void *arg) +{ + kadm5_config_params conf; + krb5_error_code ret; + krb5_context context2; + krb5_storage *sp; + krb5_data reply; + void *server_handle = NULL; + int fd; + + memset(&conf, 0, sizeof(conf)); + conf.admin_server = fuzz_admin_server; + + fd = open(fuzz_file, O_RDONLY); + if (fd < 0) + err(1, "Could not open fuzz file %s", fuzz_file); + sp = krb5_storage_from_fd(fd); + if (sp == NULL) + err(1, "Could not read fuzz file %s", fuzz_file); + (void) close(fd); + + ret = krb5_init_context(&context2); + if (ret) + errx(1, "Fuzzing failed: krb5_init_context failed: %d", ret); + ret = kadm5_c_init_with_skey_ctx(context2, + fuzz_client_name, + fuzz_keytab_name, + fuzz_service_name ? + fuzz_service_name : + KADM5_ADMIN_SERVICE, + &conf, + 0, /* struct_version */ + 0, /* api_version */ + &server_handle); + if (ret) + errx(1, "Fuzzing failed: kadm5_c_init_with_skey_ctx failed: %d", ret); + + ret = _kadm5_connect(server_handle, 1 /* want_write */); + if (ret) + errx(1, "Fuzzing failed: Could not connect to self (%s): " + "_kadm5_connect failed: %d", fuzz_admin_server, ret); + ret = _kadm5_client_send(server_handle, sp); + if (ret) + errx(1, "Fuzzing failed: Could not send request to self (%s): " + "_kadm5_client_send failed: %d", fuzz_admin_server, ret); + krb5_data_zero(&reply); + ret = _kadm5_client_recv(server_handle, &reply); + if (ret) + errx(1, "Fuzzing failed: Could not read reply from self (%s): " + "_kadm5_client_recv failed: %d", fuzz_admin_server, ret); + krb5_storage_free(sp); + krb5_data_free(&reply); + fprintf(stderr, "Fuzzed with %s", fuzz_file); + exit(0); + + return NULL; +} +#endif diff --git a/kadmin/load.c b/kadmin/load.c index 0fb305eec..f62f8b96d 100644 --- a/kadmin/load.c +++ b/kadmin/load.c @@ -31,12 +31,12 @@ * SUCH DAMAGE. */ +#include + #include "kadmin_locl.h" #include "kadmin-commands.h" #include -RCSID("$Id$"); - struct entry { char *principal; char *key; @@ -155,7 +155,7 @@ parse_keys(hdb_entry *ent, char *str) krb5_error_code ret; int tmp; char *p; - int i; + size_t i; p = strsep(&str, ":"); if (sscanf(p, "%d", &tmp) != 1) @@ -207,7 +207,7 @@ parse_keys(hdb_entry *ent, char *str) if (key->salt == NULL) krb5_errx (context, 1, "malloc: out of memory"); key->salt->type = type; - + if (p_len) { if(*p == '\"') { ret = krb5_data_copy(&key->salt->salt, p + 1, p_len - 2); @@ -310,9 +310,11 @@ parse_generation(char *str, GENERATION **gen) return 0; } +/* On error modify strp to point to the problem element */ static int -parse_extensions(char *str, HDB_extensions **e) +parse_extensions(char **strp, HDB_extensions **e) { + char *str = *strp; char *p; int ret; @@ -330,18 +332,21 @@ parse_extensions(char *str, HDB_extensions **e) void *d; len = strlen(p); - d = malloc(len); + d = emalloc(len); len = hex_decode(p, d, len); if (len < 0) { free(d); + *strp = p; return -1; } ret = decode_HDB_extension(d, len, &ext, NULL); free(d); - if (ret) + if (ret) { + *strp = p; return -1; + } d = realloc((*e)->val, ((*e)->len + 1) * sizeof((*e)->val[0])); if (d == NULL) abort(); @@ -355,6 +360,45 @@ parse_extensions(char *str, HDB_extensions **e) return 0; } +/* XXX: Principal names with '\n' cannot be dumped or loaded */ +static int +my_fgetln(FILE *f, char **bufp, size_t *szp, size_t *lenp) +{ + size_t len; + size_t sz = *szp; + char *buf = *bufp; + char *n; + + if (!buf) { + buf = malloc(sz ? sz : 8192); + if (!buf) + return ENOMEM; + if (!sz) + sz = 8192; + } + + len = 0; + while (fgets(&buf[len], sz-len, f) != NULL) { + len += strlen(&buf[len]); + if (buf[len-1] == '\n') + break; + if (feof(f)) + break; + if (sz > SIZE_MAX/2 || + (n = realloc(buf, sz += 1 + (sz >> 1))) == NULL) { + free(buf); + *bufp = NULL; + *szp = 0; + *lenp = 0; + return ENOMEM; + } + buf = n; + } + *bufp = buf; + *szp = sz; + *lenp = len; + return 0; /* *len == 0 || no EOL -> EOF */ +} /* * Parse the dump file in `filename' and create the database (merging @@ -364,56 +408,70 @@ parse_extensions(char *str, HDB_extensions **e) static int doit(const char *filename, int mergep) { - krb5_error_code ret; + krb5_error_code ret = 0; + krb5_error_code ret2 = 0; FILE *f; - char s[8192]; /* XXX should fix this properly */ + char *line = NULL; + size_t linesz = 0; + size_t linelen = 0; char *p; - int line; + int lineno; int flags = O_RDWR; struct entry e; - hdb_entry_ex ent; + hdb_entry ent; HDB *db = _kadm5_s_get_db(kadm_handle); f = fopen(filename, "r"); - if(f == NULL){ + if (f == NULL) { krb5_warn(context, errno, "fopen(%s)", filename); return 1; } - ret = kadm5_log_truncate (kadm_handle); + /* + * We don't have a version number in the dump, so we don't know which iprop + * log entries to keep, if any. We throw the log away. + * + * We could merge the ipropd-master/slave dump/load here as an option, in + * which case we would first load the dump. + * + * If we're merging, first recover unconfirmed records in the existing log. + */ + if (mergep) + ret = kadm5_log_init(kadm_handle); + if (ret == 0) + ret = kadm5_log_reinit(kadm_handle, 0); if (ret) { fclose (f); - krb5_warn(context, ret, "kadm5_log_truncate"); + krb5_warn(context, ret, "kadm5_log_reinit"); return 1; } - if(!mergep) + if (!mergep) flags |= O_CREAT | O_TRUNC; ret = db->hdb_open(context, db, flags, 0600); - if(ret){ + if (ret){ krb5_warn(context, ret, "hdb_open"); fclose(f); return 1; } - line = 0; - ret = 0; - while(fgets(s, sizeof(s), f) != NULL) { - line++; - - p = s; + (void) db->hdb_set_sync(context, db, 0); + for (lineno = 1; + (ret2 = my_fgetln(f, &line, &linesz, &linelen)) == 0 && linelen > 0; + ++lineno) { + p = line; while (isspace((unsigned char)*p)) p++; e.principal = p; - for(p = s; *p; p++){ - if(*p == '\\') + for (p = line; *p; p++){ + if (*p == '\\') /* Support '\n' escapes??? */ p++; - else if(isspace((unsigned char)*p)) { + else if (isspace((unsigned char)*p)) { *p = 0; break; } } p = skip_next(p); - + e.key = p; p = skip_next(p); @@ -448,97 +506,119 @@ doit(const char *filename, int mergep) skip_next(p); memset(&ent, 0, sizeof(ent)); - ret = krb5_parse_name(context, e.principal, &ent.entry.principal); - if(ret) { + ret2 = krb5_parse_name(context, e.principal, &ent.principal); + if (ret2) { + const char *msg = krb5_get_error_message(context, ret); fprintf(stderr, "%s:%d:%s (%s)\n", - filename, - line, - krb5_get_err_text(context, ret), - e.principal); + filename, lineno, msg, e.principal); + krb5_free_error_message(context, msg); + ret = 1; continue; } - - if (parse_keys(&ent.entry, e.key)) { + + if (parse_keys(&ent, e.key)) { fprintf (stderr, "%s:%d:error parsing keys (%s)\n", - filename, line, e.key); - hdb_free_entry (context, &ent); + filename, lineno, e.key); + hdb_free_entry (context, db, &ent); + ret = 1; continue; } - - if (parse_event(&ent.entry.created_by, e.created) == -1) { + + if (parse_event(&ent.created_by, e.created) == -1) { fprintf (stderr, "%s:%d:error parsing created event (%s)\n", - filename, line, e.created); - hdb_free_entry (context, &ent); + filename, lineno, e.created); + hdb_free_entry (context, db, &ent); + ret = 1; continue; } - if (parse_event_alloc (&ent.entry.modified_by, e.modified) == -1) { + if (parse_event_alloc (&ent.modified_by, e.modified) == -1) { fprintf (stderr, "%s:%d:error parsing event (%s)\n", - filename, line, e.modified); - hdb_free_entry (context, &ent); + filename, lineno, e.modified); + hdb_free_entry (context, db, &ent); + ret = 1; continue; } - if (parse_time_string_alloc (&ent.entry.valid_start, e.valid_start) == -1) { + if (parse_time_string_alloc (&ent.valid_start, e.valid_start) == -1) { fprintf (stderr, "%s:%d:error parsing time (%s)\n", - filename, line, e.valid_start); - hdb_free_entry (context, &ent); + filename, lineno, e.valid_start); + hdb_free_entry (context, db, &ent); + ret = 1; continue; } - if (parse_time_string_alloc (&ent.entry.valid_end, e.valid_end) == -1) { + if (parse_time_string_alloc (&ent.valid_end, e.valid_end) == -1) { fprintf (stderr, "%s:%d:error parsing time (%s)\n", - filename, line, e.valid_end); - hdb_free_entry (context, &ent); + filename, lineno, e.valid_end); + hdb_free_entry (context, db, &ent); + ret = 1; continue; } - if (parse_time_string_alloc (&ent.entry.pw_end, e.pw_end) == -1) { + if (parse_time_string_alloc (&ent.pw_end, e.pw_end) == -1) { fprintf (stderr, "%s:%d:error parsing time (%s)\n", - filename, line, e.pw_end); - hdb_free_entry (context, &ent); + filename, lineno, e.pw_end); + hdb_free_entry (context, db, &ent); + ret = 1; continue; } - if (parse_integer_alloc (&ent.entry.max_life, e.max_life) == -1) { + if (parse_integer_alloc (&ent.max_life, e.max_life) == -1) { fprintf (stderr, "%s:%d:error parsing lifetime (%s)\n", - filename, line, e.max_life); - hdb_free_entry (context, &ent); + filename, lineno, e.max_life); + hdb_free_entry (context, db, &ent); + ret = 1; continue; } - if (parse_integer_alloc (&ent.entry.max_renew, e.max_renew) == -1) { + if (parse_integer_alloc (&ent.max_renew, e.max_renew) == -1) { fprintf (stderr, "%s:%d:error parsing lifetime (%s)\n", - filename, line, e.max_renew); - hdb_free_entry (context, &ent); + filename, lineno, e.max_renew); + hdb_free_entry (context, db, &ent); + ret = 1; continue; } - if (parse_hdbflags2int (&ent.entry.flags, e.flags) != 1) { + if (parse_hdbflags2int (&ent.flags, e.flags) != 1) { fprintf (stderr, "%s:%d:error parsing flags (%s)\n", - filename, line, e.flags); - hdb_free_entry (context, &ent); + filename, lineno, e.flags); + hdb_free_entry (context, db, &ent); + ret = 1; continue; } - if(parse_generation(e.generation, &ent.entry.generation) == -1) { + if(parse_generation(e.generation, &ent.generation) == -1) { fprintf (stderr, "%s:%d:error parsing generation (%s)\n", - filename, line, e.generation); - hdb_free_entry (context, &ent); + filename, lineno, e.generation); + hdb_free_entry (context, db, &ent); + ret = 1; continue; } - if(parse_extensions(e.extensions, &ent.entry.extensions) == -1) { + if (parse_extensions(&e.extensions, &ent.extensions) == -1) { fprintf (stderr, "%s:%d:error parsing extension (%s)\n", - filename, line, e.extensions); - hdb_free_entry (context, &ent); + filename, lineno, e.extensions); + hdb_free_entry (context, db, &ent); + ret = 1; continue; } - ret = db->hdb_store(context, db, HDB_F_REPLACE, &ent); - hdb_free_entry (context, &ent); - if (ret) { - krb5_warn(context, ret, "db_store"); + ret2 = db->hdb_store(context, db, HDB_F_REPLACE, &ent); + hdb_free_entry (context, db, &ent); + if (ret2) { + krb5_warn(context, ret2, "db_store"); break; } } - db->hdb_close(context, db); + free(line); + if (ret2) + ret = ret2; + ret2 = db->hdb_set_sync(context, db, 1); + if (ret2) { + krb5_err(context, 1, ret2, "failed to sync the HDB"); + ret = ret2; + } + (void) kadm5_log_end(kadm_handle); + ret2 = db->hdb_close(context, db); + if (ret2) + ret = ret2; fclose(f); return ret != 0; } diff --git a/kadmin/mod.c b/kadmin/mod.c index 649285252..2d4bd5d50 100644 --- a/kadmin/mod.c +++ b/kadmin/mod.c @@ -34,19 +34,20 @@ #include "kadmin_locl.h" #include "kadmin-commands.h" -RCSID("$Id$"); - -static void +void add_tl(kadm5_principal_ent_rec *princ, int type, krb5_data *data) { krb5_tl_data *tl, **ptl; tl = ecalloc(1, sizeof(*tl)); tl->tl_data_next = NULL; - tl->tl_data_type = KRB5_TL_EXTENSION; + tl->tl_data_type = type; tl->tl_data_length = data->length; tl->tl_data_contents = data->data; + if (tl->tl_data_length < 0 || data->length != (size_t)tl->tl_data_length) + errx(1, "TL data overflow"); + princ->n_tl_data++; ptl = &princ->tl_data; while (*ptl != NULL) @@ -56,16 +57,30 @@ add_tl(kadm5_principal_ent_rec *princ, int type, krb5_data *data) return; } +/* + * Find a TL data of type KRB5_TL_EXTENSION that has an extension of type + * `etype' in it. + */ +krb5_tl_data * +get_tl(kadm5_principal_ent_rec *princ, int type) +{ + krb5_tl_data *tl = princ->tl_data; + + while (tl && tl->tl_data_type != type) + tl = tl->tl_data_next; + return tl; +} + static void -add_constrained_delegation(krb5_context context, +add_constrained_delegation(krb5_context contextp, kadm5_principal_ent_rec *princ, struct getarg_strings *strings) { krb5_error_code ret; HDB_extension ext; krb5_data buf; - size_t size; - + size_t size = 0; + memset(&ext, 0, sizeof(ext)); ext.mandatory = FALSE; ext.data.element = choice_HDB_extension_data_allowed_to_delegate_to; @@ -81,15 +96,15 @@ add_constrained_delegation(krb5_context context, calloc(strings->num_strings, sizeof(ext.data.u.allowed_to_delegate_to.val[0])); ext.data.u.allowed_to_delegate_to.len = strings->num_strings; - + for (i = 0; i < strings->num_strings; i++) { - ret = krb5_parse_name(context, strings->strings[i], &p); + ret = krb5_parse_name(contextp, strings->strings[i], &p); if (ret) abort(); ret = copy_Principal(p, &ext.data.u.allowed_to_delegate_to.val[i]); if (ret) abort(); - krb5_free_principal(context, p); + krb5_free_principal(contextp, p); } } @@ -105,14 +120,14 @@ add_constrained_delegation(krb5_context context, } static void -add_aliases(krb5_context context, kadm5_principal_ent_rec *princ, +add_aliases(krb5_context contextp, kadm5_principal_ent_rec *princ, struct getarg_strings *strings) { - krb5_error_code ret; + krb5_error_code ret = 0; HDB_extension ext; krb5_data buf; krb5_principal p; - size_t size; + size_t size = 0; int i; memset(&ext, 0, sizeof(ext)); @@ -128,11 +143,18 @@ add_aliases(krb5_context context, kadm5_principal_ent_rec *princ, calloc(strings->num_strings, sizeof(ext.data.u.aliases.aliases.val[0])); ext.data.u.aliases.aliases.len = strings->num_strings; - - for (i = 0; i < strings->num_strings; i++) { - ret = krb5_parse_name(context, strings->strings[i], &p); - ret = copy_Principal(p, &ext.data.u.aliases.aliases.val[i]); - krb5_free_principal(context, p); + + for (i = 0; ret == 0 && i < strings->num_strings; i++) { + ret = krb5_parse_name(contextp, strings->strings[i], &p); + if (ret) + krb5_err(contextp, 1, ret, "Could not parse alias %s", + strings->strings[i]); + if (ret == 0) + ret = copy_Principal(p, &ext.data.u.aliases.aliases.val[i]); + if (ret) + krb5_err(contextp, 1, ret, "Could not copy parsed alias %s", + strings->strings[i]); + krb5_free_principal(contextp, p); } } @@ -148,13 +170,13 @@ add_aliases(krb5_context context, kadm5_principal_ent_rec *princ, } static void -add_pkinit_acl(krb5_context context, kadm5_principal_ent_rec *princ, +add_pkinit_acl(krb5_context contextp, kadm5_principal_ent_rec *princ, struct getarg_strings *strings) { krb5_error_code ret; HDB_extension ext; krb5_data buf; - size_t size; + size_t size = 0; int i; memset(&ext, 0, sizeof(ext)); @@ -170,7 +192,7 @@ add_pkinit_acl(krb5_context context, kadm5_principal_ent_rec *princ, calloc(strings->num_strings, sizeof(ext.data.u.pkinit_acl.val[0])); ext.data.u.pkinit_acl.len = strings->num_strings; - + for (i = 0; i < strings->num_strings; i++) { ext.data.u.pkinit_acl.val[i].subject = estrdup(strings->strings[i]); } @@ -187,16 +209,124 @@ add_pkinit_acl(krb5_context context, kadm5_principal_ent_rec *princ, add_tl(princ, KRB5_TL_EXTENSION, &buf); } +static krb5_error_code +add_etypes(krb5_context contextp, + kadm5_principal_ent_rec *princ, + struct getarg_strings *strings) +{ + krb5_error_code ret = 0; + HDB_EncTypeList etypes; + krb5_data buf; + size_t i, size; + + etypes.len = strings->num_strings; + if ((etypes.val = calloc(strings->num_strings, + sizeof(etypes.val[0]))) == NULL) + krb5_err(contextp, 1, ret, "Out of memory"); + + for (i = 0; i < strings->num_strings; i++) { + krb5_enctype etype; + + ret = krb5_string_to_enctype(contextp, strings->strings[i], &etype); + if (ret) { + krb5_warn(contextp, ret, "Could not parse enctype %s", + strings->strings[i]); + free(etypes.val); + return ret; + } + etypes.val[i] = etype; + } + + if (ret == 0) { + ASN1_MALLOC_ENCODE(HDB_EncTypeList, buf.data, buf.length, + &etypes, &size, ret); + } + if (ret || buf.length != size) + abort(); + add_tl(princ, KRB5_TL_ETYPES, &buf); + free(etypes.val); + return 0; +} + +static void +add_kvno_diff(krb5_context contextp, kadm5_principal_ent_rec *princ, + int is_svc_diff, krb5_kvno kvno_diff) +{ + krb5_error_code ret; + HDB_extension ext; + krb5_data buf; + size_t size = 0; + + if (kvno_diff < 0) + return; + if (kvno_diff > 2048) + kvno_diff = 2048; + + ext.mandatory = 0; + if (is_svc_diff) { + ext.data.element = choice_HDB_extension_data_hist_kvno_diff_svc; + ext.data.u.hist_kvno_diff_svc = (unsigned int)kvno_diff; + } else { + ext.data.element = choice_HDB_extension_data_hist_kvno_diff_clnt; + ext.data.u.hist_kvno_diff_clnt = (unsigned int)kvno_diff; + } + ASN1_MALLOC_ENCODE(HDB_extension, buf.data, buf.length, + &ext, &size, ret); + if (ret) + abort(); + if (buf.length != size) + abort(); + + add_tl(princ, KRB5_TL_EXTENSION, &buf); +} + +static void +add_krb5_config(kadm5_principal_ent_rec *princ, const char *fname) +{ + HDB_extension ext; + krb5_data buf; + size_t size; + int ret; + + memset(&ext, 0, sizeof(ext)); + ext.mandatory = FALSE; + ext.data.element = choice_HDB_extension_data_krb5_config; + + if ((ret = rk_undumpdata(fname, + &ext.data.u.krb5_config.data, + &ext.data.u.krb5_config.length))) { + krb5_warn(context, ret, "Could not read %s", fname); + return; + } + + ASN1_MALLOC_ENCODE(HDB_extension, buf.data, buf.length, + &ext, &size, ret); + free_HDB_extension(&ext); + if (ret) + abort(); + if (buf.length != size) + abort(); + add_tl(princ, KRB5_TL_EXTENSION, &buf); +} + +struct mod_data { + struct modify_namespace_key_rotation_options *opt_ns_kr; + struct modify_namespace_options *opt_ns; + struct modify_options *opt; + void *kadm_handle; +}; + static int do_mod_entry(krb5_principal principal, void *data) { krb5_error_code ret; kadm5_principal_ent_rec princ; int mask = 0; - struct modify_options *e = data; + struct mod_data *m = data; + struct modify_options *e = m->opt; memset (&princ, 0, sizeof(princ)); - ret = kadm5_get_principal(kadm_handle, principal, &princ, + ret = kadm5_get_principal(m->kadm_handle, principal, &princ, KADM5_PRINCIPAL | KADM5_ATTRIBUTES | KADM5_MAX_LIFE | KADM5_MAX_RLIFE | KADM5_PRINC_EXPIRE_TIME | @@ -209,16 +339,22 @@ do_mod_entry(krb5_principal principal, void *data) e->expiration_time_string || e->pw_expiration_time_string || e->attributes_string || + e->policy_string || e->kvno_integer != -1 || + e->service_enctypes_strings.num_strings || e->constrained_delegation_strings.num_strings || e->alias_strings.num_strings || - e->pkinit_acl_strings.num_strings) { + e->pkinit_acl_strings.num_strings || + e->krb5_config_file_string || + e->hist_kvno_diff_clnt_integer != -1 || + e->hist_kvno_diff_svc_integer != -1) { ret = set_entry(context, &princ, &mask, e->max_ticket_life_string, e->max_renewable_life_string, e->expiration_time_string, e->pw_expiration_time_string, - e->attributes_string); + e->attributes_string, + e->policy_string); if(e->kvno_integer != -1) { princ.kvno = e->kvno_integer; mask |= KADM5_KVNO; @@ -236,16 +372,31 @@ do_mod_entry(krb5_principal principal, void *data) add_pkinit_acl(context, &princ, &e->pkinit_acl_strings); mask |= KADM5_TL_DATA; } - + if (e->service_enctypes_strings.num_strings) { + ret = add_etypes(context, &princ, &e->service_enctypes_strings); + mask |= KADM5_TL_DATA; + } + if (e->hist_kvno_diff_clnt_integer != -1) { + add_kvno_diff(context, &princ, 0, e->hist_kvno_diff_clnt_integer); + mask |= KADM5_TL_DATA; + } + if (e->hist_kvno_diff_svc_integer != -1) { + add_kvno_diff(context, &princ, 1, e->hist_kvno_diff_svc_integer); + mask |= KADM5_TL_DATA; + } + if (e->krb5_config_file_string) { + add_krb5_config(&princ, e->krb5_config_file_string); + mask |= KADM5_TL_DATA; + } } else ret = edit_entry(&princ, &mask, NULL, 0); if(ret == 0) { - ret = kadm5_modify_principal(kadm_handle, &princ, mask); + ret = kadm5_modify_principal(m->kadm_handle, &princ, mask); if(ret) krb5_warn(context, ret, "kadm5_modify_principal"); } - kadm5_free_principal_ent(kadm_handle, &princ); + kadm5_free_principal_ent(m->kadm_handle, &princ); return ret; } @@ -253,13 +404,450 @@ int mod_entry(struct modify_options *opt, int argc, char **argv) { krb5_error_code ret = 0; + struct mod_data data; int i; - for(i = 0; i < argc; i++) { - ret = foreach_principal(argv[i], do_mod_entry, "mod", opt); - if (ret) - break; - } + data.kadm_handle = NULL; + data.opt_ns_kr = NULL; + data.opt_ns = NULL; + data.opt = opt; + + ret = kadm5_dup_context(kadm_handle, &data.kadm_handle); + for (i = 0; ret == 0 && i < argc; i++) + ret = foreach_principal(argv[i], do_mod_entry, "mod", &data); + if (data.kadm_handle) + kadm5_destroy(data.kadm_handle); return ret != 0; } +static int +do_mod_ns_entry(krb5_principal principal, void *data) +{ + krb5_error_code ret; + kadm5_principal_ent_rec princ; + int mask = 0; + struct mod_data *m = data; + struct modify_namespace_options *e = m->opt_ns; + + memset (&princ, 0, sizeof(princ)); + ret = kadm5_get_principal(m->kadm_handle, principal, &princ, + KADM5_PRINCIPAL | KADM5_ATTRIBUTES | + KADM5_MAX_LIFE | KADM5_MAX_RLIFE | + KADM5_PRINC_EXPIRE_TIME | + KADM5_PW_EXPIRATION); + if(ret) + return ret; + + if(e->max_ticket_life_string || + e->max_renewable_life_string || + e->attributes_string || + e->enctypes_strings.num_strings || + e->krb5_config_file_string) { + ret = set_entry(context, &princ, &mask, e->max_ticket_life_string, + e->max_renewable_life_string, NULL, NULL, + e->attributes_string, NULL); + if (e->enctypes_strings.num_strings) { + ret = add_etypes(context, &princ, &e->enctypes_strings); + mask |= KADM5_TL_DATA; + } + if (e->krb5_config_file_string) { + add_krb5_config(&princ, e->krb5_config_file_string); + mask |= KADM5_TL_DATA; + } + } else + ret = edit_entry(&princ, &mask, NULL, 0); + if(ret == 0) { + ret = kadm5_modify_principal(m->kadm_handle, &princ, mask); + if(ret) + krb5_warn(context, ret, "kadm5_modify_principal"); + } + + kadm5_free_principal_ent(m->kadm_handle, &princ); + return ret; +} + +int +modify_namespace(struct modify_namespace_options *opt, int argc, char **argv) +{ + krb5_error_code ret = 0; + struct mod_data data; + int i; + + data.kadm_handle = NULL; + data.opt_ns_kr = NULL; + data.opt_ns = opt; + data.opt = NULL; + + ret = kadm5_dup_context(kadm_handle, &data.kadm_handle); + for (i = 0; ret == 0 && i < argc; i++) + ret = foreach_principal(argv[i], do_mod_ns_entry, "mod_ns", &data); + if (data.kadm_handle) + kadm5_destroy(data.kadm_handle); + return ret != 0; +} + +#if 0 +struct modify_namespace_key_rotation_options { + int force_flag; + int keep_base_key_flag; + char* revoke_old_string; + char* new_key_rotation_epoch_string; + char* new_key_rotation_period_string; +}; +#endif + +static int +princ2kstuple(kadm5_principal_ent_rec *princ, + unsigned int kvno, + krb5_key_salt_tuple **kstuple, + size_t *nkstuple) +{ + krb5_error_code ret = 0; + HDB_EncTypeList etypes; + krb5_tl_data *tl; + size_t i; + + *kstuple = 0; + *nkstuple = 0; + etypes.len = 0; + etypes.val = 0; + for (tl = princ->tl_data; tl; tl = tl->tl_data_next) { + if (tl->tl_data_type != KRB5_TL_ETYPES || tl->tl_data_length < 0) + continue; + ret = decode_HDB_EncTypeList(tl->tl_data_contents, tl->tl_data_length, + &etypes, NULL); + if (ret) + break; + *nkstuple = etypes.len; + *kstuple = ecalloc(etypes.len, sizeof(kstuple[0][0])); + for (i = 0; i < etypes.len; i++) { + (*kstuple)[i].ks_enctype = etypes.val[i]; + (*kstuple)[i].ks_salttype = 0; + } + return 0; + } + if (princ->n_key_data > 0) { + *kstuple = ecalloc(1, sizeof(kstuple[0][0])); + *nkstuple = 1; + for (i = 0; i < princ->n_key_data; i++) { + if (princ->key_data->key_data_kvno == kvno) { + (*kstuple)[0].ks_enctype = princ->key_data->key_data_type[0]; + (*kstuple)[0].ks_salttype = princ->key_data->key_data_type[1]; + return 0; + } + } + } + krb5_warnx(context, "Could not determine what enctypes to generate " + "keys for; recreate namespace?"); + return EINVAL; +} + +static int +randkey_kr(kadm5_principal_ent_rec *princ, + unsigned int old_kvno, + unsigned int kvno) +{ + krb5_key_salt_tuple *kstuple = 0; + krb5_error_code ret = 0; + size_t nkstuple = 0; + + /* + * We might be using kadm5clnt, so we'll use kadm5_randkey_principal_3(), + * which will generate new keys on the server side. This allows a race, + * but it will be detected by the key rotation update checks in lib/kadm5 + * and lib/hdb. + */ + ret = princ2kstuple(princ, old_kvno, &kstuple, &nkstuple); + if (ret == 0) + ret = kadm5_randkey_principal_3(kadm_handle, princ->principal, 1, + nkstuple, kstuple, NULL, NULL); + free(kstuple); + return ret; +} + +static int +do_mod_ns_kr(krb5_principal principal, void *data) +{ + krb5_error_code ret; + kadm5_principal_ent_rec princ; + struct modify_namespace_key_rotation_options *e = data; + HDB_Ext_KeyRotation existing; + HDB_Ext_KeyRotation new_kr; + HDB_extension ext; + KeyRotation new_krs[3]; + krb5_tl_data *tl; + krb5_data d; + time_t now = time(NULL); + size_t size; + int freeit = 0; + + d.data = 0; + d.length = 0; + new_kr.len = 0; + new_kr.val = new_krs; + ext.mandatory = 0; + ext.data.element = choice_HDB_extension_data_key_rotation; + ext.data.u.key_rotation.len = 0; + ext.data.u.key_rotation.val = 0; + existing.len = 0; + existing.val = 0; + memset(&new_krs, 0, sizeof(new_krs)); + memset(&princ, 0, sizeof(princ)); + + if (e->force_flag || e->revoke_old_string) { + krb5_warnx(context, "--force and --revoke-old not implemented yet"); + return ENOTSUP; + } + + ret = kadm5_get_principal(kadm_handle, principal, &princ, + KADM5_PRINCIPAL | KADM5_KVNO | + KADM5_KEY_DATA | KADM5_TL_DATA); + if (ret == 0) { + freeit = 1; + for (tl = princ.tl_data; tl; tl = tl->tl_data_next) { + if (tl->tl_data_type != KRB5_TL_KRB5_CONFIG) + continue; + ret = decode_HDB_Ext_KeyRotation(tl->tl_data_contents, + tl->tl_data_length, &existing, NULL); + if (ret) { + krb5_warn(context, ret, "unable to decode existing key " + "rotation schedule"); + kadm5_free_principal_ent(kadm_handle, &princ); + return ret; + } + } + if (!existing.len) { + krb5_warnx(context, "no key rotation schedule; " + "re-create namespace?"); + kadm5_free_principal_ent(kadm_handle, &princ); + return EINVAL; + } + } + + if (ret) { + krb5_warn(context, ret, "No such namespace"); + kadm5_free_principal_ent(kadm_handle, &princ); + return ret; + } + + if (existing.len > 1) + new_kr.val[1] = existing.val[0]; + if (existing.len > 2) + new_kr.val[2] = existing.val[1]; + new_kr.val[0].flags = existing.val[0].flags; + new_kr.val[0].base_kvno = princ.kvno + 2; /* XXX Compute better */ + new_kr.val[0].base_key_kvno = existing.val[0].base_key_kvno + 1; + if (e->new_key_rotation_epoch_string) { + if ((ret = str2time_t(e->new_key_rotation_epoch_string, + &new_kr.val[0].epoch))) + krb5_warn(context, ret, "Invalid epoch specification: %s", + e->new_key_rotation_epoch_string); + } else { + new_kr.val[0].epoch = existing.val[0].epoch + + existing.val[0].period * (princ.kvno - new_kr.val[0].base_kvno); + } + if (ret == 0 && e->new_key_rotation_period_string) { + time_t t; + + if ((ret = str2time_t(e->new_key_rotation_period_string, &t))) + krb5_warn(context, ret, "Invalid period specification: %s", + e->new_key_rotation_period_string); + else + new_kr.val[0].period = t; + } else { + new_kr.val[0].period = existing.val[0].period + + existing.val[0].period * (princ.kvno - new_kr.val[0].base_kvno); + } + if (new_kr.val[0].epoch < now) { + krb5_warnx(context, "New epoch cannot be in the past"); + ret = EINVAL; + } + if (new_kr.val[0].epoch < 30) { + krb5_warnx(context, "New period cannot be less than 30s"); + ret = EINVAL; + } + if (ret == 0) + ret = randkey_kr(&princ, princ.kvno, new_kr.val[0].base_key_kvno); + ext.data.u.key_rotation = new_kr; + if (ret == 0) + ASN1_MALLOC_ENCODE(HDB_extension, d.data, d.length, + &ext, &size, ret); + if (ret == 0) + add_tl(&princ, KRB5_TL_EXTENSION, &d); + if (ret == 0) { + ret = kadm5_modify_principal(kadm_handle, &princ, + KADM5_PRINCIPAL | KADM5_TL_DATA); + if (ret) + krb5_warn(context, ret, "Could not update namespace"); + } + + krb5_data_free(&d); + free_HDB_Ext_KeyRotation(&existing); + if (freeit) + kadm5_free_principal_ent(kadm_handle, &princ); + return ret; +} + +int +modify_ns_kr(struct modify_namespace_key_rotation_options *opt, + int argc, + char **argv) +{ + krb5_error_code ret = 0; + struct mod_data data; + int i; + + data.kadm_handle = NULL; + data.opt_ns_kr = opt; + data.opt_ns = NULL; + data.opt = NULL; + + ret = kadm5_dup_context(kadm_handle, &data.kadm_handle); + for (i = 0; ret == 0 && i < argc; i++) + ret = foreach_principal(argv[i], do_mod_ns_kr, "mod_ns", opt); + if (data.kadm_handle) + kadm5_destroy(data.kadm_handle); + return ret != 0; +} + +#define princ_realm(P) ((P)->realm) +#define princ_num_comp(P) ((P)->name.name_string.len) +#define princ_ncomp(P, N) ((P)->name.name_string.val[(N)]) + +static int +princ_cmp(const void *a, const void *b) +{ + krb5_const_principal pa = a; + krb5_const_principal pb = b; + size_t i; + int r; + + r = strcmp(princ_realm(pa), princ_realm(pb)); + if (r == 0) + r = princ_num_comp(pa) - princ_num_comp(pb); + for (i = 0; r == 0 && i < princ_num_comp(pa); i++) + r = strcmp(princ_ncomp(pa, i), princ_ncomp(pb, i)); + return r; +} + +/* Sort and remove dups */ +static void +uniq(HDB_Ext_Aliases *a) +{ + size_t i = 0; + + qsort(a->aliases.val, a->aliases.len, sizeof(a->aliases.val[0]), + princ_cmp); + + /* While there are at least two principals left to look at... */ + while (i + 1 < a->aliases.len) { + if (princ_cmp(&a->aliases.val[i], &a->aliases.val[i + 1])) { + /* ...if they are different, increment i and loop */ + i++; + continue; + } + /* ...else drop the one on the right and loop w/o incrementing i */ + free_Principal(&a->aliases.val[i + 1]); + if (i + 2 < a->aliases.len) + memmove(&a->aliases.val[i + 1], + &a->aliases.val[i + 2], + sizeof(a->aliases.val[i + 1]) * (a->aliases.len - (i + 2))); + a->aliases.len--; + } +} + +int +add_alias(void *opt, int argc, char **argv) +{ + kadm5_principal_ent_rec princ; + krb5_error_code ret; + krb5_principal p = NULL; + HDB_Ext_Aliases *a; + HDB_extension ext; + krb5_tl_data *tl = NULL; + krb5_data d; + size_t i; + + memset(&princ, 0, sizeof(princ)); + krb5_data_zero(&d); + + if (argc < 2) { + krb5_warnx(context, "Principal not given"); + return 1; + } + ret = krb5_parse_name(context, argv[0], &p); + if (ret) { + krb5_warn(context, ret, "Invalid principal: %s", argv[0]); + return 1; + } + + ret = kadm5_get_principal(kadm_handle, p, &princ, + KADM5_PRINCIPAL_NORMAL_MASK | KADM5_TL_DATA); + if (ret) { + krb5_warn(context, ret, "Principal not found %s", argv[0]); + return 1; + } + krb5_free_principal(context, p); + p = NULL; + + a = &ext.data.u.aliases; + a->case_insensitive = 0; + a->aliases.len = 0; + a->aliases.val = 0; + if ((tl = get_tl(&princ, KRB5_TL_ALIASES))) { + ret = decode_HDB_Ext_Aliases(tl->tl_data_contents, tl->tl_data_length, + a, NULL); + if (ret) { + kadm5_free_principal_ent(kadm_handle, &princ); + krb5_warn(context, ret, "Principal has invalid aliases extension " + "contents: %s", argv[0]); + return 1; + } + } + + argv++; + argc--; + + a->aliases.val = realloc(a->aliases.val, + sizeof(a->aliases.val[0]) * (a->aliases.len + argc)); + if (a->aliases.val == NULL) + krb5_err(context, 1, errno, "Out of memory"); + for (i = 0; ret == 0 && i < argc; i++) { + ret = krb5_parse_name(context, argv[i], &p); + if (ret) { + krb5_warn(context, ret, "krb5_parse_name"); + break; + } + ret = copy_Principal(p, &a->aliases.val[a->aliases.len]); + krb5_free_principal(context, p); + if (ret == 0) + a->aliases.len++; + } + uniq(a); + + ext.data.element = choice_HDB_extension_data_aliases; + ext.mandatory = 0; + if (ret == 0) + ASN1_MALLOC_ENCODE(HDB_extension, d.data, d.length, &ext, &i, ret); + free_HDB_extension(&ext); + if (ret == 0) { + int16_t len = d.length; + + if (len < 0 || d.length != (size_t)len) { + krb5_warnx(context, "Too many aliases; does not fit in 32767 bytes"); + ret = EOVERFLOW; + } + } + if (ret == 0) { + add_tl(&princ, KRB5_TL_EXTENSION, &d); + krb5_data_zero(&d); + ret = kadm5_modify_principal(kadm_handle, &princ, + KADM5_PRINCIPAL | KADM5_TL_DATA); + if (ret) + krb5_warn(context, ret, "kadm5_modify_principal"); + } + + kadm5_free_principal_ent(kadm_handle, &princ); + krb5_data_free(&d); + return ret == 0 ? 0 : 1; +} diff --git a/kadmin/prune.c b/kadmin/prune.c new file mode 100644 index 000000000..69d14eb04 --- /dev/null +++ b/kadmin/prune.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018 Cesnet z.s.p.o. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadmin_locl.h" +#include "kadmin-commands.h" + +int +prune(struct prune_options *opt, int argc, char **argv) +{ + krb5_error_code ret = 0; + krb5_principal princ_ent = NULL; + + if (argc == 0) { + krb5_warnx(context, "prune: missing principal name argument"); + return 0; + } + if (argc > 1) { + krb5_warnx(context, "prune: too many arguments"); + return 0; + } + + ret = krb5_parse_name(context, argv[0], &princ_ent); + if (ret) { + krb5_warn(context, ret, "krb5_parse_name %s", argv[0]); + goto out2; + } + + ret = kadm5_prune_principal(kadm_handle, princ_ent, opt->kvno_integer); + if (ret) + krb5_warn(context, ret, "kadm5_prune_principal"); + +out2: + return ret != 0; +} diff --git a/kadmin/pw_quality.c b/kadmin/pw_quality.c index 9bb18c34e..23b136266 100644 --- a/kadmin/pw_quality.c +++ b/kadmin/pw_quality.c @@ -34,8 +34,6 @@ #include "kadmin_locl.h" #include "kadmin-commands.h" -RCSID("$Id$"); - int password_quality(void *opt, int argc, char **argv) { diff --git a/kadmin/random_password.c b/kadmin/random_password.c index 0433b25bc..bf8bf8b3f 100644 --- a/kadmin/random_password.c +++ b/kadmin/random_password.c @@ -33,8 +33,6 @@ #include "kadmin_locl.h" -RCSID("$Id$"); - /* This file defines some a function that generates a random password, that can be used when creating a large amount of principals (such as for a batch of students). Since this is a political matter, you @@ -70,7 +68,8 @@ random_password(char *pw, size_t len) "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 2, "@$%&*()-+=:,/<>1234567890", 1); strlcpy(pw, pass, len); - memset(pass, 0, strlen(pass)); + len = strlen(pass); + memset_s(pass, len, 0, len); free(pass); #endif } @@ -157,7 +156,7 @@ generate_password(char **pw, int num_classes, ...) } } (*pw)[len] = '\0'; - memset(rbuf, 0, sizeof(rbuf)); + memset_s(rbuf, sizeof(rbuf), 0, sizeof(rbuf)); free(classes); } #endif diff --git a/kadmin/rename.c b/kadmin/rename.c index 0b1314587..cdd7de24d 100644 --- a/kadmin/rename.c +++ b/kadmin/rename.c @@ -34,8 +34,6 @@ #include "kadmin_locl.h" #include "kadmin-commands.h" -RCSID("$Id$"); - int rename_entry(void *opt, int argc, char **argv) { diff --git a/kadmin/rpc.c b/kadmin/rpc.c index fcc228c92..8a176da63 100644 --- a/kadmin/rpc.c +++ b/kadmin/rpc.c @@ -42,7 +42,7 @@ int __r; \ if ((__r = (x))) { \ krb5_errx(dcontext, 1, "Failed (%d) on %s:%d", \ - __r, __FUNCTION__, __LINE__); \ + __r, __FILE__, __LINE__); \ } \ } while(0) @@ -109,47 +109,47 @@ parse_name(const unsigned char *p, size_t len, const gss_OID oid, char **name) { size_t l; - + if (len < 4) return 1; - + /* TOK_ID */ if (memcmp(p, "\x04\x01", 2) != 0) return 1; len -= 2; p += 2; - + /* MECH_LEN */ l = (p[0] << 8) | p[1]; len -= 2; p += 2; if (l < 2 || len < l) return 1; - + /* oid wrapping */ if (p[0] != 6 || p[1] != l - 2) return 1; p += 2; l -= 2; len -= 2; - + /* MECH */ if (l != oid->length || memcmp(p, oid->elements, oid->length) != 0) return 1; len -= l; p += l; - + /* MECHNAME_LEN */ if (len < 4) return 1; - l = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; + l = (unsigned long)p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; len -= 4; p += 4; - + /* MECH NAME */ if (len != l) return 1; - + *name = malloc(l + 1); INSIST(*name != NULL); memcpy(*name, p, l); @@ -161,7 +161,7 @@ parse_name(const unsigned char *p, size_t len, static void -gss_error(krb5_context context, +gss_error(krb5_context contextp, gss_OID mech, OM_uint32 type, OM_uint32 error) { OM_uint32 new_stat; @@ -176,7 +176,7 @@ gss_error(krb5_context context, mech, &msg_ctx, &status_string); - krb5_warnx(context, "%.*s", + krb5_warnx(contextp, "%.*s", (int)status_string.length, (char *)status_string.value); gss_release_buffer (&new_stat, &status_string); @@ -184,11 +184,11 @@ gss_error(krb5_context context, } static void -gss_print_errors (krb5_context context, +gss_print_errors (krb5_context contextp, OM_uint32 maj_stat, OM_uint32 min_stat) { - gss_error(context, GSS_C_NO_OID, GSS_C_GSS_CODE, maj_stat); - gss_error(context, GSS_C_NO_OID, GSS_C_MECH_CODE, min_stat); + gss_error(contextp, GSS_C_NO_OID, GSS_C_GSS_CODE, maj_stat); + gss_error(contextp, GSS_C_NO_OID, GSS_C_MECH_CODE, min_stat); } static int @@ -202,13 +202,13 @@ read_data(krb5_storage *sp, krb5_storage *msg, size_t len) if (tlen > sizeof(buf)) tlen = sizeof(buf); - + slen = krb5_storage_read(sp, buf, tlen); - INSIST(slen == tlen); - + INSIST((size_t)slen == tlen); + slen = krb5_storage_write(msg, buf, tlen); - INSIST(slen == tlen); - + INSIST((size_t)slen == tlen); + len -= tlen; } return 0; @@ -226,7 +226,7 @@ collect_framents(krb5_storage *sp, krb5_storage *msg) ret = krb5_ret_uint32(sp, &len); if (ret) return ret; - + last_fragment = (len & LAST_FRAGMENT); len &= ~LAST_FRAGMENT; @@ -252,7 +252,7 @@ store_data_xdr(krb5_storage *sp, krb5_data data) static const char zero[4] = { 0, 0, 0, 0 }; ret = krb5_storage_write(sp, zero, res); - if(ret != res) + if((size_t)ret != res) return (ret < 0)? errno : krb5_storage_get_eof_code(sp); } return 0; @@ -273,7 +273,7 @@ ret_data_xdr(krb5_storage *sp, krb5_data *data) res = 4 - (data->length % 4); if (res != 4) { ret = krb5_storage_read(sp, buf, res); - if(ret != res) + if((size_t)ret != res) return (ret < 0)? errno : krb5_storage_get_eof_code(sp); } } @@ -341,7 +341,7 @@ store_string_xdr(krb5_storage *sp, const char *str) c.length = strlen(str) + 1; } else krb5_data_zero(&c); - + return store_data_xdr(sp, c); } @@ -362,19 +362,19 @@ ret_string_xdr(krb5_storage *sp, char **str) } static int -store_principal_xdr(krb5_context context, +store_principal_xdr(krb5_context contextp, krb5_storage *sp, krb5_principal p) { char *str; - CHECK(krb5_unparse_name(context, p, &str)); + CHECK(krb5_unparse_name(contextp, p, &str)); CHECK(store_string_xdr(sp, str)); free(str); return 0; } static int -ret_principal_xdr(krb5_context context, +ret_principal_xdr(krb5_context contextp, krb5_storage *sp, krb5_principal *p) { @@ -382,27 +382,27 @@ ret_principal_xdr(krb5_context context, *p = NULL; CHECK(ret_string_xdr(sp, &str)); if (str) { - CHECK(krb5_parse_name(context, str, p)); + CHECK(krb5_parse_name(contextp, str, p)); free(str); } return 0; } static int -store_principal_ent(krb5_context context, +store_principal_ent(krb5_context contextp, krb5_storage *sp, kadm5_principal_ent_rec *ent) { - size_t i; + int i; - CHECK(store_principal_xdr(context, sp, ent->principal)); + CHECK(store_principal_xdr(contextp, sp, ent->principal)); CHECK(krb5_store_uint32(sp, ent->princ_expire_time)); CHECK(krb5_store_uint32(sp, ent->pw_expiration)); CHECK(krb5_store_uint32(sp, ent->last_pwd_change)); CHECK(krb5_store_uint32(sp, ent->max_life)); CHECK(krb5_store_int32(sp, ent->mod_name == NULL)); if (ent->mod_name) - CHECK(store_principal_xdr(context, sp, ent->mod_name)); + CHECK(store_principal_xdr(contextp, sp, ent->mod_name)); CHECK(krb5_store_uint32(sp, ent->mod_date)); CHECK(krb5_store_uint32(sp, ent->attributes)); CHECK(krb5_store_uint32(sp, ent->kvno)); @@ -443,7 +443,7 @@ store_principal_ent(krb5_context context, } static int -ret_principal_ent(krb5_context context, +ret_principal_ent(krb5_context contextp, krb5_storage *sp, kadm5_principal_ent_rec *ent) { @@ -452,7 +452,7 @@ ret_principal_ent(krb5_context context, memset(ent, 0, sizeof(*ent)); - CHECK(ret_principal_xdr(context, sp, &ent->principal)); + CHECK(ret_principal_xdr(contextp, sp, &ent->principal)); CHECK(krb5_ret_uint32(sp, &flag)); ent->princ_expire_time = flag; CHECK(krb5_ret_uint32(sp, &flag)); @@ -463,7 +463,7 @@ ret_principal_ent(krb5_context context, ent->max_life = flag; CHECK(krb5_ret_uint32(sp, &flag)); if (flag == 0) - ret_principal_xdr(context, sp, &ent->mod_name); + CHECK(ret_principal_xdr(contextp, sp, &ent->mod_name)); CHECK(krb5_ret_uint32(sp, &flag)); ent->mod_date = flag; CHECK(krb5_ret_uint32(sp, &flag)); @@ -508,13 +508,13 @@ ret_principal_ent(krb5_context context, count++; } - INSIST(ent->n_tl_data == count); + INSIST((size_t)ent->n_tl_data == count); } else { INSIST(ent->n_tl_data == 0); } - + CHECK(krb5_ret_uint32(sp, &num)); - INSIST(num == ent->n_key_data); + INSIST(num == (uint32_t)ent->n_key_data); ent->key_data = calloc(num, sizeof(ent->key_data[0])); INSIST(ent->key_data != NULL); @@ -529,6 +529,7 @@ ret_principal_ent(krb5_context context, CHECK(krb5_ret_uint32(sp, &flag)); ent->key_data[i].key_data_type[1] = flag; } + CHECK(i == num); return 0; } @@ -538,7 +539,7 @@ ret_principal_ent(krb5_context context, */ static void -proc_create_principal(kadm5_server_context *context, +proc_create_principal(kadm5_server_context *contextp, krb5_storage *in, krb5_storage *out) { @@ -551,30 +552,30 @@ proc_create_principal(kadm5_server_context *context, CHECK(krb5_ret_uint32(in, &version)); INSIST(version == VERSION2); - CHECK(ret_principal_ent(context->context, in, &ent)); + CHECK(ret_principal_ent(contextp->context, in, &ent)); CHECK(krb5_ret_uint32(in, &mask)); CHECK(ret_string_xdr(in, &password)); INSIST(ent.principal); - ret = _kadm5_acl_check_permission(context, KADM5_PRIV_ADD, ent.principal); + ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_ADD, ent.principal); if (ret) goto fail; - ret = kadm5_create_principal(context, &ent, mask, password); + ret = kadm5_create_principal(contextp, &ent, mask, password); fail: - krb5_warn(context->context, ret, "create principal"); + krb5_warn(contextp->context, ret, "create principal"); CHECK(krb5_store_uint32(out, VERSION2)); /* api version */ CHECK(krb5_store_uint32(out, ret)); /* code */ free(password); - kadm5_free_principal_ent(context, &ent); + kadm5_free_principal_ent(contextp, &ent); } static void -proc_delete_principal(kadm5_server_context *context, +proc_delete_principal(kadm5_server_context *contextp, krb5_storage *in, krb5_storage *out) { @@ -584,24 +585,24 @@ proc_delete_principal(kadm5_server_context *context, CHECK(krb5_ret_uint32(in, &version)); INSIST(version == VERSION2); - CHECK(ret_principal_xdr(context->context, in, &princ)); + CHECK(ret_principal_xdr(contextp->context, in, &princ)); - ret = _kadm5_acl_check_permission(context, KADM5_PRIV_DELETE, princ); + ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_DELETE, princ); if (ret) goto fail; - ret = kadm5_delete_principal(context, princ); + ret = kadm5_delete_principal(contextp, princ); fail: - krb5_warn(context->context, ret, "delete principal"); + krb5_warn(contextp->context, ret, "delete principal"); CHECK(krb5_store_uint32(out, VERSION2)); /* api version */ CHECK(krb5_store_uint32(out, ret)); /* code */ - krb5_free_principal(context->context, princ); + krb5_free_principal(contextp->context, princ); } static void -proc_get_principal(kadm5_server_context *context, +proc_get_principal(kadm5_server_context *contextp, krb5_storage *in, krb5_storage *out) { @@ -614,30 +615,30 @@ proc_get_principal(kadm5_server_context *context, CHECK(krb5_ret_uint32(in, &version)); INSIST(version == VERSION2); - CHECK(ret_principal_xdr(context->context, in, &princ)); + CHECK(ret_principal_xdr(contextp->context, in, &princ)); CHECK(krb5_ret_uint32(in, &mask)); - ret = _kadm5_acl_check_permission(context, KADM5_PRIV_GET, princ); + ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_GET, princ); if(ret) goto fail; - ret = kadm5_get_principal(context, princ, &ent, mask); + ret = kadm5_get_principal(contextp, princ, &ent, mask); fail: - krb5_warn(context->context, ret, "get principal principal"); + krb5_warn(contextp->context, ret, "get principal principal"); CHECK(krb5_store_uint32(out, VERSION2)); /* api version */ CHECK(krb5_store_uint32(out, ret)); /* code */ if (ret == 0) { - CHECK(store_principal_ent(context->context, out, &ent)); + CHECK(store_principal_ent(contextp->context, out, &ent)); } - krb5_free_principal(context->context, princ); - kadm5_free_principal_ent(context, &ent); + krb5_free_principal(contextp->context, princ); + kadm5_free_principal_ent(contextp, &ent); } static void -proc_chrand_principal_v2(kadm5_server_context *context, - krb5_storage *in, +proc_chrand_principal_v2(kadm5_server_context *contextp, + krb5_storage *in, krb5_storage *out) { krb5_error_code ret; @@ -648,36 +649,36 @@ proc_chrand_principal_v2(kadm5_server_context *context, CHECK(krb5_ret_uint32(in, &version)); INSIST(version == VERSION2); - CHECK(ret_principal_xdr(context->context, in, &princ)); + CHECK(ret_principal_xdr(contextp->context, in, &princ)); - ret = _kadm5_acl_check_permission(context, KADM5_PRIV_CPW, princ); + ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ); if(ret) goto fail; - ret = kadm5_randkey_principal(context, princ, + ret = kadm5_randkey_principal(contextp, princ, &new_keys, &n_keys); fail: - krb5_warn(context->context, ret, "rand key principal"); + krb5_warn(contextp->context, ret, "rand key principal"); CHECK(krb5_store_uint32(out, VERSION2)); /* api version */ CHECK(krb5_store_uint32(out, ret)); if (ret == 0) { - size_t i; + int i; CHECK(krb5_store_int32(out, n_keys)); for(i = 0; i < n_keys; i++){ CHECK(krb5_store_uint32(out, new_keys[i].keytype)); CHECK(store_data_xdr(out, new_keys[i].keyvalue)); - krb5_free_keyblock_contents(context->context, &new_keys[i]); + krb5_free_keyblock_contents(contextp->context, &new_keys[i]); } free(new_keys); } - krb5_free_principal(context->context, princ); + krb5_free_principal(contextp->context, princ); } static void -proc_init(kadm5_server_context *context, +proc_init(kadm5_server_context *contextp, krb5_storage *in, krb5_storage *out) { @@ -686,10 +687,10 @@ proc_init(kadm5_server_context *context, CHECK(krb5_store_uint32(out, 0)); /* code */ } -struct proc { - char *name; +struct krb5_proc { + const char *name; void (*func)(kadm5_server_context *, krb5_storage *, krb5_storage *); -} procs[] = { +} rwprocs[] = { { "NULL", NULL }, { "create principal", proc_create_principal }, { "delete principal", proc_delete_principal }, @@ -712,6 +713,29 @@ struct proc { { "chpass principal v3", NULL }, { "chrand principal v3", NULL }, { "setkey principal v3", NULL } +}, roprocs[] = { + { "NULL", NULL }, + { "create principal", NULL }, + { "delete principal", NULL }, + { "modify principal", NULL }, + { "rename principal", NULL }, + { "get principal", proc_get_principal }, + { "chpass principal", NULL }, + { "chrand principal", NULL }, + { "create policy", NULL }, + { "delete policy", NULL }, + { "modify policy", NULL }, + { "get policy", NULL }, + { "get privs", NULL }, + { "init", NULL }, + { "get principals", NULL }, + { "get polices", NULL }, + { "setkey principal", NULL }, + { "setkey principal v4", NULL }, + { "create principal v3", NULL }, + { "chpass principal v3", NULL }, + { "chrand principal v3", NULL }, + { "setkey principal v3", NULL } }; static krb5_error_code @@ -723,7 +747,7 @@ copyheader(krb5_storage *sp, krb5_data *data) off = krb5_storage_seek(sp, 0, SEEK_CUR); CHECK(krb5_data_alloc(data, off)); - INSIST(off == data->length); + INSIST((size_t)off == data->length); krb5_storage_seek(sp, 0, SEEK_SET); sret = krb5_storage_read(sp, data->data, data->length); INSIST(sret == off); @@ -741,9 +765,11 @@ struct gctx { }; static int -process_stream(krb5_context context, - unsigned char *buf, size_t ilen, - krb5_storage *sp) +process_stream(krb5_context contextp, + unsigned char *buf, + size_t ilen, + krb5_storage *sp, + int readonly) { krb5_error_code ret; krb5_storage *msg, *reply, *dreply; @@ -758,6 +784,16 @@ process_stream(krb5_context context, reply = krb5_storage_emem(); dreply = krb5_storage_emem(); + if (msg == NULL || reply == NULL || dreply == NULL) { + if (msg != NULL) + krb5_storage_free(msg); + if (reply != NULL) + krb5_storage_free(reply); + if (dreply != NULL) + krb5_storage_free(dreply); + return krb5_enomem(contextp); + } + /* * First packet comes partly from the caller */ @@ -792,46 +828,46 @@ process_stream(krb5_context context, if (ilen < 4) { memcpy(tmp, buf, ilen); slen = krb5_storage_read(sp, tmp + ilen, sizeof(tmp) - ilen); - INSIST(slen == sizeof(tmp) - ilen); + INSIST((size_t)slen == sizeof(tmp) - ilen); ilen = sizeof(tmp); buf = tmp; } INSIST(ilen >= 4); - + _krb5_get_int(buf, &len, 4); last_fragment = (len & LAST_FRAGMENT) != 0; len &= ~LAST_FRAGMENT; - + ilen -= 4; buf += 4; if (ilen) { if (len < ilen) { slen = krb5_storage_write(msg, buf, len); - INSIST(slen == len); + INSIST((size_t)slen == len); ilen -= len; len = 0; } else { slen = krb5_storage_write(msg, buf, ilen); - INSIST(slen == ilen); + INSIST((size_t)slen == ilen); len -= ilen; } } CHECK(read_data(sp, msg, len)); - + if (!last_fragment) { ret = collect_framents(sp, msg); if (ret == HEIM_ERR_EOF) - krb5_errx(context, 0, "client disconnected"); + krb5_errx(contextp, 0, "client disconnected"); INSIST(ret == 0); } } else { ret = collect_framents(sp, msg); if (ret == HEIM_ERR_EOF) - krb5_errx(context, 0, "client disconnected"); + krb5_errx(contextp, 0, "client disconnected"); INSIST(ret == 0); } krb5_storage_seek(msg, 0, SEEK_SET); @@ -873,14 +909,15 @@ process_stream(krb5_context context, krb5_data data; int conf_state; uint32_t seq; - krb5_storage *sp; + krb5_storage *sp1; + struct krb5_proc *procs = readonly ? roprocs : rwprocs; INSIST(gcred.service == rpg_privacy); INSIST(gctx.done); INSIST(krb5_data_cmp(&gcred.handle, &gctx.handle) == 0); - + CHECK(ret_data_xdr(msg, &data)); gin.value = data.data; @@ -892,10 +929,10 @@ process_stream(krb5_context context, INSIST(maj_stat == GSS_S_COMPLETE); INSIST(conf_state != 0); - sp = krb5_storage_from_mem(gout.value, gout.length); - INSIST(sp != NULL); + sp1 = krb5_storage_from_mem(gout.value, gout.length); + INSIST(sp1 != NULL); - CHECK(krb5_ret_uint32(sp, &seq)); + CHECK(krb5_ret_uint32(sp1, &seq)); INSIST (seq == gcred.seq_num); /* @@ -904,20 +941,25 @@ process_stream(krb5_context context, INSIST(seq > gctx.seq_num); gctx.seq_num = seq; - /* - * If context is setup, priv data have the seq_num stored + /* + * If contextp is setup, priv data have the seq_num stored * first in the block, so add it here before users data is * added. */ CHECK(krb5_store_uint32(dreply, gctx.seq_num)); - if (chdr.proc >= sizeof(procs)/sizeof(procs[0])) { - krb5_warnx(context, "proc number out of array"); + if (chdr.proc >= sizeof(rwprocs)/sizeof(rwprocs[0])) { + krb5_warnx(contextp, "proc number out of array"); } else if (procs[chdr.proc].func == NULL) { - krb5_warnx(context, "proc '%s' never implemented", - procs[chdr.proc].name); + if (readonly && rwprocs[chdr.proc].func) + krb5_warnx(contextp, + "proc '%s' not allowed (readonly mode)", + procs[chdr.proc].name); + else + krb5_warnx(contextp, "proc '%s' never implemented", + procs[chdr.proc].name); } else { - krb5_warnx(context, "proc %s", procs[chdr.proc].name); + krb5_warnx(contextp, "proc %s", procs[chdr.proc].name); INSIST(server_handle != NULL); (*procs[chdr.proc].func)(server_handle, sp, dreply); } @@ -931,7 +973,7 @@ process_stream(krb5_context context, INSIST(gctx.ctx == NULL); gctx.inprogress = 1; - /* FALL THOUGH */ + HEIM_FALLTHROUGH; case RPG_CONTINUE_INIT: { gss_name_t src_name = GSS_C_NO_NAME; krb5_data in; @@ -946,7 +988,7 @@ process_stream(krb5_context context, gout.length = 0; maj_stat = gss_accept_sec_context(&min_stat, - &gctx.ctx, + &gctx.ctx, GSS_C_NO_CREDENTIAL, &gin, GSS_C_NO_CHANNEL_BINDINGS, @@ -957,29 +999,29 @@ process_stream(krb5_context context, NULL, NULL); if (GSS_ERROR(maj_stat)) { - gss_print_errors(context, maj_stat, min_stat); - krb5_errx(context, 1, "gss error, exit"); + gss_print_errors(contextp, maj_stat, min_stat); + krb5_errx(contextp, 1, "gss error, exit"); } if ((maj_stat & GSS_S_CONTINUE_NEEDED) == 0) { kadm5_config_params realm_params; - gss_buffer_desc buf; + gss_buffer_desc bufp; char *client; gctx.done = 1; - + memset(&realm_params, 0, sizeof(realm_params)); - maj_stat = gss_export_name(&min_stat, src_name, &buf); + maj_stat = gss_export_name(&min_stat, src_name, &bufp); INSIST(maj_stat == GSS_S_COMPLETE); - CHECK(parse_name(buf.value, buf.length, + CHECK(parse_name(bufp.value, bufp.length, GSS_KRB5_MECHANISM, &client)); - gss_release_buffer(&min_stat, &buf); + gss_release_buffer(&min_stat, &bufp); - krb5_warnx(context, "%s connected", client); + krb5_warnx(contextp, "%s connected", client); - ret = kadm5_s_init_with_password_ctx(context, + ret = kadm5_s_init_with_password_ctx(contextp, client, NULL, KADM5_ADMIN_SERVICE, @@ -992,7 +1034,7 @@ process_stream(krb5_context context, INSIST(gctx.ctx != GSS_C_NO_CONTEXT); CHECK(krb5_store_uint32(dreply, 0)); - CHECK(store_gss_init_res(dreply, gctx.handle, + CHECK(store_gss_init_res(dreply, gctx.handle, maj_stat, min_stat, 1, &gout)); if (gout.value) gss_release_buffer(&min_stat, &gout); @@ -1002,9 +1044,9 @@ process_stream(krb5_context context, break; } case RPG_DESTROY: - krb5_errx(context, 1, "client destroyed gss context"); + krb5_errx(contextp, 1, "client destroyed gss contextp"); default: - krb5_errx(context, 1, "client sent unknown gsscode %d", + krb5_errx(contextp, 1, "client sent unknown gsscode %d", (int)gcred.proc); } @@ -1026,7 +1068,7 @@ process_stream(krb5_context context, CHECK(krb5_store_uint32(reply, 0)); /* SUCCESS */ CHECK(krb5_storage_to_data(dreply, &data)); - INSIST(krb5_storage_write(reply, data.data, data.length) == data.length); + INSIST((size_t)krb5_storage_write(reply, data.data, data.length) == data.length); krb5_data_free(&data); } else { @@ -1054,23 +1096,23 @@ process_stream(krb5_context context, ssize_t sret; gctx.inprogress = 0; sret = krb5_storage_write(reply, data.data, data.length); - INSIST(sret == data.length); + INSIST((size_t)sret == data.length); krb5_data_free(&data); } else { int conf_state; gin.value = data.data; gin.length = data.length; - + maj_stat = gss_wrap(&min_stat, gctx.ctx, 1, 0, &gin, &conf_state, &gout); INSIST(maj_stat == GSS_S_COMPLETE); INSIST(conf_state != 0); krb5_data_free(&data); - + data.data = gout.value; data.length = gout.length; - + store_data_xdr(reply, data); gss_release_buffer(&min_stat, &gout); } @@ -1082,7 +1124,7 @@ process_stream(krb5_context context, CHECK(krb5_storage_to_data(reply, &data)); CHECK(krb5_store_uint32(sp, data.length | LAST_FRAGMENT)); sret = krb5_storage_write(sp, data.data, data.length); - INSIST(sret == data.length); + INSIST((size_t)sret == data.length); krb5_data_free(&data); } @@ -1091,16 +1133,20 @@ process_stream(krb5_context context, int -handle_mit(krb5_context context, void *buf, size_t len, int fd) +handle_mit(krb5_context contextp, + void *buf, + size_t len, + krb5_socket_t sock, + int readonly) { krb5_storage *sp; - dcontext = context; + dcontext = contextp; - sp = krb5_storage_from_fd(fd); + sp = krb5_storage_from_socket(sock); INSIST(sp != NULL); - - process_stream(context, buf, len, sp); - + + process_stream(contextp, buf, len, sp, readonly); + return 0; } diff --git a/kadmin/server.c b/kadmin/server.c index 5603d7c16..281822a30 100644 --- a/kadmin/server.c +++ b/kadmin/server.c @@ -34,232 +34,535 @@ #include "kadmin_locl.h" #include -RCSID("$Id$"); +static kadm5_ret_t check_aliases(kadm5_server_context *, + kadm5_principal_ent_rec *, + kadm5_principal_ent_rec *); + +/* + * All the iter_cb stuff is about online listing of principals via + * kadm5_iter_principals(). Search for "LIST" to see more commentary. + */ +struct iter_cb_data { + krb5_context context; + krb5_auth_context ac; + krb5_storage *rsp; + kadm5_ret_t ret; + size_t n; + size_t i; + int fd; + unsigned int initial:1; + unsigned int stop:1; +}; + +/* + * This function sends the current chunk of principal listing and checks if the + * client requested that the listing stop. + */ +static int +iter_cb_send_now(struct iter_cb_data *d) +{ + struct timeval tv; + krb5_data out; + + krb5_data_zero(&out); + + if (!d->stop) { + fd_set fds; + int nfds; + + /* + * The client can send us one message to interrupt the iteration. + * + * TODO: Maybe we should have the client send a message every N chunks + * so we can clock the listing and have a chance to receive any + * interrupt message from the client? + */ + FD_ZERO(&fds); + FD_SET(d->fd, &fds); + tv.tv_sec = 0; + tv.tv_usec = 0; + nfds = select(d->fd + 1, &fds, NULL, NULL, &tv); + if (nfds == -1) { + d->ret = errno; + } else if (nfds > 0) { + /* + * And it did. We'll throw this message away. It should be a NOP + * call, which we'd throw away anyways. If the client's stop + * message arrives after we're done anyways, well, it will be + * processed as a NOP and thrown away. + */ + d->stop = 1; + d->ret = krb5_read_priv_message(d->context, d->ac, &d->fd, &out); + krb5_data_free(&out); + if (d->ret == HEIM_ERR_EOF) + exit(0); + } + } + d->i = 0; + d->ret = krb5_storage_to_data(d->rsp, &out); + if (d->ret == 0) + d->ret = krb5_write_priv_message(d->context, d->ac, &d->fd, &out); + krb5_data_free(&out); + krb5_storage_free(d->rsp); + if ((d->rsp = krb5_storage_emem()) == NULL) + return krb5_enomem(d->context); + return d->ret; +} + +static int +iter_cb(void *cbdata, const char *p) +{ + struct iter_cb_data *d = cbdata; + krb5_error_code ret = 0; + size_t n = d->n; + + /* Convince the compiler that `-(int)d->n' is defined */ + if (n == 0 || n > INT_MAX) + return ERANGE; + if (d->rsp == NULL && (d->rsp = krb5_storage_emem()) == NULL) + return krb5_enomem(d->context); + if (d->i == 0) { + /* Every chunk starts with a result code */ + ret = krb5_store_int32(d->rsp, d->ret); + if (ret) + return ret; + if (d->ret) + return ret; + } + if (d->initial) { + /* + * We'll send up to `d->n' entries per-write. We send a negative + * number to indicate we accepted the client's proposal that we speak + * the online LIST protocol. + * + * Note that if we're here then we've already placed a result code in + * this reply (see above). + */ + d->initial = 0; + ret = krb5_store_int32(d->rsp, -(int)n); /* Princs per-chunk */ + if (ret == 0) + ret = iter_cb_send_now(d); + if (ret) + return ret; + /* + * Now that we've sent the acceptance reply, put a result code as the + * first thing in the next reply, which will have the first chunk of + * the listing. + */ + ret = krb5_store_int32(d->rsp, d->ret); + if (ret) + return ret; + if (d->ret) + return ret; + } + + if (p) { + ret = krb5_store_string(d->rsp, p); + d->i++; + } else { + /* + * We get called with `p == NULL' when the listing is done. This + * forces us to iter_cb_send_now(d) below, but also forces us to have a + * properly formed reply (i.e., that we have a result code as the first + * item), even if the chunk is otherwise empty (`d->i == 0'). + */ + d->i = n; + } + + if (ret == 0 && d->i == n) + ret = iter_cb_send_now(d); /* Chunk finished; send it */ + if (d->stop) + return EINTR; + return ret; +} static kadm5_ret_t -kadmind_dispatch(void *kadm_handle, krb5_boolean initial, - krb5_data *in, krb5_data *out) +kadmind_dispatch(void *kadm_handlep, krb5_boolean initial, + krb5_data *in, krb5_auth_context ac, int fd, + krb5_data *out, int readonly) { - kadm5_ret_t ret; - int32_t cmd, mask, tmp; - kadm5_server_context *context = kadm_handle; + kadm5_ret_t ret = 0; + kadm5_ret_t ret_sp = 0; + int32_t cmd, mask, kvno, tmp; + kadm5_server_context *contextp = kadm_handlep; char client[128], name[128], name2[128]; - char *op = ""; - krb5_principal princ, princ2; - kadm5_principal_ent_rec ent; - char *password, *expression; + const char *op = ""; + krb5_principal princ = NULL, princ2 = NULL; + kadm5_principal_ent_rec ent, ent_prev; + char *password = NULL, *expression; krb5_keyblock *new_keys; + krb5_key_salt_tuple *ks_tuple = NULL; + int keepold = FALSE; + int n_ks_tuple = 0; int n_keys; char **princs; int n_princs; + int keys_ok = 0; + krb5_storage *rsp; /* response goes here */ krb5_storage *sp; + int len; - krb5_unparse_name_fixed(context->context, context->caller, - client, sizeof(client)); + memset(&ent, 0, sizeof(ent)); + memset(&ent_prev, 0, sizeof(ent_prev)); + krb5_data_zero(out); + + rsp = krb5_storage_emem(); + if (rsp == NULL) + return krb5_enomem(contextp->context); sp = krb5_storage_from_data(in); - if (sp == NULL) - krb5_errx(context->context, 1, "out of memory"); + if (sp == NULL) { + krb5_storage_free(rsp); + return krb5_enomem(contextp->context); + } + + ret = krb5_unparse_name_fixed(contextp->context, contextp->caller, + client, sizeof(client)); + if (ret == 0) + ret = krb5_ret_int32(sp, &cmd); + if (ret) { + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); + goto fail; + } - krb5_ret_int32(sp, &cmd); switch(cmd){ + case kadm_nop:{ + /* + * In the future we could use this for versioning. + * + * We used to respond to NOPs with KADM5_FAILURE. Now we respond with + * zero. In the future we could send back a protocol version number + * and use NOPs for protocol version negotiation. + * + * In the meantime, this gets called only if a client wants to + * interrupt a long-running LIST operation. + */ + op = "NOP"; + ret = krb5_ret_int32(sp, &tmp); + if (ret == 0 && tmp == 0) { + /* + * Reply not wanted. This would be a LIST interrupt request. + */ + krb5_storage_free(rsp); + krb5_storage_free(sp); + return 0; + } + ret_sp = krb5_store_int32(rsp, ret = 0); + break; + } case kadm_get:{ op = "GET"; ret = krb5_ret_principal(sp, &princ); - if(ret) + if (ret) { + ret_sp = krb5_store_int32(rsp, KADM5_UNK_PRINC); goto fail; + } ret = krb5_ret_int32(sp, &mask); - if(ret){ - krb5_free_principal(context->context, princ); + if (ret) { + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); goto fail; - } + } + mask |= KADM5_PRINCIPAL; - krb5_unparse_name_fixed(context->context, princ, name, sizeof(name)); - krb5_warnx(context->context, "%s: %s %s", client, op, name); - ret = _kadm5_acl_check_permission(context, KADM5_PRIV_GET, princ); - if(ret){ - krb5_free_principal(context->context, princ); + krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); + krb5_warnx(contextp->context, "%s: %s %s", client, op, name); + + /* If the caller doesn't have KADM5_PRIV_GET, we're done. */ + ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_GET, princ); + if (ret) { + ret_sp = krb5_store_int32(rsp, ret); goto fail; + } + + /* Then check to see if it is ok to return keys */ + if ((mask & KADM5_KEY_DATA) != 0) { + ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_GET_KEYS, + princ); + if (ret == 0) { + keys_ok = 1; + } else if ((mask == (KADM5_PRINCIPAL|KADM5_KEY_DATA)) || + (mask == (KADM5_PRINCIPAL|KADM5_KVNO|KADM5_KEY_DATA))) { + /* + * Requests for keys will get bogus keys, which is useful if + * the client just wants to see what (kvno, enctype)s the + * principal has keys for, but terrible if the client wants to + * write the keys into a keytab or modify the principal and + * write the bogus keys back to the server. + * + * We use a heuristic to detect which case we're handling here. + * If the client only asks for the flags in the above + * condition, then it's very likely a kadmin ext_keytab, + * add_enctype, or other request that should not see bogus + * keys. We deny them. + * + * The kadmin get command can be coaxed into making a request + * with the same mask. But the default long and terse output + * modes request other things too, so in all likelihood this + * heuristic will not hurt any kadmin get uses. + */ + ret_sp = krb5_store_int32(rsp, ret); + goto fail; + } + } + + ret = kadm5_get_principal(kadm_handlep, princ, &ent, mask); + ret_sp = krb5_store_int32(rsp, ret); + if (ret == 0) { + if (ret_sp == 0 && keys_ok) + ret_sp = kadm5_store_principal_ent(rsp, &ent); + else if (ret_sp == 0) + ret_sp = kadm5_store_principal_ent_nokeys(rsp, &ent); } - ret = kadm5_get_principal(kadm_handle, princ, &ent, mask); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - krb5_store_int32(sp, ret); - if(ret == 0){ - kadm5_store_principal_ent(sp, &ent); - kadm5_free_principal_ent(kadm_handle, &ent); - } - krb5_free_principal(context->context, princ); + kadm5_free_principal_ent(kadm_handlep, &ent); break; } case kadm_delete:{ op = "DELETE"; + if (readonly) { + ret_sp = krb5_store_int32(rsp, ret = KADM5_READ_ONLY); + goto fail; + } ret = krb5_ret_principal(sp, &princ); - if(ret) - goto fail; - krb5_unparse_name_fixed(context->context, princ, name, sizeof(name)); - krb5_warnx(context->context, "%s: %s %s", client, op, name); - ret = _kadm5_acl_check_permission(context, KADM5_PRIV_DELETE, princ); - if(ret){ - krb5_free_principal(context->context, princ); - goto fail; - } - ret = kadm5_delete_principal(kadm_handle, princ); - krb5_free_principal(context->context, princ); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - krb5_store_int32(sp, ret); + if (ret == 0) + ret = krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); + if (ret == 0) { + ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_DELETE, princ); + krb5_warnx(contextp->context, "%s: %s %s (%s)", client, op, name, + ret == 0 ? "granted" : "denied"); + } + + /* + * There's no need to check that the caller has permission to + * delete the victim principal's aliases. + */ + if (ret == 0) + ret = kadm5_delete_principal(kadm_handlep, princ); + ret_sp = krb5_store_int32(rsp, ret); break; } case kadm_create:{ op = "CREATE"; + if (readonly) { + ret_sp = krb5_store_int32(rsp, ret = KADM5_READ_ONLY); + goto fail; + } ret = kadm5_ret_principal_ent(sp, &ent); - if(ret) + if(ret) { + ret_sp = krb5_store_int32(rsp, ret); goto fail; + } ret = krb5_ret_int32(sp, &mask); if(ret){ - kadm5_free_principal_ent(context->context, &ent); + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); + kadm5_free_principal_ent(kadm_handlep, &ent); goto fail; } ret = krb5_ret_string(sp, &password); if(ret){ - kadm5_free_principal_ent(context->context, &ent); + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); + kadm5_free_principal_ent(kadm_handlep, &ent); goto fail; } - krb5_unparse_name_fixed(context->context, ent.principal, + krb5_unparse_name_fixed(contextp->context, ent.principal, name, sizeof(name)); - krb5_warnx(context->context, "%s: %s %s", client, op, name); - ret = _kadm5_acl_check_permission(context, KADM5_PRIV_ADD, + krb5_warnx(contextp->context, "%s: %s %s", client, op, name); + ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_ADD, ent.principal); if(ret){ - kadm5_free_principal_ent(context->context, &ent); - memset(password, 0, strlen(password)); - free(password); + ret_sp = krb5_store_int32(rsp, ret); + kadm5_free_principal_ent(kadm_handlep, &ent); goto fail; } - ret = kadm5_create_principal(kadm_handle, &ent, + if ((mask & KADM5_TL_DATA)) { + /* + * Also check that the caller can create the aliases, if the + * new principal has any. + */ + ret = check_aliases(contextp, &ent, NULL); + if (ret) { + ret_sp = krb5_store_int32(rsp, KADM5_BAD_PRINCIPAL); + kadm5_free_principal_ent(kadm_handlep, &ent); + goto fail; + } + } + ret = kadm5_create_principal(kadm_handlep, &ent, mask, password); - kadm5_free_principal_ent(kadm_handle, &ent); - memset(password, 0, strlen(password)); - free(password); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - krb5_store_int32(sp, ret); + kadm5_free_principal_ent(kadm_handlep, &ent); + ret_sp = krb5_store_int32(rsp, ret); break; } case kadm_modify:{ op = "MODIFY"; + if (readonly) { + ret_sp = krb5_store_int32(rsp, ret = KADM5_READ_ONLY); + goto fail; + } ret = kadm5_ret_principal_ent(sp, &ent); - if(ret) + if(ret) { + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); goto fail; + } ret = krb5_ret_int32(sp, &mask); if(ret){ - kadm5_free_principal_ent(context, &ent); + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); + kadm5_free_principal_ent(contextp, &ent); goto fail; } - krb5_unparse_name_fixed(context->context, ent.principal, + krb5_unparse_name_fixed(contextp->context, ent.principal, name, sizeof(name)); - krb5_warnx(context->context, "%s: %s %s", client, op, name); - ret = _kadm5_acl_check_permission(context, KADM5_PRIV_MODIFY, + krb5_warnx(contextp->context, "%s: %s %s", client, op, name); + ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_MODIFY, ent.principal); if(ret){ - kadm5_free_principal_ent(context, &ent); + ret_sp = krb5_store_int32(rsp, ret); + kadm5_free_principal_ent(contextp, &ent); goto fail; } - ret = kadm5_modify_principal(kadm_handle, &ent, mask); - kadm5_free_principal_ent(kadm_handle, &ent); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - krb5_store_int32(sp, ret); + if ((mask & KADM5_TL_DATA)) { + /* + * Also check that the caller can create aliases that are in + * the new entry but not the old one. There's no need to + * check that the caller can delete aliases it wants to + * drop. See also handling of rename. + */ + ret = kadm5_get_principal(kadm_handlep, ent.principal, &ent_prev, mask); + if (ret) { + ret_sp = krb5_store_int32(rsp, ret); + kadm5_free_principal_ent(contextp, &ent); + goto fail; + } + ret = check_aliases(contextp, &ent, &ent_prev); + kadm5_free_principal_ent(contextp, &ent_prev); + if (ret) { + ret_sp = krb5_store_int32(rsp, KADM5_BAD_PRINCIPAL); + kadm5_free_principal_ent(contextp, &ent); + goto fail; + } + } + ret = kadm5_modify_principal(kadm_handlep, &ent, mask); + kadm5_free_principal_ent(kadm_handlep, &ent); + ret_sp = krb5_store_int32(rsp, ret); break; } + case kadm_prune:{ + op = "PRUNE"; + if (readonly) { + ret_sp = krb5_store_int32(rsp, ret = KADM5_READ_ONLY); + goto fail; + } + ret = krb5_ret_principal(sp, &princ); + if (ret == 0) + ret = krb5_ret_int32(sp, &kvno); + if (ret == HEIM_ERR_EOF) { + kvno = 0; + } else if (ret) { + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); + goto fail; + } + krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); + krb5_warnx(contextp->context, "%s: %s %s", client, op, name); + ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ); + if (ret) { + ret_sp = krb5_store_int32(rsp, ret); + goto fail; + } + + ret = kadm5_prune_principal(kadm_handlep, princ, kvno); + ret_sp = krb5_store_int32(rsp, ret); + break; + } case kadm_rename:{ op = "RENAME"; + if (readonly) { + ret_sp = krb5_store_int32(rsp, ret = KADM5_READ_ONLY); + goto fail; + } ret = krb5_ret_principal(sp, &princ); - if(ret) + if (ret == 0) + ret = krb5_ret_principal(sp, &princ2); + if (ret) { + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); goto fail; - ret = krb5_ret_principal(sp, &princ2); - if(ret){ - krb5_free_principal(context->context, princ); - goto fail; - } - krb5_unparse_name_fixed(context->context, princ, name, sizeof(name)); - krb5_unparse_name_fixed(context->context, princ2, name2, sizeof(name2)); - krb5_warnx(context->context, "%s: %s %s -> %s", + } + + krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); + krb5_unparse_name_fixed(contextp->context, princ2, + name2, sizeof(name2)); + krb5_warnx(contextp->context, "%s: %s %s -> %s", client, op, name, name2); - ret = _kadm5_acl_check_permission(context, + ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_ADD, - princ2) - || _kadm5_acl_check_permission(context, - KADM5_PRIV_DELETE, - princ); - if(ret){ - krb5_free_principal(context->context, princ); - krb5_free_principal(context->context, princ2); + princ2); + if (ret == 0) { + /* + * Also require modify for the principal. For backwards + * compatibility, allow delete permission on the old name to + * cure lack of modify permission on the old name. + */ + ret = _kadm5_acl_check_permission(contextp, + KADM5_PRIV_MODIFY, + princ); + if (ret) { + ret = _kadm5_acl_check_permission(contextp, + KADM5_PRIV_DELETE, + princ); + } + } + if (ret) { + ret_sp = krb5_store_int32(rsp, ret); goto fail; - } - ret = kadm5_rename_principal(kadm_handle, princ, princ2); - krb5_free_principal(context->context, princ); - krb5_free_principal(context->context, princ2); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - krb5_store_int32(sp, ret); + } + + ret = kadm5_rename_principal(kadm_handlep, princ, princ2); + ret_sp = krb5_store_int32(rsp, ret); break; } case kadm_chpass:{ + krb5_boolean is_self_cpw, allow_self_cpw; + op = "CHPASS"; + if (readonly) { + ret_sp = krb5_store_int32(rsp, ret = KADM5_READ_ONLY); + goto fail; + } ret = krb5_ret_principal(sp, &princ); - if(ret) + if (ret == 0) + ret = krb5_ret_string(sp, &password); + if (ret == 0) + ret = krb5_ret_int32(sp, &keepold); + if (ret == HEIM_ERR_EOF) + ret = 0; + if (ret == 0) { + ret = krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); + if (ret == 0) + krb5_warnx(contextp->context, "%s: %s %s", client, op, name); + } + if (ret) { + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); goto fail; - ret = krb5_ret_string(sp, &password); - if(ret){ - krb5_free_principal(context->context, princ); - goto fail; - } - krb5_unparse_name_fixed(context->context, princ, name, sizeof(name)); - krb5_warnx(context->context, "%s: %s %s", client, op, name); + } /* - * The change is allowed if at least one of: - - * a) it's for the principal him/herself and this was an - * initial ticket, but then, check with the password quality - * function. - * b) the user is on the CPW ACL. + * Change password requests are subject to ACLs unless the principal is + * changing their own password and the initial ticket flag is set, and + * the allow_self_change_password configuration option is TRUE. */ - - if (initial - && krb5_principal_compare (context->context, context->caller, - princ)) - { - krb5_data pwd_data; - const char *pwd_reason; - - pwd_data.data = password; - pwd_data.length = strlen(password); - - pwd_reason = kadm5_check_password_quality (context->context, - princ, &pwd_data); - if (pwd_reason != NULL) - ret = KADM5_PASS_Q_DICT; - else - ret = 0; - } else - ret = _kadm5_acl_check_permission(context, KADM5_PRIV_CPW, princ); - - if(ret) { - krb5_free_principal(context->context, princ); - memset(password, 0, strlen(password)); - free(password); - goto fail; + is_self_cpw = + krb5_principal_compare(contextp->context, contextp->caller, princ); + allow_self_cpw = + krb5_config_get_bool_default(contextp->context, NULL, TRUE, + "kadmin", "allow_self_change_password", NULL); + if (!(is_self_cpw && initial && allow_self_cpw)) { + ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ); + if (ret) { + ret_sp = krb5_store_int32(rsp, ret); + goto fail; + } } - ret = kadm5_chpass_principal(kadm_handle, princ, password); - krb5_free_principal(context->context, princ); - memset(password, 0, strlen(password)); - free(password); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - krb5_store_int32(sp, ret); + + ret = kadm5_chpass_principal_3(kadm_handlep, princ, keepold, 0, NULL, + password); + ret_sp = krb5_store_int32(rsp, ret); break; } case kadm_chpass_with_key:{ @@ -268,26 +571,35 @@ kadmind_dispatch(void *kadm_handle, krb5_boolean initial, int n_key_data; op = "CHPASS_WITH_KEY"; + if (readonly) { + ret_sp = krb5_store_int32(rsp, ret = KADM5_READ_ONLY); + goto fail; + } ret = krb5_ret_principal(sp, &princ); - if(ret) - goto fail; - ret = krb5_ret_int32(sp, &n_key_data); - if (ret) { - krb5_free_principal(context->context, princ); - goto fail; + if (ret == 0) + ret = krb5_ret_int32(sp, &n_key_data); + if (ret == 0) { + ret = krb5_ret_int32(sp, &keepold); + if (ret == HEIM_ERR_EOF) + ret = 0; } + if (ret) { + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); + goto fail; + } + /* n_key_data will be squeezed into an int16_t below. */ if (n_key_data < 0 || n_key_data >= 1 << 16 || - n_key_data > UINT_MAX/sizeof(*key_data)) { + (size_t)n_key_data > UINT_MAX/sizeof(*key_data)) { + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); ret = ERANGE; - krb5_free_principal(context->context, princ); goto fail; } key_data = malloc (n_key_data * sizeof(*key_data)); - if (key_data == NULL) { - ret = ENOMEM; - krb5_free_principal(context->context, princ); + if (key_data == NULL && n_key_data != 0) { + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); + ret = krb5_enomem(contextp->context); goto fail; } @@ -296,50 +608,56 @@ kadmind_dispatch(void *kadm_handle, krb5_boolean initial, if (ret) { int16_t dummy = i; - kadm5_free_key_data (context, &dummy, key_data); + kadm5_free_key_data (contextp, &dummy, key_data); free (key_data); - krb5_free_principal(context->context, princ); + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); goto fail; } } - krb5_unparse_name_fixed(context->context, princ, name, sizeof(name)); - krb5_warnx(context->context, "%s: %s %s", client, op, name); - /* * The change is only allowed if the user is on the CPW ACL, * this it to force password quality check on the user. */ - ret = _kadm5_acl_check_permission(context, KADM5_PRIV_CPW, princ); + ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ); + ret_sp = krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); + if (ret_sp == 0) + krb5_warnx(contextp->context, "%s: %s %s (%s)", client, op, name, + ret ? "denied" : "granted"); if(ret) { int16_t dummy = n_key_data; - kadm5_free_key_data (context, &dummy, key_data); + kadm5_free_key_data (contextp, &dummy, key_data); free (key_data); - krb5_free_principal(context->context, princ); + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); goto fail; } - ret = kadm5_chpass_principal_with_key(kadm_handle, princ, - n_key_data, key_data); + ret = kadm5_chpass_principal_with_key_3(kadm_handlep, princ, keepold, + n_key_data, key_data); { int16_t dummy = n_key_data; - kadm5_free_key_data (context, &dummy, key_data); + kadm5_free_key_data (contextp, &dummy, key_data); } free (key_data); - krb5_free_principal(context->context, princ); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - krb5_store_int32(sp, ret); + ret_sp = krb5_store_int32(rsp, ret); break; } case kadm_randkey:{ + size_t i; + op = "RANDKEY"; + if (readonly) { + ret_sp = krb5_store_int32(rsp, ret = KADM5_READ_ONLY); + goto fail; + } ret = krb5_ret_principal(sp, &princ); - if(ret) + if (ret) { + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); goto fail; - krb5_unparse_name_fixed(context->context, princ, name, sizeof(name)); - krb5_warnx(context->context, "%s: %s %s", client, op, name); + } + krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); + krb5_warnx(contextp->context, "%s: %s %s", client, op, name); /* * The change is allowed if at least one of: * a) it's for the principal him/herself and this was an initial ticket @@ -347,28 +665,86 @@ kadmind_dispatch(void *kadm_handle, krb5_boolean initial, */ if (initial - && krb5_principal_compare (context->context, context->caller, + && krb5_principal_compare (contextp->context, contextp->caller, princ)) ret = 0; else - ret = _kadm5_acl_check_permission(context, KADM5_PRIV_CPW, princ); + ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ); - if(ret) { - krb5_free_principal(context->context, princ); + if (ret) { + ret_sp = krb5_store_int32(rsp, ret); goto fail; - } - ret = kadm5_randkey_principal(kadm_handle, princ, - &new_keys, &n_keys); - krb5_free_principal(context->context, princ); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - krb5_store_int32(sp, ret); - if(ret == 0){ - int i; - krb5_store_int32(sp, n_keys); - for(i = 0; i < n_keys; i++){ - krb5_store_keyblock(sp, new_keys[i]); - krb5_free_keyblock_contents(context->context, &new_keys[i]); + } + + /* + * See comments in kadm5_c_randkey_principal() regarding the + * protocol. + */ + ret = krb5_ret_int32(sp, &keepold); + if (ret != 0 && ret != HEIM_ERR_EOF) { + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); + goto fail; + } + + ret = krb5_ret_int32(sp, &n_ks_tuple); + if (ret == HEIM_ERR_EOF) { + const char *enctypes; + size_t n; + + enctypes = krb5_config_get_string(contextp->context, NULL, + "realms", + krb5_principal_get_realm(contextp->context, + princ), + "supported_enctypes", NULL); + if (enctypes == NULL || enctypes[0] == '\0') + enctypes = "aes128-cts-hmac-sha1-96"; + ret = krb5_string_to_keysalts2(contextp->context, enctypes, + &n, &ks_tuple); + n_ks_tuple = n; + } + if (ret != 0) { + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); /* XXX */ + goto fail; + } + + if (n_ks_tuple < 0) { + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); /* XXX */ + ret = EOVERFLOW; + goto fail; + } + free(ks_tuple); + if ((ks_tuple = calloc(n_ks_tuple, sizeof (*ks_tuple))) == NULL) { + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); + ret = errno; + goto fail; + } + + for (i = 0; i < n_ks_tuple; i++) { + ret = krb5_ret_int32(sp, &ks_tuple[i].ks_enctype); + if (ret != 0) { + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); + free(ks_tuple); + goto fail; + } + ret = krb5_ret_int32(sp, &ks_tuple[i].ks_salttype); + if (ret != 0) { + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); + free(ks_tuple); + goto fail; + } + } + ret = kadm5_randkey_principal_3(kadm_handlep, princ, keepold, + n_ks_tuple, ks_tuple, &new_keys, + &n_keys); + free(ks_tuple); + + ret_sp = krb5_store_int32(rsp, ret); + if (ret == 0 && ret_sp == 0){ + ret_sp = krb5_store_int32(rsp, n_keys); + for (i = 0; i < n_keys; i++){ + if (ret_sp == 0) + ret_sp = krb5_store_keyblock(rsp, new_keys[i]); + krb5_free_keyblock_contents(contextp->context, &new_keys[i]); } free(new_keys); } @@ -376,71 +752,271 @@ kadmind_dispatch(void *kadm_handle, krb5_boolean initial, } case kadm_get_privs:{ uint32_t privs; - ret = kadm5_get_privs(kadm_handle, &privs); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - krb5_store_int32(sp, ret); - if(ret == 0) - krb5_store_uint32(sp, privs); + ret = kadm5_get_privs(kadm_handlep, &privs); + if (ret == 0) + ret_sp = krb5_store_uint32(rsp, privs); break; } case kadm_get_princs:{ op = "LIST"; ret = krb5_ret_int32(sp, &tmp); - if(ret) + if (ret) { + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); goto fail; - if(tmp){ + } + /* See kadm5_c_iter_principals() */ + if (tmp == 0x55555555) { + /* Want online iteration */ ret = krb5_ret_string(sp, &expression); - if(ret) + if (ret) { + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); + goto fail; + } + if (expression[0] == '\0') { + free(expression); + expression = NULL; + } + } else if (tmp) { + ret = krb5_ret_string(sp, &expression); + if (ret) { + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); goto fail; + } }else expression = NULL; - krb5_warnx(context->context, "%s: %s %s", client, op, + krb5_warnx(contextp->context, "%s: %s %s", client, op, expression ? expression : "*"); - ret = _kadm5_acl_check_permission(context, KADM5_PRIV_LIST, NULL); + ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_LIST, NULL); if(ret){ + ret_sp = krb5_store_int32(rsp, ret); free(expression); goto fail; } - ret = kadm5_get_principals(kadm_handle, expression, &princs, &n_princs); - free(expression); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - krb5_store_int32(sp, ret); - if(ret == 0){ - int i; - krb5_store_int32(sp, n_princs); - for(i = 0; i < n_princs; i++) - krb5_store_string(sp, princs[i]); - kadm5_free_name_list(kadm_handle, princs, &n_princs); - } + if (fd > -1 && tmp == 0x55555555) { + struct iter_cb_data iter_cbdata; + int n; + + /* + * The client proposes that we speak the online variation of LIST + * by sending a magic value in the int32 that is meant to be a + * boolean for "an expression follows". The client must send an + * expression in this case because the server might be an old one, + * so even if the caller to kadm5_get/iter_principals() passed NULL + * for the expression, the client must send something ("*"). + * + * The list of principals will be streamed in multiple replies. + * + * The first reply will have just a return code and a negative + * count of maximum number of names per-subsequent reply. See + * `iter_cb()'. + * + * The second reply, third, .., nth replies will have a return code + * followed by 50 names, except the last reply must have fewer than + * 50 names -zero if need be- so the client can deterministically + * notice the end of the stream. + */ + + n = list_chunk_size; + if (n < 0) + n = krb5_config_get_int_default(contextp->context, NULL, -1, + "kadmin", "list_chunk_size", NULL); + if (n < 0) + n = 50; + if (n > 500) + n = 500; + if ((iter_cbdata.rsp = krb5_storage_emem()) == NULL) { + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); + ret = krb5_enomem(contextp->context); + goto fail; + } + iter_cbdata.context = contextp->context; + iter_cbdata.initial = 1; + iter_cbdata.stop = 0; + iter_cbdata.ret = 0; + iter_cbdata.ac = ac; + iter_cbdata.fd = fd; + iter_cbdata.n = n; + iter_cbdata.i = 0; + + /* + * All sending of replies will happen in iter_cb, except for the + * final chunk with the final result code. + */ + iter_cbdata.ret = kadm5_iter_principals(kadm_handlep, expression, + iter_cb, &iter_cbdata); + /* Send terminating chunk */ + iter_cb(&iter_cbdata, NULL); + /* Final result */ + ret = krb5_store_int32(rsp, iter_cbdata.ret); + krb5_storage_free(iter_cbdata.rsp); + } else { + ret = kadm5_get_principals(kadm_handlep, expression, &princs, &n_princs); + ret_sp = krb5_store_int32(rsp, ret); + if (ret == 0 && ret_sp == 0) { + int i; + + ret_sp = krb5_store_int32(rsp, n_princs); + for (i = 0; ret_sp == 0 && i < n_princs; i++) + ret_sp = krb5_store_string(rsp, princs[i]); + kadm5_free_name_list(kadm_handlep, princs, &n_princs); + } + } + free(expression); break; } default: - krb5_warnx(context->context, "%s: UNKNOWN OP %d", client, cmd); - krb5_storage_free(sp); - sp = krb5_storage_emem(); - krb5_store_int32(sp, KADM5_FAILURE); + krb5_warnx(contextp->context, "%s: UNKNOWN OP %d", client, cmd); + ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); break; } - krb5_storage_to_data(sp, out); - krb5_storage_free(sp); - return 0; + fail: - krb5_warn(context->context, ret, "%s", op); - krb5_storage_seek(sp, 0, SEEK_SET); - krb5_store_int32(sp, ret); - krb5_storage_to_data(sp, out); + if (password != NULL) { + len = strlen(password); + memset_s(password, len, 0, len); + free(password); + } + krb5_storage_to_data(rsp, out); + krb5_storage_free(rsp); krb5_storage_free(sp); + krb5_free_principal(contextp->context, princ); + krb5_free_principal(contextp->context, princ2); + if (ret) + krb5_warn(contextp->context, ret, "%s", op); + if (out->length == 0) + krb5_warn(contextp->context, ret, "%s: reply failed", op); + else if (ret_sp) + krb5_warn(contextp->context, ret, "%s: reply incomplete", op); + if (ret_sp) + return ret_sp; + return 0; +} + +struct iter_aliases_ctx { + HDB_Ext_Aliases aliases; + krb5_tl_data *tl; + int alias_idx; + int done; +}; + +static kadm5_ret_t +iter_aliases(kadm5_principal_ent_rec *from, + struct iter_aliases_ctx *ctx, + krb5_principal *out) +{ + HDB_extension ext; + kadm5_ret_t ret; + size_t size; + + *out = NULL; + + if (ctx->done > 0) + return 0; + if (from == NULL) { + ctx->done = 1; + return 0; + } + + if (ctx->done == 0) { + if (ctx->alias_idx < ctx->aliases.aliases.len) { + *out = &ctx->aliases.aliases.val[ctx->alias_idx++]; + return 0; + } + /* Out of aliases in this TL, step to next TL */ + ctx->tl = ctx->tl->tl_data_next; + } else if (ctx->done < 0) { + /* Setup iteration context */ + memset(ctx, 0, sizeof(*ctx)); + ctx->done = 0; + ctx->aliases.aliases.val = NULL; + ctx->aliases.aliases.len = 0; + ctx->tl = from->tl_data; + } + + free_HDB_Ext_Aliases(&ctx->aliases); + ctx->alias_idx = 0; + + /* Find TL with aliases */ + for (; ctx->tl != NULL; ctx->tl = ctx->tl->tl_data_next) { + if (ctx->tl->tl_data_type != KRB5_TL_EXTENSION) + continue; + + ret = decode_HDB_extension(ctx->tl->tl_data_contents, + ctx->tl->tl_data_length, + &ext, &size); + if (ret) + return ret; + if (ext.data.element == choice_HDB_extension_data_aliases && + ext.data.u.aliases.aliases.len > 0) { + ctx->aliases = ext.data.u.aliases; + break; + } + free_HDB_extension(&ext); + } + + if (ctx->tl != NULL && ctx->aliases.aliases.len > 0) { + *out = &ctx->aliases.aliases.val[ctx->alias_idx++]; + return 0; + } + + ctx->done = 1; + return 0; +} + +static kadm5_ret_t +check_aliases(kadm5_server_context *contextp, + kadm5_principal_ent_rec *add_princ, + kadm5_principal_ent_rec *del_princ) +{ + kadm5_ret_t ret; + struct iter_aliases_ctx iter; + struct iter_aliases_ctx iter_del; + krb5_principal new_name, old_name; + int match; + + /* + * Yeah, this is O(N^2). Gathering and sorting all the aliases + * would be a bit of a pain; if we ever have principals with enough + * aliases for this to be a problem, we can fix it then. + */ + for (iter.done = -1; iter.done != 1;) { + match = 0; + ret = iter_aliases(add_princ, &iter, &new_name); + if (ret) + return ret; + if (iter.done == 1) + break; + for (iter_del.done = -1; iter_del.done != 1;) { + ret = iter_aliases(del_princ, &iter_del, &old_name); + if (ret) + return ret; + if (iter_del.done == 1) + break; + if (!krb5_principal_compare(contextp->context, new_name, old_name)) + continue; + free_HDB_Ext_Aliases(&iter_del.aliases); + match = 1; + break; + } + if (match) + continue; + ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_ADD, new_name); + if (ret) { + free_HDB_Ext_Aliases(&iter.aliases); + return ret; + } + } + return 0; } static void -v5_loop (krb5_context context, +v5_loop (krb5_context contextp, krb5_auth_context ac, krb5_boolean initial, - void *kadm_handle, - int fd) + void *kadm_handlep, + krb5_socket_t fd, + int readonly) { krb5_error_code ret; krb5_data in, out; @@ -449,17 +1025,22 @@ v5_loop (krb5_context context, doing_useful_work = 0; if(term_flag) exit(0); - ret = krb5_read_priv_message(context, ac, &fd, &in); + ret = krb5_read_priv_message(contextp, ac, &fd, &in); if(ret == HEIM_ERR_EOF) exit(0); if(ret) - krb5_err(context, 1, ret, "krb5_read_priv_message"); + krb5_err(contextp, 1, ret, "krb5_read_priv_message"); doing_useful_work = 1; - kadmind_dispatch(kadm_handle, initial, &in, &out); + ret = kadmind_dispatch(kadm_handlep, initial, &in, ac, fd, &out, + readonly); + if (ret) + krb5_err(contextp, 1, ret, "kadmind_dispatch"); krb5_data_free(&in); - ret = krb5_write_priv_message(context, ac, &fd, &out); + if (out.length) + ret = krb5_write_priv_message(contextp, ac, &fd, &out); + krb5_data_free(&out); if(ret) - krb5_err(context, 1, ret, "krb5_write_priv_message"); + krb5_err(contextp, 1, ret, "krb5_write_priv_message"); } } @@ -469,106 +1050,125 @@ match_appl_version(const void *data, const char *appl_version) unsigned minor; if(sscanf(appl_version, "KADM0.%u", &minor) != 1) return 0; - *(unsigned*)data = minor; + /*XXX*/ + *(unsigned*)(intptr_t)data = minor; return 1; } static void -handle_v5(krb5_context context, +handle_v5(krb5_context contextp, krb5_keytab keytab, - int fd) + krb5_socket_t fd, + int readonly) { krb5_error_code ret; krb5_ticket *ticket; char *server_name; char *client; - void *kadm_handle; + void *kadm_handlep; krb5_boolean initial; krb5_auth_context ac = NULL; - - unsigned kadm_version; + unsigned kadm_version = 1; kadm5_config_params realm_params; - ret = krb5_recvauth_match_version(context, &ac, &fd, + ret = krb5_recvauth_match_version(contextp, &ac, &fd, match_appl_version, &kadm_version, NULL, KRB5_RECVAUTH_IGNORE_VERSION, keytab, &ticket); - if(ret == KRB5_KT_NOTFOUND) - krb5_errx(context, 1, "krb5_recvauth: key not found"); - if(ret) - krb5_err(context, 1, ret, "krb5_recvauth"); - - ret = krb5_unparse_name (context, ticket->server, &server_name); - if (ret) - krb5_err (context, 1, ret, "krb5_unparse_name"); - - if (strncmp (server_name, KADM5_ADMIN_SERVICE, - strlen(KADM5_ADMIN_SERVICE)) != 0) - krb5_errx (context, 1, "ticket for strange principal (%s)", - server_name); - - free (server_name); + if (ret) { + krb5_err(contextp, 1, ret, "krb5_recvauth"); + return; + } + ret = krb5_unparse_name(contextp, ticket->server, &server_name); + if (ret) { + krb5_err(contextp, 1, ret, "krb5_unparse_name"); + krb5_free_ticket(contextp, ticket); + return; + } + if (strncmp(server_name, KADM5_ADMIN_SERVICE, + strlen(KADM5_ADMIN_SERVICE)) != 0) { + krb5_errx(contextp, 1, "ticket for strange principal (%s)", server_name); + krb5_free_ticket(contextp, ticket); + free(server_name); + return; + } + free(server_name); memset(&realm_params, 0, sizeof(realm_params)); if(kadm_version == 1) { krb5_data params; - ret = krb5_read_priv_message(context, ac, &fd, ¶ms); - if(ret) - krb5_err(context, 1, ret, "krb5_read_priv_message"); - _kadm5_unmarshal_params(context, ¶ms, &realm_params); + ret = krb5_read_priv_message(contextp, ac, &fd, ¶ms); + if (ret) { + krb5_err(contextp, 1, ret, "krb5_read_priv_message"); + krb5_free_ticket(contextp, ticket); + return; + } + ret = _kadm5_unmarshal_params(contextp, ¶ms, &realm_params); + if (ret) { + krb5_err(contextp, 1, ret, + "Could not read or parse kadm5 parameters"); + krb5_free_ticket(contextp, ticket); + return; + } } initial = ticket->ticket.flags.initial; - ret = krb5_unparse_name(context, ticket->client, &client); - if (ret) - krb5_err (context, 1, ret, "krb5_unparse_name"); - krb5_free_ticket (context, ticket); - ret = kadm5_s_init_with_password_ctx(context, + ret = krb5_unparse_name(contextp, ticket->client, &client); + krb5_free_ticket(contextp, ticket); + if (ret) { + krb5_err(contextp, 1, ret, "krb5_unparse_name"); + return; + } + ret = kadm5_s_init_with_password_ctx(contextp, client, NULL, KADM5_ADMIN_SERVICE, &realm_params, 0, 0, - &kadm_handle); - if(ret) - krb5_err (context, 1, ret, "kadm5_init_with_password_ctx"); - v5_loop (context, ac, initial, kadm_handle, fd); + &kadm_handlep); + if (ret) { + krb5_err(contextp, 1, ret, "kadm5_init_with_password_ctx"); + return; + } + v5_loop(contextp, ac, initial, kadm_handlep, fd, readonly); } krb5_error_code -kadmind_loop(krb5_context context, +kadmind_loop(krb5_context contextp, krb5_keytab keytab, - int fd) + krb5_socket_t sock, + int readonly) { u_char buf[sizeof(KRB5_SENDAUTH_VERSION) + 4]; ssize_t n; unsigned long len; - n = krb5_net_read(context, &fd, buf, 4); + n = krb5_net_read(contextp, &sock, buf, 4); if(n == 0) exit(0); if(n < 0) - krb5_err(context, 1, errno, "read"); + krb5_err(contextp, 1, errno, "read"); _krb5_get_int(buf, &len, 4); if (len == sizeof(KRB5_SENDAUTH_VERSION)) { - n = krb5_net_read(context, &fd, buf + 4, len); + n = krb5_net_read(contextp, &sock, buf + 4, len); if (n < 0) - krb5_err (context, 1, errno, "reading sendauth version"); + krb5_err (contextp, 1, errno, "reading sendauth version"); if (n == 0) - krb5_errx (context, 1, "EOF reading sendauth version"); + krb5_errx (contextp, 1, "EOF reading sendauth version"); if(memcmp(buf + 4, KRB5_SENDAUTH_VERSION, len) == 0) { - handle_v5(context, keytab, fd); + handle_v5(contextp, keytab, sock, readonly); return 0; } len += 4; } else len = 4; - handle_mit(context, buf, len, fd); + handle_mit(contextp, buf, len, sock, readonly); return 0; } + diff --git a/kadmin/stash.c b/kadmin/stash.c index 62e4db653..c33623038 100644 --- a/kadmin/stash.c +++ b/kadmin/stash.c @@ -3,6 +3,8 @@ * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -34,17 +36,16 @@ #include "kadmin_locl.h" #include "kadmin-commands.h" -RCSID("$Id$"); - extern int local_flag; int stash(struct stash_options *opt, int argc, char **argv) { - char buf[1024]; + char buf[1024+1]; krb5_error_code ret; krb5_enctype enctype; hdb_master_key mkey; + int aret; if(!local_flag) { krb5_warnx(context, "stash is only available in local (-l) mode"); @@ -58,8 +59,8 @@ stash(struct stash_options *opt, int argc, char **argv) } if(opt->key_file_string == NULL) { - asprintf(&opt->key_file_string, "%s/m-key", hdb_db_dir(context)); - if (opt->key_file_string == NULL) + aret = asprintf(&opt->key_file_string, "%s/m-key", hdb_db_dir(context)); + if (aret == -1) errx(1, "out of memory"); } @@ -74,6 +75,7 @@ stash(struct stash_options *opt, int argc, char **argv) if (ret) krb5_warn(context, ret, "reading master key from %s", opt->key_file_string); + hdb_free_master_key(context, mkey); return 0; } else { krb5_keyblock key; @@ -84,7 +86,7 @@ stash(struct stash_options *opt, int argc, char **argv) salt.saltvalue.length = 0; if(opt->master_key_fd_integer != -1) { ssize_t n; - n = read(opt->master_key_fd_integer, buf, sizeof(buf)); + n = read(opt->master_key_fd_integer, buf, sizeof(buf)-1); if(n == 0) krb5_warnx(context, "end of file reading passphrase"); else if(n < 0) { @@ -93,26 +95,38 @@ stash(struct stash_options *opt, int argc, char **argv) } buf[n] = '\0'; buf[strcspn(buf, "\r\n")] = '\0'; + } else if (opt->random_password_flag) { + random_password (buf, sizeof(buf)); + printf("Using random master stash password: %s\n", buf); } else { - if(UI_UTIL_read_pw_string(buf, sizeof(buf), "Master key: ", 1)) { + if(UI_UTIL_read_pw_string(buf, sizeof(buf), "Master key: ", + UI_UTIL_FLAG_VERIFY)) { hdb_free_master_key(context, mkey); return 0; } } ret = krb5_string_to_key_salt(context, enctype, buf, salt, &key); - ret = hdb_add_master_key(context, &key, &mkey); + if (ret == 0) + ret = hdb_add_master_key(context, &key, &mkey); + if (ret) + krb5_warn(context, errno, "setting master key"); krb5_free_keyblock_contents(context, &key); } { - char *new, *old; - asprintf(&old, "%s.old", opt->key_file_string); - asprintf(&new, "%s.new", opt->key_file_string); - if(old == NULL || new == NULL) { + char *new = NULL, *old = NULL; + + aret = asprintf(&old, "%s.old", opt->key_file_string); + if (aret == -1) { ret = ENOMEM; goto out; } - + aret = asprintf(&new, "%s.new", opt->key_file_string); + if (aret == -1) { + ret = ENOMEM; + goto out; + } + if(unlink(new) < 0 && errno != ENOENT) { ret = errno; goto out; @@ -123,12 +137,18 @@ stash(struct stash_options *opt, int argc, char **argv) unlink(new); else { unlink(old); +#ifndef NO_POSIX_LINKS if(link(opt->key_file_string, old) < 0 && errno != ENOENT) { ret = errno; unlink(new); - } else if(rename(new, opt->key_file_string) < 0) { - ret = errno; + } else { +#endif + if(rename(new, opt->key_file_string) < 0) { + ret = errno; + } +#ifndef NO_POSIX_LINKS } +#endif } out: free(old); diff --git a/kadmin/test_util.c b/kadmin/test_util.c index c7f718090..56e4d1149 100644 --- a/kadmin/test_util.c +++ b/kadmin/test_util.c @@ -32,8 +32,6 @@ #include "kadmin_locl.h" -RCSID("$Id$"); - krb5_context context; void *kadm_handle; diff --git a/kadmin/util.c b/kadmin/util.c index 65849d2a0..6b83bb7a2 100644 --- a/kadmin/util.c +++ b/kadmin/util.c @@ -34,8 +34,6 @@ #include "kadmin_locl.h" #include -RCSID("$Id$"); - /* * util.c - functions for parsing, unparsing, and editing different * types of data used in kadmin. @@ -49,6 +47,12 @@ get_response(const char *prompt, const char *def, char *buf, size_t len); */ struct units kdb_attrs[] = { + { "auth-data-reqd", KRB5_KDB_AUTH_DATA_REQUIRED }, + { "no-auth-data-reqd", KRB5_KDB_NO_AUTH_DATA_REQUIRED }, + { "disallow-client", KRB5_KDB_DISALLOW_CLIENT }, + { "virtual", KRB5_KDB_VIRTUAL }, + { "virtual-keys", KRB5_KDB_VIRTUAL_KEYS }, + { "materialize", KRB5_KDB_MATERIALIZE }, { "allow-digest", KRB5_KDB_ALLOW_DIGEST }, { "allow-kerberos4", KRB5_KDB_ALLOW_KERBEROS4 }, { "trusted-for-delegation", KRB5_KDB_TRUSTED_FOR_DELEGATION }, @@ -67,7 +71,7 @@ struct units kdb_attrs[] = { { "disallow-tgt-based", KRB5_KDB_DISALLOW_TGT_BASED }, { "disallow-forwardable", KRB5_KDB_DISALLOW_FORWARDABLE }, { "disallow-postdated", KRB5_KDB_DISALLOW_POSTDATED }, - { NULL } + { NULL, 0 } }; /* @@ -147,6 +151,61 @@ edit_attributes (const char *prompt, krb5_flags *attr, int *mask, int bit) return 0; } +/* + * try to parse the string `resp' into policy in `attr', also + * setting the `bit' in `mask' if attributes are given and valid. + */ + +#define VALID_POLICY_NAME_CHARS \ + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_" + +int +parse_policy (const char *resp, char **policy, int *mask, int bit) +{ + if (strspn(resp, VALID_POLICY_NAME_CHARS) == strlen(resp) && + *resp != '\0') { + + *policy = strdup(resp); + if (*policy == NULL) { + fprintf (stderr, "Out of memory"); + return -1; + } + if (mask) + *mask |= bit; + return 0; + } else if(*resp == '?') { + print_flags_table (kdb_attrs, stderr); + } else { + fprintf (stderr, "Unable to parse \"%s\"\n", resp); + } + return -1; +} + +/* + * allow the user to edit the attributes in `attr', prompting with `prompt' + */ + +int +edit_policy (const char *prompt, char **policy, int *mask, int bit) +{ + char buf[1024], resp[1024]; + + if (mask && (*mask & bit)) + return 0; + + buf[0] = '\0'; + strlcpy(buf, "default", sizeof (buf)); + for (;;) { + if(get_response("Policy", buf, resp, sizeof(resp)) != 0) + return 1; + if (resp[0] == '\0') + break; + if (parse_policy (resp, policy, mask, bit) == 0) + break; + } + return 0; +} + /* * time_t * the special value 0 means ``never'' @@ -190,11 +249,19 @@ str2time_t (const char *str, time_t *t) if (str[0] == '+') { str++; *t = parse_time(str, "month"); - if (t < 0) + if (*t < 0) return -1; *t += time(NULL); return 0; } + if (str[0] == '-') { + str++; + *t = parse_time(str, "month"); + if (*t < 0) + return -1; + *t = time(NULL) - *t; + return 0; + } if(strcasecmp(str, "never") == 0) { *t = 0; @@ -287,7 +354,14 @@ edit_timet (const char *prompt, krb5_timestamp *value, int *mask, int bit) void deltat2str(unsigned t, char *str, size_t len) { - if(t == 0 || t == INT_MAX) + /* + * A time delta in kadmin context is a positive number, and there's no + * point to it being possibly as large as 2^64 -1, so we use unsigned + * instead of a more generally appropriate type for time deltas (which + * conceptually can be negative, which in kadmin context there's no need + * for). + */ + if (t == 0 || t > INT_MAX) snprintf(str, len, "unlimited"); else unparse_time(t, str, len); @@ -304,6 +378,15 @@ str2deltat(const char *str, krb5_deltat *delta) int res; if(strcasecmp(str, "unlimited") == 0) { + /* + * Using zero to mean "unlimited" is unfortunate. We should use + * `UINT_MAX'. However, we've had this assumption that zero means + * unlimited, so there are HDB entries with present-but-zero max-life + * and max-renew-life. + * + * We could switch to using `UINT_MAX' or `UINT64_MAX' for "unlimited", + * but we'd have to continue to treat `0' as special for some time. + */ *delta = 0; return 0; } @@ -393,6 +476,14 @@ set_defaults(kadm5_principal_ent_t ent, int *mask, && (default_mask & KADM5_ATTRIBUTES) && !(*mask & KADM5_ATTRIBUTES)) ent->attributes = default_ent->attributes & ~KRB5_KDB_DISALLOW_ALL_TIX; + + if (default_ent + && (default_mask & KADM5_POLICY) + && !(*mask & KADM5_POLICY)) { + ent->policy = strdup(default_ent->policy); + if (ent->policy == NULL) + abort(); + } } int @@ -422,6 +513,10 @@ edit_entry(kadm5_principal_ent_t ent, int *mask, KADM5_ATTRIBUTES) != 0) return 1; + if(edit_policy ("Policy", &ent->policy, mask, + KADM5_POLICY) != 0) + return 1; + return 0; } @@ -432,26 +527,27 @@ edit_entry(kadm5_principal_ent_t ent, int *mask, */ int -set_entry(krb5_context context, +set_entry(krb5_context contextp, kadm5_principal_ent_t ent, int *mask, const char *max_ticket_life, const char *max_renewable_life, const char *expiration, const char *pw_expiration, - const char *attributes) + const char *attributes, + const char *policy) { if (max_ticket_life != NULL) { if (parse_deltat (max_ticket_life, &ent->max_life, mask, KADM5_MAX_LIFE)) { - krb5_warnx (context, "unable to parse `%s'", max_ticket_life); + krb5_warnx (contextp, "unable to parse `%s'", max_ticket_life); return 1; } } if (max_renewable_life != NULL) { if (parse_deltat (max_renewable_life, &ent->max_renewable_life, mask, KADM5_MAX_RLIFE)) { - krb5_warnx (context, "unable to parse `%s'", max_renewable_life); + krb5_warnx (contextp, "unable to parse `%s'", max_renewable_life); return 1; } } @@ -459,21 +555,28 @@ set_entry(krb5_context context, if (expiration) { if (parse_timet (expiration, &ent->princ_expire_time, mask, KADM5_PRINC_EXPIRE_TIME)) { - krb5_warnx (context, "unable to parse `%s'", expiration); + krb5_warnx (contextp, "unable to parse `%s'", expiration); return 1; } } if (pw_expiration) { if (parse_timet (pw_expiration, &ent->pw_expiration, mask, KADM5_PW_EXPIRATION)) { - krb5_warnx (context, "unable to parse `%s'", pw_expiration); + krb5_warnx (contextp, "unable to parse `%s'", pw_expiration); return 1; } } if (attributes != NULL) { if (parse_attributes (attributes, &ent->attributes, mask, KADM5_ATTRIBUTES)) { - krb5_warnx (context, "unable to parse `%s'", attributes); + krb5_warnx (contextp, "unable to parse `%s'", attributes); + return 1; + } + } + if (policy != NULL) { + if (parse_policy (policy, &ent->policy, + mask, KADM5_POLICY)) { + krb5_warnx (contextp, "unable to parse `%s'", attributes); return 1; } } @@ -503,6 +606,32 @@ is_expression(const char *string) return 0; } +struct foreach_principal_data { + const char *funcname; + int (*func)(krb5_principal, void *); + void *data; +}; + +static int +foreach_principal_cb(void *data, const char *p) +{ + struct foreach_principal_data *d = data; + krb5_principal princ; + krb5_error_code ret; + + ret = krb5_parse_name(context, p, &princ); + if (ret) + return ret; + + ret = d->func(princ, d->data); + krb5_free_principal(context, princ); + if (ret) { + krb5_warn(context, ret, "%s %s", d->funcname, p); + krb5_clear_error_message(context); + } + return ret; +} + /* * Loop over all principals matching exp. If any of calls to `func' * failes, the first error is returned when all principals are @@ -514,52 +643,66 @@ foreach_principal(const char *exp_str, const char *funcname, void *data) { - char **princs; - int num_princs; - int i; - krb5_error_code saved_ret = 0, ret = 0; - krb5_principal princ_ent; + struct foreach_principal_data d; + krb5_error_code ret; + krb5_principal p; int is_expr; + int go_slow = + secure_getenv("KADMIN_USE_GET_PRINCIPALS") != NULL && + *secure_getenv("KADMIN_USE_GET_PRINCIPALS") != '\0'; /* if this isn't an expression, there is no point in wading through the whole database looking for matches */ is_expr = is_expression(exp_str); - if(is_expr) - ret = kadm5_get_principals(kadm_handle, exp_str, &princs, &num_princs); - if(!is_expr || ret == KADM5_AUTH_LIST) { - /* we might be able to perform the requested opreration even - if we're not allowed to list principals */ - num_princs = 1; - princs = malloc(sizeof(*princs)); - if(princs == NULL) - return ENOMEM; - princs[0] = strdup(exp_str); - if(princs[0] == NULL){ - free(princs); - return ENOMEM; - } - } else if(ret) { - krb5_warn(context, ret, "kadm5_get_principals"); - return ret; + + d.funcname = funcname; + d.func = func; + d.data = data; + + if (is_expr && !go_slow) { + ret = kadm5_iter_principals(kadm_handle, exp_str, + foreach_principal_cb, &d); + if (ret == 0) + return 0; + if (ret != KADM5_AUTH_LIST) { + krb5_warn(context, ret, "kadm5_iter_principals"); + return ret; + } + } else if (is_expr) { + char **princs = NULL; + int count = 0; + + /* + * This is just for testing, and maybe in case there are HDB backends + * that are not re-entrant (LDAP?). + */ + ret = kadm5_get_principals(kadm_handle, exp_str, &princs, &count); + if (ret == 0 && count > 0) { + int i; + + for (i = 0; ret == 0 && i < count; i++) + ret = foreach_principal_cb(&d, princs[i]); + kadm5_free_name_list(kadm_handle, princs, &count); + return ret; + } + if (ret != KADM5_AUTH_LIST) { + krb5_warn(context, ret, "kadm5_iter_principals"); + return ret; + } } - for(i = 0; i < num_princs; i++) { - ret = krb5_parse_name(context, princs[i], &princ_ent); - if(ret){ - krb5_warn(context, ret, "krb5_parse_name(%s)", princs[i]); - continue; - } - ret = (*func)(princ_ent, data); - if(ret) { - krb5_clear_error_message(context); - krb5_warn(context, ret, "%s %s", funcname, princs[i]); - if (saved_ret == 0) - saved_ret = ret; - } - krb5_free_principal(context, princ_ent); + /* we might be able to perform the requested opreration even + if we're not allowed to list principals */ + ret = krb5_parse_name(context, exp_str, &p); + if (ret) { + krb5_warn(context, ret, "krb5_parse_name(%s)", exp_str); + return ret; } - if (ret == 0 && saved_ret != 0) - ret = saved_ret; - kadm5_free_name_list(kadm_handle, princs, &num_princs); + ret = (*func)(p, data); + if (ret) { + krb5_warn(context, ret, "%s %s", funcname, exp_str); + krb5_clear_error_message(context); + } + krb5_free_principal(context, p); return ret; } diff --git a/kcm/Makefile.am b/kcm/Makefile.am index 91eedabd9..b9649d387 100644 --- a/kcm/Makefile.am +++ b/kcm/Makefile.am @@ -2,7 +2,7 @@ include $(top_srcdir)/Makefile.am.common -AM_CPPFLAGS += $(INCLUDE_libintl) $(INCLUDE_krb4) $(INCLUDE_hcrypto) -I$(srcdir)/../lib/krb5 +AM_CPPFLAGS += $(INCLUDE_libintl) -I$(srcdir)/../lib/krb5 libexec_PROGRAMS = kcm @@ -17,13 +17,15 @@ kcm_SOURCES = \ glue.c \ headers.h \ kcm_locl.h \ - kcm-protos.h \ log.c \ main.c \ protocol.c \ + sessions.c \ renew.c -$(srcdir)/kcm-protos.h: +noinst_HEADERS = $(srcdir)/kcm-protos.h + +$(srcdir)/kcm-protos.h: $(kcm_SOURCES) cd $(srcdir); perl ../cf/make-proto.pl -o kcm-protos.h -q -P comment $(kcm_SOURCES) || rm -f kcm-protos.h $(kcm_OBJECTS): $(srcdir)/kcm-protos.h @@ -31,13 +33,13 @@ $(kcm_OBJECTS): $(srcdir)/kcm-protos.h man_MANS = kcm.8 LDADD = $(top_builddir)/lib/hdb/libhdb.la \ - $(LIB_openldap) \ $(top_builddir)/lib/krb5/libkrb5.la \ - $(LIB_krb4) \ $(LIB_hcrypto) \ $(top_builddir)/lib/asn1/libasn1.la \ + $(top_builddir)/lib/ntlm/libheimntlm.la \ + $(top_builddir)/lib/ipc/libheim-ipcs.la \ $(LIB_roken) \ $(LIB_door_create) \ $(LIB_pidfile) -EXTRA_DIST = $(man_MANS) +EXTRA_DIST = NTMakefile $(man_MANS) diff --git a/kcm/NTMakefile b/kcm/NTMakefile new file mode 100644 index 000000000..4f25946f6 --- /dev/null +++ b/kcm/NTMakefile @@ -0,0 +1,35 @@ +######################################################################## +# +# Copyright (c) 2009, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=kcm + +!include ../windows/NTMakefile.w32 + diff --git a/kcm/acl.c b/kcm/acl.c index 2823260ca..5102c1335 100644 --- a/kcm/acl.c +++ b/kcm/acl.c @@ -2,6 +2,8 @@ * Copyright (c) 2005, PADL Software Pty Ltd. * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -32,8 +34,6 @@ #include "kcm_locl.h" -RCSID("$Id$"); - krb5_error_code kcm_access(krb5_context context, kcm_client *client, @@ -58,6 +58,8 @@ kcm_access(krb5_context context, case KCM_OP_GET_INITIAL_TICKET: case KCM_OP_GET_TICKET: case KCM_OP_MOVE_CACHE: + case KCM_OP_SET_DEFAULT_CACHE: + case KCM_OP_SET_KDC_OFFSET: write_p = 1; read_p = 0; break; @@ -67,13 +69,18 @@ kcm_access(krb5_context context, case KCM_OP_GEN_NEW: case KCM_OP_RETRIEVE: case KCM_OP_GET_PRINCIPAL: - case KCM_OP_GET_FIRST: - case KCM_OP_GET_NEXT: - case KCM_OP_END_GET: - case KCM_OP_MAX: + case KCM_OP_GET_CRED_UUID_LIST: + case KCM_OP_GET_CRED_BY_UUID: + case KCM_OP_GET_CACHE_UUID_LIST: + case KCM_OP_GET_CACHE_BY_UUID: + case KCM_OP_GET_DEFAULT_CACHE: + case KCM_OP_GET_KDC_OFFSET: write_p = 0; read_p = 1; break; + default: + ret = KRB5_FCC_PERM; + goto out; } if (ccache->flags & KCM_FLAGS_OWNER_IS_SYSTEM) { @@ -87,33 +94,45 @@ kcm_access(krb5_context context, } /* Let root always read system caches */ - if (client->uid == 0) { + if (CLIENT_IS_ROOT(client)) { ret = 0; goto out; } } - mask = 0; + /* start out with "other" mask */ + mask = S_IROTH|S_IWOTH; - /* Root may do whatever they like */ - if (client->uid == ccache->uid || CLIENT_IS_ROOT(client)) { + /* root can do anything */ + if (CLIENT_IS_ROOT(client)) { if (read_p) - mask |= S_IRUSR; + mask |= S_IRUSR|S_IRGRP|S_IROTH; if (write_p) - mask |= S_IWUSR; - } else if (client->gid == ccache->gid || CLIENT_IS_ROOT(client)) { - if (read_p) - mask |= S_IRGRP; - if (write_p) - mask |= S_IWGRP; - } else { + mask |= S_IWUSR|S_IWGRP|S_IWOTH; + } + /* same session same as owner */ + if (kcm_is_same_session(client, ccache->uid, ccache->session)) { if (read_p) mask |= S_IROTH; if (write_p) mask |= S_IWOTH; } + /* owner */ + if (client->uid == ccache->uid) { + if (read_p) + mask |= S_IRUSR; + if (write_p) + mask |= S_IWUSR; + } + /* group */ + if (client->gid == ccache->gid) { + if (read_p) + mask |= S_IRGRP; + if (write_p) + mask |= S_IWGRP; + } - ret = ((ccache->mode & mask) == mask) ? 0 : KRB5_FCC_PERM; + ret = (ccache->mode & mask) ? 0 : KRB5_FCC_PERM; out: if (ret) { diff --git a/kcm/acquire.c b/kcm/acquire.c index 6d211c467..a5450c05a 100644 --- a/kcm/acquire.c +++ b/kcm/acquire.c @@ -32,8 +32,6 @@ #include "kcm_locl.h" -RCSID("$Id$"); - /* * Get a new ticket using a keytab/cached key and swap it into * an existing redentials cache @@ -50,7 +48,9 @@ kcm_ccache_acquire(krb5_context context, krb5_get_init_creds_opt *opt = NULL; krb5_ccache_data ccdata; char *in_tkt_service = NULL; + const char *estr; + *credp = NULL; memset(&cred, 0, sizeof(cred)); KCM_ASSERT_VALID(ccache); @@ -69,7 +69,7 @@ kcm_ccache_acquire(krb5_context context, ccache->name); return KRB5_FCC_INTERNAL; } - + HEIMDAL_MUTEX_lock(&ccache->mutex); /* Fake up an internal ccache */ @@ -79,9 +79,11 @@ kcm_ccache_acquire(krb5_context context, if (ccache->server != NULL) { ret = krb5_unparse_name(context, ccache->server, &in_tkt_service); if (ret) { + estr = krb5_get_error_message(context, ret); kcm_log(0, "Failed to unparse service principal name for cache %s: %s", - ccache->name, krb5_get_err_text(context, ret)); - return ret; + ccache->name, estr); + krb5_free_error_message(context, estr); + goto out; } } @@ -116,28 +118,28 @@ kcm_ccache_acquire(krb5_context context, } if (ret) { + estr = krb5_get_error_message(context, ret); kcm_log(0, "Failed to acquire credentials for cache %s: %s", - ccache->name, krb5_get_err_text(context, ret)); - if (in_tkt_service != NULL) - free(in_tkt_service); + ccache->name, estr); + krb5_free_error_message(context, estr); goto out; } - if (in_tkt_service != NULL) - free(in_tkt_service); - /* Swap them in */ kcm_ccache_remove_creds_internal(context, ccache); ret = kcm_ccache_store_cred_internal(context, ccache, &cred, 0, credp); if (ret) { + estr = krb5_get_error_message(context, ret); kcm_log(0, "Failed to store credentials for cache %s: %s", - ccache->name, krb5_get_err_text(context, ret)); + ccache->name, estr); + krb5_free_error_message(context, estr); krb5_free_cred_contents(context, &cred); goto out; } out: + free(in_tkt_service); if (opt) krb5_get_init_creds_opt_free(context, opt); diff --git a/kcm/cache.c b/kcm/cache.c index 88b3ae25b..b11812769 100644 --- a/kcm/cache.c +++ b/kcm/cache.c @@ -2,6 +2,8 @@ * Copyright (c) 2005, PADL Software Pty Ltd. * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -32,30 +34,31 @@ #include "kcm_locl.h" -RCSID("$Id$"); - -static HEIMDAL_MUTEX ccache_mutex = HEIMDAL_MUTEX_INITIALIZER; -static kcm_ccache_data *ccache_head = NULL; +HEIMDAL_MUTEX ccache_mutex = HEIMDAL_MUTEX_INITIALIZER; +kcm_ccache_data *ccache_head = NULL; static unsigned int ccache_nextid = 0; char *kcm_ccache_nextid(pid_t pid, uid_t uid, gid_t gid) { unsigned n; char *name; + int ret; HEIMDAL_MUTEX_lock(&ccache_mutex); n = ++ccache_nextid; HEIMDAL_MUTEX_unlock(&ccache_mutex); - asprintf(&name, "%d:%u", uid, n); + ret = asprintf(&name, "%ld:%u", (long)uid, n); + if (ret == -1) + return NULL; return name; } -static krb5_error_code -kcm_ccache_resolve_internal(krb5_context context, - const char *name, - kcm_ccache *ccache) +krb5_error_code +kcm_ccache_resolve(krb5_context context, + const char *name, + kcm_ccache *ccache) { kcm_ccache p; krb5_error_code ret; @@ -85,6 +88,66 @@ kcm_ccache_resolve_internal(krb5_context context, return ret; } +krb5_error_code +kcm_ccache_resolve_by_uuid(krb5_context context, + kcmuuid_t uuid, + kcm_ccache *ccache) +{ + kcm_ccache p; + krb5_error_code ret; + + *ccache = NULL; + + ret = KRB5_FCC_NOFILE; + + HEIMDAL_MUTEX_lock(&ccache_mutex); + + for (p = ccache_head; p != NULL; p = p->next) { + if ((p->flags & KCM_FLAGS_VALID) == 0) + continue; + if (memcmp(p->uuid, uuid, sizeof(kcmuuid_t)) == 0) { + ret = 0; + break; + } + } + + if (ret == 0) { + kcm_retain_ccache(context, p); + *ccache = p; + } + + HEIMDAL_MUTEX_unlock(&ccache_mutex); + + return ret; +} + +krb5_error_code +kcm_ccache_get_uuids(krb5_context context, kcm_client *client, kcm_operation opcode, krb5_storage *sp) +{ + krb5_error_code ret; + kcm_ccache p; + + ret = KRB5_FCC_NOFILE; + + HEIMDAL_MUTEX_lock(&ccache_mutex); + + for (p = ccache_head; p != NULL; p = p->next) { + if ((p->flags & KCM_FLAGS_VALID) == 0) + continue; + ret = kcm_access(context, client, opcode, p); + if (ret) { + ret = 0; + continue; + } + krb5_storage_write(sp, p->uuid, sizeof(p->uuid)); + } + + HEIMDAL_MUTEX_unlock(&ccache_mutex); + + return ret; +} + + krb5_error_code kcm_debug_ccache(krb5_context context) { kcm_ccache p; @@ -105,10 +168,10 @@ krb5_error_code kcm_debug_ccache(krb5_context context) ncreds++; if (p->client != NULL) - krb5_unparse_name(context, p->client, &cpn); + (void) krb5_unparse_name(context, p->client, &cpn); if (p->server != NULL) - krb5_unparse_name(context, p->server, &spn); - + (void) krb5_unparse_name(context, p->server, &spn); + kcm_log(7, "cache %08x: name %s refcnt %d flags %04x mode %04o " "uid %d gid %d client %s server %s ncreds %d", p, p->name, p->refcnt, p->flags, p->mode, p->uid, p->gid, @@ -116,19 +179,56 @@ krb5_error_code kcm_debug_ccache(krb5_context context) (spn == NULL) ? "" : spn, ncreds); - if (cpn != NULL) - free(cpn); - if (spn != NULL) - free(spn); + free(cpn); + free(spn); } return 0; } -static krb5_error_code -kcm_ccache_destroy_internal(krb5_context context, const char *name) +static void +kcm_free_ccache_data_internal(krb5_context context, + kcm_ccache_data *cache) { - kcm_ccache *p; + KCM_ASSERT_VALID(cache); + + if (cache->name != NULL) { + free(cache->name); + cache->name = NULL; + } + + if (cache->flags & KCM_FLAGS_USE_KEYTAB) { + krb5_kt_close(context, cache->key.keytab); + cache->key.keytab = NULL; + } else if (cache->flags & KCM_FLAGS_USE_CACHED_KEY) { + krb5_free_keyblock_contents(context, &cache->key.keyblock); + krb5_keyblock_zero(&cache->key.keyblock); + } + + cache->flags = 0; + cache->mode = 0; + cache->uid = -1; + cache->gid = -1; + cache->session = -1; + + kcm_zero_ccache_data_internal(context, cache); + + cache->tkt_life = 0; + cache->renew_life = 0; + cache->kdc_offset = 0; + + cache->next = NULL; + cache->refcnt = 0; + + HEIMDAL_MUTEX_unlock(&cache->mutex); + HEIMDAL_MUTEX_destroy(&cache->mutex); +} + + +krb5_error_code +kcm_ccache_destroy(krb5_context context, const char *name) +{ + kcm_ccache *p, ccache; krb5_error_code ret; ret = KRB5_FCC_NOFILE; @@ -142,11 +242,18 @@ kcm_ccache_destroy_internal(krb5_context context, const char *name) break; } } - if (ret) goto out; - kcm_release_ccache(context, p); + if ((*p)->refcnt != 1) { + ret = EAGAIN; + goto out; + } + + ccache = *p; + *p = (*p)->next; + kcm_free_ccache_data_internal(context, ccache); + free(ccache); out: HEIMDAL_MUTEX_unlock(&ccache_mutex); @@ -195,6 +302,8 @@ kcm_ccache_alloc(krb5_context context, new_slot = 1; } + RAND_bytes(slot->uuid, sizeof(slot->uuid)); + slot->name = strdup(name); if (slot->name == NULL) { ret = KRB5_CC_NOMEM; @@ -212,6 +321,7 @@ kcm_ccache_alloc(krb5_context context, slot->key.keytab = NULL; slot->tkt_life = 0; slot->renew_life = 0; + slot->kdc_offset = 0; if (new_slot) ccache_head = slot; @@ -299,44 +409,6 @@ kcm_zero_ccache_data(krb5_context context, return ret; } -static krb5_error_code -kcm_free_ccache_data_internal(krb5_context context, - kcm_ccache_data *cache) -{ - KCM_ASSERT_VALID(cache); - - if (cache->name != NULL) { - free(cache->name); - cache->name = NULL; - } - - if (cache->flags & KCM_FLAGS_USE_KEYTAB) { - krb5_kt_close(context, cache->key.keytab); - cache->key.keytab = NULL; - } else if (cache->flags & KCM_FLAGS_USE_CACHED_KEY) { - krb5_free_keyblock_contents(context, &cache->key.keyblock); - krb5_keyblock_zero(&cache->key.keyblock); - } - - cache->flags = 0; - cache->mode = 0; - cache->uid = -1; - cache->gid = -1; - - kcm_zero_ccache_data_internal(context, cache); - - cache->tkt_life = 0; - cache->renew_life = 0; - - cache->next = NULL; - cache->refcnt = 0; - - HEIMDAL_MUTEX_unlock(&cache->mutex); - HEIMDAL_MUTEX_destroy(&cache->mutex); - - return 0; -} - krb5_error_code kcm_retain_ccache(krb5_context context, kcm_ccache ccache) @@ -351,26 +423,21 @@ kcm_retain_ccache(krb5_context context, } krb5_error_code -kcm_release_ccache(krb5_context context, - kcm_ccache *ccache) +kcm_release_ccache(krb5_context context, kcm_ccache c) { - kcm_ccache c = *ccache; krb5_error_code ret = 0; KCM_ASSERT_VALID(c); HEIMDAL_MUTEX_lock(&c->mutex); if (c->refcnt == 1) { - ret = kcm_free_ccache_data_internal(context, c); - if (ret == 0) - free(c); + kcm_free_ccache_data_internal(context, c); + free(c); } else { c->refcnt--; HEIMDAL_MUTEX_unlock(&c->mutex); } - *ccache = NULL; - return ret; } @@ -414,29 +481,6 @@ kcm_ccache_new(krb5_context context, return ret; } -krb5_error_code -kcm_ccache_resolve(krb5_context context, - const char *name, - kcm_ccache *ccache) -{ - krb5_error_code ret; - - ret = kcm_ccache_resolve_internal(context, name, ccache); - - return ret; -} - -krb5_error_code -kcm_ccache_destroy(krb5_context context, - const char *name) -{ - krb5_error_code ret; - - ret = kcm_ccache_destroy_internal(context, name); - - return ret; -} - krb5_error_code kcm_ccache_destroy_if_empty(krb5_context context, kcm_ccache ccache) @@ -446,7 +490,7 @@ kcm_ccache_destroy_if_empty(krb5_context context, KCM_ASSERT_VALID(ccache); if (ccache->creds == NULL) { - ret = kcm_ccache_destroy_internal(context, ccache->name); + ret = kcm_ccache_destroy(context, ccache->name); } else ret = 0; @@ -541,6 +585,8 @@ kcm_ccache_remove_cred_internal(krb5_context context, krb5_free_cred_contents(context, &cred->cred); free(cred); ret = 0; + if (*c == NULL) + break; } } @@ -612,3 +658,21 @@ kcm_ccache_retrieve_cred(krb5_context context, return ret; } + +char * +kcm_ccache_first_name(kcm_client *client) +{ + kcm_ccache p; + char *name = NULL; + + HEIMDAL_MUTEX_lock(&ccache_mutex); + + for (p = ccache_head; p != NULL; p = p->next) { + if (kcm_is_same_session(client, p->uid, p->session)) + break; + } + if (p) + name = strdup(p->name); + HEIMDAL_MUTEX_unlock(&ccache_mutex); + return name; +} diff --git a/kcm/client.c b/kcm/client.c index a6c83b45f..061d4e972 100644 --- a/kcm/client.c +++ b/kcm/client.c @@ -2,6 +2,8 @@ * Copyright (c) 2005, PADL Software Pty Ltd. * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -33,8 +35,6 @@ #include "kcm_locl.h" #include -RCSID("$Id$"); - krb5_error_code kcm_ccache_resolve_client(krb5_context context, kcm_client *client, @@ -43,18 +43,57 @@ kcm_ccache_resolve_client(krb5_context context, kcm_ccache *ccache) { krb5_error_code ret; + const char *estr; ret = kcm_ccache_resolve(context, name, ccache); if (ret) { - kcm_log(1, "Failed to resolve cache %s: %s", - name, krb5_get_err_text(context, ret)); + char *uid = NULL; + + /* + * Both MIT and Heimdal are unable to, in krb5_cc_default(), call to + * KCM (or CCAPI, or LSA, or...) to get the user's default ccache name + * in their collection. Instead, the default ccache name is obtained + * in a static way, and for KCM that's "%{UID}". When we + * krb5_cc_switch(), we simply maintain a pointer to the name of the + * ccache that was made the default, but klist can't make use of this + * because krb5_cc_default() can't. + * + * The solution here is to first try resolving the ccache name given by + * the client, and if that fails but the name happens to be what would + * be the library's default KCM ccache name for that user, then try + * resolving it through the default ccache name pointer saved at switch + * time. + */ + if (asprintf(&uid, "%llu", (unsigned long long)client->uid) == -1 || + uid == NULL) + return ENOMEM; + + if (strcmp(name, uid) == 0) { + struct kcm_default_cache *c; + + for (c = default_caches; c != NULL; c = c->next) { + if (kcm_is_same_session(client, c->uid, c->session)) { + if (strcmp(c->name, name) != 0) { + ret = kcm_ccache_resolve(context, c->name, ccache); + break; + } + } + } + } + free(uid); + } + + if (ret) { + estr = krb5_get_error_message(context, ret); + kcm_log(1, "Failed to resolve cache %s: %s", name, estr); + krb5_free_error_message(context, estr); return ret; } ret = kcm_access(context, client, opcode, *ccache); if (ret) { ret = KRB5_FCC_NOFILE; /* don't disclose */ - kcm_release_ccache(context, ccache); + kcm_release_ccache(context, *ccache); } return ret; @@ -67,28 +106,23 @@ kcm_ccache_destroy_client(krb5_context context, { krb5_error_code ret; kcm_ccache ccache; + const char *estr; ret = kcm_ccache_resolve(context, name, &ccache); if (ret) { - kcm_log(1, "Failed to resolve cache %s: %s", - name, krb5_get_err_text(context, ret)); + estr = krb5_get_error_message(context, ret); + kcm_log(1, "Failed to resolve cache %s: %s", name, estr); + krb5_free_error_message(context, estr); return ret; } ret = kcm_access(context, client, KCM_OP_DESTROY, ccache); - if (ret) { - kcm_release_ccache(context, &ccache); + kcm_cleanup_events(context, ccache); + kcm_release_ccache(context, ccache); + if (ret) return ret; - } - ret = kcm_ccache_destroy(context, ccache->name); - if (ret == 0) { - /* don't leave any events dangling */ - kcm_cleanup_events(context, ccache); - } - - kcm_release_ccache(context, &ccache); - return ret; + return kcm_ccache_destroy(context, name); } krb5_error_code @@ -99,6 +133,7 @@ kcm_ccache_new_client(krb5_context context, { krb5_error_code ret; kcm_ccache ccache; + const char *estr; /* We insist the ccache name starts with UID or UID: */ if (name_constraints != 0) { @@ -121,7 +156,7 @@ kcm_ccache_new_client(krb5_context context, if (bad && !CLIENT_IS_ROOT(client)) return KRB5_CC_BADNAME; } - + ret = kcm_ccache_resolve(context, name, &ccache); if (ret == 0) { if ((ccache->uid != client->uid || @@ -134,20 +169,23 @@ kcm_ccache_new_client(krb5_context context, if (ret == KRB5_FCC_NOFILE) { ret = kcm_ccache_new(context, name, &ccache); if (ret) { - kcm_log(1, "Failed to initialize cache %s: %s", - name, krb5_get_err_text(context, ret)); + estr = krb5_get_error_message(context, ret); + kcm_log(1, "Failed to initialize cache %s: %s", name, estr); + krb5_free_error_message(context, estr); return ret; } /* bind to current client */ ccache->uid = client->uid; ccache->gid = client->gid; + ccache->session = client->session; } else { ret = kcm_zero_ccache_data(context, ccache); if (ret) { - kcm_log(1, "Failed to empty cache %s: %s", - name, krb5_get_err_text(context, ret)); - kcm_release_ccache(context, &ccache); + estr = krb5_get_error_message(context, ret); + kcm_log(1, "Failed to empty cache %s: %s", name, estr); + krb5_free_error_message(context, estr); + kcm_release_ccache(context, ccache); return ret; } kcm_cleanup_events(context, ccache); @@ -155,7 +193,7 @@ kcm_ccache_new_client(krb5_context context, ret = kcm_access(context, client, KCM_OP_INITIALIZE, ccache); if (ret) { - kcm_release_ccache(context, &ccache); + kcm_release_ccache(context, ccache); kcm_ccache_destroy(context, name); return ret; } diff --git a/kcm/config.c b/kcm/config.c index d7c5e1688..217d28d8d 100644 --- a/kcm/config.c +++ b/kcm/config.c @@ -2,6 +2,8 @@ * Copyright (c) 2005, PADL Software Pty Ltd. * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -34,20 +36,18 @@ #include #include -RCSID("$Id$"); +#define MAX_REQUEST_MAX 67108864ll /* 64MB, the maximum accepted value of max_request */ static const char *config_file; /* location of kcm config file */ size_t max_request = 0; /* maximal size of a request */ char *socket_path = NULL; -char *door_path = NULL; static char *max_request_str; /* `max_request' as a string */ -#ifdef SUPPORT_DETACH int detach_from_console = -1; -#define DETACH_IS_DEFAULT FALSE -#endif +int daemon_child = -1; +int automatic_renewal = -1; static const char *system_cache_name = NULL; static const char *system_keytab = NULL; @@ -60,7 +60,8 @@ static const char *system_group = NULL; static const char *renew_life = NULL; static const char *ticket_life = NULL; -int disallow_getting_krbtgt = -1; +int launchd_flag = 0; +int disallow_getting_krbtgt = 0; int name_constraints = -1; static int help_flag; @@ -83,20 +84,23 @@ static struct getargs args[] = { "max-request", 0, arg_string, &max_request, "max size for a kcm-request", "size" }, -#ifdef SUPPORT_DETACH -#if DETACH_IS_DEFAULT { - "detach", 'D', arg_negative_flag, &detach_from_console, - "don't detach from console" + "launchd", 0, arg_flag, &launchd_flag, + "when in use by launchd", NULL }, -#else { "detach", 0 , arg_flag, &detach_from_console, - "detach from console" + "detach from console", NULL }, -#endif -#endif - { "help", 'h', arg_flag, &help_flag }, + { + "daemon-child", 0 , arg_integer, &daemon_child, + "private argument, do not use", NULL + }, + { + "automatic-renewal", 0 , arg_negative_flag, &automatic_renewal, + "disable automatic TGT renewal", NULL + }, + { "help", 'h', arg_flag, &help_flag, NULL, NULL }, { "system-principal", 'k', arg_string, &system_principal, "system principal name", "principal" @@ -111,26 +115,24 @@ static struct getargs args[] = { }, { "name-constraints", 'n', arg_negative_flag, &name_constraints, - "disable credentials cache name constraints" + "disable credentials cache name constraints", NULL }, { "disallow-getting-krbtgt", 0, arg_flag, &disallow_getting_krbtgt, - "disable fetching krbtgt from the cache" + "disable fetching krbtgt from the cache", NULL }, { "renewable-life", 'r', arg_string, &renew_life, "renewable lifetime of system tickets", "time" }, + { + "max-request", 'r', arg_integer, &max_request_str, + "max request size", "bytes" + }, { "socket-path", 's', arg_string, &socket_path, "path to kcm domain socket", "path" }, -#ifdef HAVE_DOOR_CREATE - { - "door-path", 's', arg_string, &door_path, - "path to kcm door", "path" - }, -#endif { "server", 'S', arg_string, &system_server, "server to get system ticket for", "principal" @@ -143,7 +145,7 @@ static struct getargs args[] = { "user", 'u', arg_string, &system_user, "system cache owner", "user" }, - { "version", 'v', arg_flag, &version_flag } + { "version", 'v', arg_flag, &version_flag, NULL, NULL } }; static int num_args = sizeof(args) / sizeof(args[0]); @@ -240,7 +242,7 @@ ccache_init_system(void) ret = krb5_parse_name(kcm_context, system_principal, &ccache->client); if (ret) { - kcm_release_ccache(kcm_context, &ccache); + kcm_release_ccache(kcm_context, ccache); return ret; } @@ -250,7 +252,7 @@ ccache_init_system(void) if (system_server != NULL) { ret = krb5_parse_name(kcm_context, system_server, &ccache->server); if (ret) { - kcm_release_ccache(kcm_context, &ccache); + kcm_release_ccache(kcm_context, ccache); return ret; } } @@ -264,7 +266,7 @@ ccache_init_system(void) ret = krb5_kt_default(kcm_context, &ccache->key.keytab); } if (ret) { - kcm_release_ccache(kcm_context, &ccache); + kcm_release_ccache(kcm_context, ccache); return ret; } @@ -272,12 +274,12 @@ ccache_init_system(void) renew_life = kcm_system_config_get_string("renew_life"); if (renew_life == NULL) - renew_life = "1 month"; + renew_life = "6 months"; if (renew_life != NULL) { ccache->renew_life = parse_time(renew_life, "s"); if (ccache->renew_life < 0) { - kcm_release_ccache(kcm_context, &ccache); + kcm_release_ccache(kcm_context, ccache); return EINVAL; } } @@ -288,7 +290,7 @@ ccache_init_system(void) if (ticket_life != NULL) { ccache->tkt_life = parse_time(ticket_life, "s"); if (ccache->tkt_life < 0) { - kcm_release_ccache(kcm_context, &ccache); + kcm_release_ccache(kcm_context, ccache); return EINVAL; } } @@ -314,7 +316,7 @@ ccache_init_system(void) /* enqueue default actions for credentials cache */ ret = kcm_ccache_enqueue_default(kcm_context, ccache, NULL); - kcm_release_ccache(kcm_context, &ccache); /* retained by event queue */ + kcm_release_ccache(kcm_context, ccache); /* retained by event queue */ return ret; } @@ -323,13 +325,13 @@ void kcm_configure(int argc, char **argv) { krb5_error_code ret; - int optind = 0; + int optidx = 0; const char *p; - while(getarg(args, num_args, argc, argv, &optind)) - warnx("error at argument `%s'", argv[optind]); + while (getarg(args, num_args, argc, argv, &optidx)) + warnx("error at argument `%s'", argv[optidx]); - if(help_flag) + if (help_flag) usage (0); if (version_flag) { @@ -337,8 +339,8 @@ kcm_configure(int argc, char **argv) exit(0); } - argc -= optind; - argv += optind; + argc -= optidx; + argv += optidx; if (argc != 0) usage(1); @@ -352,15 +354,25 @@ kcm_configure(int argc, char **argv) ret = krb5_prepend_config_files_default(config_file, &files); if (ret) krb5_err(kcm_context, 1, ret, "getting configuration files"); - + ret = krb5_set_config_files(kcm_context, files); krb5_free_config_files(files); if(ret) krb5_err(kcm_context, 1, ret, "reading configuration files"); } - if(max_request_str) - max_request = parse_bytes(max_request_str, NULL); + if (max_request_str) { + int64_t bytes; + + if ((bytes = parse_bytes(max_request_str, NULL)) < 0) + krb5_errx(kcm_context, 1, + "--max-request size must be non-negative"); + if (bytes > MAX_REQUEST_MAX) + krb5_errx(kcm_context, 1, "--max-request size is too big " + "(must be smaller than %lld)", MAX_REQUEST_MAX); + + max_request = bytes; + } if(max_request == 0){ p = krb5_config_get_string (kcm_context, @@ -368,8 +380,18 @@ kcm_configure(int argc, char **argv) "kcm", "max-request", NULL); - if(p) - max_request = parse_bytes(p, NULL); + if (p) { + int64_t bytes; + + if ((bytes = parse_bytes(max_request_str, NULL)) < 0) + krb5_errx(kcm_context, 1, + "[kcm] max-request size must be non-negative"); + if (bytes > MAX_REQUEST_MAX) + krb5_errx(kcm_context, 1, "[kcm] max-request size is too big " + "(must be smaller than %lld)", MAX_REQUEST_MAX); + + max_request = bytes; + } } if (system_principal == NULL) { @@ -382,13 +404,18 @@ kcm_configure(int argc, char **argv) krb5_err(kcm_context, 1, ret, "initializing system ccache"); } -#ifdef SUPPORT_DETACH + if(automatic_renewal == -1) + automatic_renewal = krb5_config_get_bool_default(kcm_context, NULL, + TRUE, + "kcm", + "automatic_renewal", + NULL); + if(detach_from_console == -1) detach_from_console = krb5_config_get_bool_default(kcm_context, NULL, - DETACH_IS_DEFAULT, + FALSE, "kcm", "detach", NULL); -#endif kcm_openlog(); if(max_request == 0) max_request = 64 * 1024; diff --git a/kcm/connect.c b/kcm/connect.c index 9c85d8fce..ee09193b3 100644 --- a/kcm/connect.c +++ b/kcm/connect.c @@ -3,6 +3,8 @@ * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -33,656 +35,50 @@ #include "kcm_locl.h" -RCSID("$Id$"); - -struct descr { - int s; - int type; - char *path; - unsigned char *buf; - size_t size; - size_t len; - time_t timeout; - struct sockaddr_storage __ss; - struct sockaddr *sa; - socklen_t sock_len; +void +kcm_service(void *ctx, const heim_idata *req, + const heim_icred cred, + heim_ipc_complete complete, + heim_sipc_call cctx) +{ kcm_client peercred; -}; + krb5_error_code ret; + krb5_data request, rep; + unsigned char *buf; + size_t len; -static void -init_descr(struct descr *d) -{ - memset(d, 0, sizeof(*d)); - d->sa = (struct sockaddr *)&d->__ss; - d->s = -1; -} + krb5_data_zero(&rep); -/* - * re-initialize all `n' ->sa in `d'. - */ + peercred.uid = heim_ipc_cred_get_uid(cred); + peercred.gid = heim_ipc_cred_get_gid(cred); + peercred.pid = heim_ipc_cred_get_pid(cred); + peercred.session = heim_ipc_cred_get_session(cred); -static void -reinit_descrs (struct descr *d, int n) -{ - int i; - - for (i = 0; i < n; ++i) - d[i].sa = (struct sockaddr *)&d[i].__ss; -} - -/* - * Update peer credentials from socket. - * - * SCM_CREDS can only be updated the first time there is read data to - * read from the filedescriptor, so if we read do it before this - * point, the cred data might not be is not there yet. - */ - -static int -update_client_creds(int s, kcm_client *peer) -{ -#ifdef GETPEERUCRED - /* Solaris 10 */ - { - ucred_t *peercred; - - if (getpeerucred(s, &peercred) != 0) { - peer->uid = ucred_geteuid(peercred); - peer->gid = ucred_getegid(peercred); - peer->pid = 0; - ucred_free(peercred); - return 0; - } - } -#endif -#ifdef GETPEEREID - /* FreeBSD, OpenBSD */ - { - uid_t uid; - gid_t gid; - - if (getpeereid(s, &uid, &gid) == 0) { - peer->uid = uid; - peer->gid = gid; - peer->pid = 0; - return 0; - } - } -#endif -#ifdef SO_PEERCRED - /* Linux */ - { - struct ucred pc; - socklen_t pclen = sizeof(pc); - - if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&pc, &pclen) == 0) { - peer->uid = pc.uid; - peer->gid = pc.gid; - peer->pid = pc.pid; - return 0; - } - } -#endif -#if defined(LOCAL_PEERCRED) && defined(XUCRED_VERSION) - { - struct xucred peercred; - socklen_t peercredlen = sizeof(peercred); - - if (getsockopt(s, LOCAL_PEERCRED, 1, - (void *)&peercred, &peercredlen) == 0 - && peercred.cr_version == XUCRED_VERSION) - { - peer->uid = peercred.cr_uid; - peer->gid = peercred.cr_gid; - peer->pid = 0; - return 0; - } - } -#endif -#if defined(SOCKCREDSIZE) && defined(SCM_CREDS) - /* NetBSD */ - if (peer->uid == -1) { - struct msghdr msg; - socklen_t crmsgsize; - void *crmsg; - struct cmsghdr *cmp; - struct sockcred *sc; - - memset(&msg, 0, sizeof(msg)); - crmsgsize = CMSG_SPACE(SOCKCREDSIZE(NGROUPS)); - if (crmsgsize == 0) - return 1 ; - - crmsg = malloc(crmsgsize); - if (crmsg == NULL) - goto failed_scm_creds; - - memset(crmsg, 0, crmsgsize); - - msg.msg_control = crmsg; - msg.msg_controllen = crmsgsize; - - if (recvmsg(s, &msg, 0) < 0) { - free(crmsg); - goto failed_scm_creds; - } - - if (msg.msg_controllen == 0 || (msg.msg_flags & MSG_CTRUNC) != 0) { - free(crmsg); - goto failed_scm_creds; - } - - cmp = CMSG_FIRSTHDR(&msg); - if (cmp->cmsg_level != SOL_SOCKET || cmp->cmsg_type != SCM_CREDS) { - free(crmsg); - goto failed_scm_creds; - } - - sc = (struct sockcred *)(void *)CMSG_DATA(cmp); - - peer->uid = sc->sc_euid; - peer->gid = sc->sc_egid; - peer->pid = 0; - - free(crmsg); - return 0; - } else { - /* we already got the cred, just return it */ - return 0; - } - failed_scm_creds: -#endif - krb5_warn(kcm_context, errno, "failed to determine peer identity"); - return 1; -} - - -/* - * Create the socket (family, type, port) in `d' - */ - -static void -init_socket(struct descr *d) -{ - struct sockaddr_un un; - struct sockaddr *sa = (struct sockaddr *)&un; - krb5_socklen_t sa_size = sizeof(un); - - init_descr (d); - - un.sun_family = AF_UNIX; - - if (socket_path != NULL) - d->path = socket_path; - else - d->path = _PATH_KCM_SOCKET; - - strlcpy(un.sun_path, d->path, sizeof(un.sun_path)); - - d->s = socket(AF_UNIX, SOCK_STREAM, 0); - if (d->s < 0){ - krb5_warn(kcm_context, errno, "socket(%d, %d, 0)", AF_UNIX, SOCK_STREAM); - d->s = -1; - return; - } -#if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_REUSEADDR) - { - int one = 1; - setsockopt(d->s, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)); - } -#endif -#ifdef LOCAL_CREDS - { - int one = 1; - setsockopt(d->s, 0, LOCAL_CREDS, (void *)&one, sizeof(one)); - } -#endif - - d->type = SOCK_STREAM; - - unlink(d->path); - - if (bind(d->s, sa, sa_size) < 0) { - krb5_warn(kcm_context, errno, "bind %s", un.sun_path); - close(d->s); - d->s = -1; - return; - } - - if (listen(d->s, SOMAXCONN) < 0) { - krb5_warn(kcm_context, errno, "listen %s", un.sun_path); - close(d->s); - d->s = -1; - return; - } - - chmod(d->path, 0777); - - return; -} - -/* - * Allocate descriptors for all the sockets that we should listen on - * and return the number of them. - */ - -static int -init_sockets(struct descr **desc) -{ - struct descr *d; - size_t num = 0; - - d = (struct descr *)malloc(sizeof(*d)); - if (d == NULL) { - krb5_errx(kcm_context, 1, "malloc failed"); - } - - init_socket(d); - if (d->s != -1) { - kcm_log(5, "listening on domain socket %s", d->path); - num++; - } - - reinit_descrs (d, num); - *desc = d; - - return num; -} - -/* - * handle the request in `buf, len', from `addr' (or `from' as a string), - * sending a reply in `reply'. - */ - -static int -process_request(unsigned char *buf, - size_t len, - krb5_data *reply, - kcm_client *client) -{ - krb5_data request; - - if (len < 4) { + if (req->length < 4) { kcm_log(1, "malformed request from process %d (too short)", - client->pid); - return -1; + peercred.pid); + (*complete)(cctx, EINVAL, NULL); + return; } + buf = req->data; + len = req->length; + if (buf[0] != KCM_PROTOCOL_VERSION_MAJOR || buf[1] != KCM_PROTOCOL_VERSION_MINOR) { kcm_log(1, "incorrect protocol version %d.%d from process %d", - buf[0], buf[1], client->pid); - return -1; + buf[0], buf[1], peercred.pid); + (*complete)(cctx, EINVAL, NULL); + return; } - buf += 2; - len -= 2; + request.data = buf + 2; + request.length = len - 2; /* buf is now pointing at opcode */ - request.data = buf; - request.length = len; + ret = kcm_dispatch(kcm_context, &peercred, &request, &rep); - return kcm_dispatch(kcm_context, client, &request, reply); + (*complete)(cctx, ret, &rep); + krb5_data_free(&rep); } - -/* - * Handle the request in `buf, len' to socket `d' - */ - -static void -do_request(void *buf, size_t len, struct descr *d) -{ - krb5_error_code ret; - krb5_data reply; - - reply.length = 0; - - ret = process_request(buf, len, &reply, &d->peercred); - if (reply.length != 0) { - unsigned char len[4]; - struct msghdr msghdr; - struct iovec iov[2]; - - kcm_log(5, "sending %lu bytes to process %d", - (unsigned long)reply.length, - (int)d->peercred.pid); - - memset (&msghdr, 0, sizeof(msghdr)); - msghdr.msg_name = NULL; - msghdr.msg_namelen = 0; - msghdr.msg_iov = iov; - msghdr.msg_iovlen = sizeof(iov)/sizeof(*iov); -#if 0 - msghdr.msg_control = NULL; - msghdr.msg_controllen = 0; -#endif - - len[0] = (reply.length >> 24) & 0xff; - len[1] = (reply.length >> 16) & 0xff; - len[2] = (reply.length >> 8) & 0xff; - len[3] = reply.length & 0xff; - - iov[0].iov_base = (void*)len; - iov[0].iov_len = 4; - iov[1].iov_base = reply.data; - iov[1].iov_len = reply.length; - - if (sendmsg (d->s, &msghdr, 0) < 0) { - kcm_log (0, "sendmsg(%d): %d %s", (int)d->peercred.pid, - errno, strerror(errno)); - krb5_data_free(&reply); - return; - } - - krb5_data_free(&reply); - } - - if (ret) { - kcm_log(0, "Failed processing %lu byte request from process %d", - (unsigned long)len, d->peercred.pid); - } -} - -static void -clear_descr(struct descr *d) -{ - if(d->buf) - memset(d->buf, 0, d->size); - d->len = 0; - if(d->s != -1) - close(d->s); - d->s = -1; -} - -#define STREAM_TIMEOUT 4 - -/* - * accept a new stream connection on `d[parent]' and store it in `d[child]' - */ - -static void -add_new_stream (struct descr *d, int parent, int child) -{ - int s; - - if (child == -1) - return; - - d[child].peercred.pid = -1; - d[child].peercred.uid = -1; - d[child].peercred.gid = -1; - - d[child].sock_len = sizeof(d[child].__ss); - s = accept(d[parent].s, d[child].sa, &d[child].sock_len); - if(s < 0) { - krb5_warn(kcm_context, errno, "accept"); - return; - } - - if (s >= FD_SETSIZE) { - krb5_warnx(kcm_context, "socket FD too large"); - close (s); - return; - } - - d[child].s = s; - d[child].timeout = time(NULL) + STREAM_TIMEOUT; - d[child].type = SOCK_STREAM; -} - -/* - * Grow `d' to handle at least `n'. - * Return != 0 if fails - */ - -static int -grow_descr (struct descr *d, size_t n) -{ - if (d->size - d->len < n) { - unsigned char *tmp; - size_t grow; - - grow = max(1024, d->len + n); - if (d->size + grow > max_request) { - kcm_log(0, "Request exceeds max request size (%lu bytes).", - (unsigned long)d->size + grow); - clear_descr(d); - return -1; - } - tmp = realloc (d->buf, d->size + grow); - if (tmp == NULL) { - kcm_log(0, "Failed to re-allocate %lu bytes.", - (unsigned long)d->size + grow); - clear_descr(d); - return -1; - } - d->size += grow; - d->buf = tmp; - } - return 0; -} - -/* - * Handle incoming data to the stream socket in `d[index]' - */ - -static void -handle_stream(struct descr *d, int index, int min_free) -{ - unsigned char buf[1024]; - int n; - int ret = 0; - - if (d[index].timeout == 0) { - add_new_stream (d, index, min_free); - return; - } - - if (update_client_creds(d[index].s, &d[index].peercred)) { - krb5_warnx(kcm_context, "failed to update peer identity"); - clear_descr(d + index); - return; - } - - if (d[index].peercred.uid == -1) { - krb5_warnx(kcm_context, "failed to determine peer identity"); - clear_descr (d + index); - return; - } - - n = recvfrom(d[index].s, buf, sizeof(buf), 0, NULL, NULL); - if (n < 0) { - krb5_warn(kcm_context, errno, "recvfrom"); - return; - } else if (n == 0) { - krb5_warnx(kcm_context, "connection closed before end of data " - "after %lu bytes from process %ld", - (unsigned long) d[index].len, (long) d[index].peercred.pid); - clear_descr (d + index); - return; - } - if (grow_descr (&d[index], n)) - return; - memcpy(d[index].buf + d[index].len, buf, n); - d[index].len += n; - if (d[index].len > 4) { - krb5_storage *sp; - int32_t len; - - sp = krb5_storage_from_mem(d[index].buf, d[index].len); - if (sp == NULL) { - kcm_log (0, "krb5_storage_from_mem failed"); - ret = -1; - } else { - krb5_ret_int32(sp, &len); - krb5_storage_free(sp); - if (d[index].len - 4 >= len) { - memmove(d[index].buf, d[index].buf + 4, d[index].len - 4); - ret = 1; - } else - ret = 0; - } - } - if (ret < 0) - return; - else if (ret == 1) { - do_request(d[index].buf, d[index].len, &d[index]); - clear_descr(d + index); - } -} - -#ifdef HAVE_DOOR_CREATE - -static void -kcm_door_server(void *cookie, char *argp, size_t arg_size, - door_desc_t *dp, uint_t n_desc) -{ - kcm_client peercred; - door_cred_t cred; - krb5_error_code ret; - krb5_data reply; - size_t length; - char *p; - - reply.length = 0; - - p = NULL; - length = 0; - - if (door_cred(&cred) != 0) { - kcm_log(0, "door_cred failed with %s", strerror(errno)); - goto out; - } - - peercred.uid = cred.dc_euid; - peercred.gid = cred.dc_egid; - peercred.pid = cred.dc_pid; - - ret = process_request((unsigned char*)argp, arg_size, &reply, &peercred); - if (reply.length != 0) { - p = alloca(reply.length); /* XXX don't use alloca */ - if (p) { - memcpy(p, reply.data, reply.length); - length = reply.length; - } - krb5_data_free(&reply); - } - - out: - door_return(p, length, NULL, 0); -} - -static void -kcm_setup_door(void) -{ - int fd, ret; - char *path; - - fd = door_create(kcm_door_server, NULL, 0); - if (fd < 0) - krb5_err(kcm_context, 1, errno, "Failed to create door"); - - if (door_path != NULL) - path = door_path; - else - path = _PATH_KCM_DOOR; - - unlink(path); - ret = open(path, O_RDWR | O_CREAT, 0666); - if (ret < 0) - krb5_err(kcm_context, 1, errno, "Failed to create/open door"); - close(ret); - - ret = fattach(fd, path); - if (ret < 0) - krb5_err(kcm_context, 1, errno, "Failed to attach door"); - -} -#endif /* HAVE_DOOR_CREATE */ - - -void -kcm_loop(void) -{ - struct descr *d; - unsigned int ndescr; - -#ifdef HAVE_DOOR_CREATE - kcm_setup_door(); -#endif - - ndescr = init_sockets(&d); - if (ndescr <= 0) { - krb5_warnx(kcm_context, "No sockets!"); -#ifndef HAVE_DOOR_CREATE - exit(1); -#endif - } - while (exit_flag == 0){ - struct timeval tmout; - fd_set fds; - int min_free = -1; - int max_fd = 0; - int i; - - FD_ZERO(&fds); - for(i = 0; i < ndescr; i++) { - if (d[i].s >= 0){ - if(d[i].type == SOCK_STREAM && - d[i].timeout && d[i].timeout < time(NULL)) { - kcm_log(1, "Stream connection from %d expired after %lu bytes", - d[i].peercred.pid, (unsigned long)d[i].len); - clear_descr(&d[i]); - continue; - } - if (max_fd < d[i].s) - max_fd = d[i].s; - if (max_fd >= FD_SETSIZE) - krb5_errx(kcm_context, 1, "fd too large"); - FD_SET(d[i].s, &fds); - } else if (min_free < 0 || i < min_free) - min_free = i; - } - if (min_free == -1) { - struct descr *tmp; - tmp = realloc(d, (ndescr + 4) * sizeof(*d)); - if(tmp == NULL) - krb5_warnx(kcm_context, "No memory"); - else { - d = tmp; - reinit_descrs (d, ndescr); - memset(d + ndescr, 0, 4 * sizeof(*d)); - for(i = ndescr; i < ndescr + 4; i++) - init_descr (&d[i]); - min_free = ndescr; - ndescr += 4; - } - } - - tmout.tv_sec = STREAM_TIMEOUT; - tmout.tv_usec = 0; - switch (select(max_fd + 1, &fds, 0, 0, &tmout)){ - case 0: - kcm_run_events(kcm_context, time(NULL)); - break; - case -1: - if (errno != EINTR) - krb5_warn(kcm_context, errno, "select"); - break; - default: - for(i = 0; i < ndescr; i++) { - if(d[i].s >= 0 && FD_ISSET(d[i].s, &fds)) { - if (d[i].type == SOCK_STREAM) - handle_stream(d, i, min_free); - } - } - kcm_run_events(kcm_context, time(NULL)); - break; - } - } - if (d->path != NULL) - unlink(d->path); - free(d); -} - diff --git a/kcm/events.c b/kcm/events.c index da4c220aa..8b78c10f0 100644 --- a/kcm/events.c +++ b/kcm/events.c @@ -61,10 +61,10 @@ kcm_enqueue_event(krb5_context context, } static void -print_times(time_t time, char buf[64]) +print_times(time_t t, char buf[64]) { - if (time) - strftime(buf, 64, "%m-%dT%H:%M", gmtime(&time)); + if (t) + strftime(buf, 64, "%m-%dT%H:%M", gmtime(&t)); else strlcpy(buf, "never", 64); } @@ -161,7 +161,7 @@ kcm_remove_event_internal(krb5_context context, (*e)->fire_count = 0; (*e)->expire_time = 0; (*e)->backoff_time = 0; - kcm_release_ccache(context, &(*e)->ccache); + kcm_release_ccache(context, (*e)->ccache); (*e)->next = NULL; free(*e); @@ -220,7 +220,7 @@ kcm_ccache_make_default_event(krb5_context context, event->fire_time = time(NULL); /* right away */ event->action = KCM_EVENT_ACQUIRE_CREDS; } else if (is_primary_credential_p(context, ccache, newcred)) { - if (newcred->flags.b.renewable) { + if (automatic_renewal && newcred->flags.b.renewable) { event->action = KCM_EVENT_RENEW_CREDS; ccache->flags |= KCM_FLAGS_RENEWABLE; } else { @@ -398,6 +398,7 @@ kcm_run_events(krb5_context context, time_t now) { krb5_error_code ret; kcm_event **e; + const char *estr; HEIMDAL_MUTEX_lock(&events_mutex); @@ -415,14 +416,18 @@ kcm_run_events(krb5_context context, time_t now) if (now >= (*e)->fire_time) { ret = kcm_fire_event(context, e); if (ret) { + estr = krb5_get_error_message(context, ret); kcm_log(1, "Could not fire event for cache %s: %s", - (*e)->ccache->name, krb5_get_err_text(context, ret)); + (*e)->ccache->name, estr); + krb5_free_error_message(context, estr); } } else if ((*e)->expire_time && now >= (*e)->expire_time) { ret = kcm_remove_event_internal(context, e); if (ret) { + estr = krb5_get_error_message(context, ret); kcm_log(1, "Could not expire event for cache %s: %s", - (*e)->ccache->name, krb5_get_err_text(context, ret)); + (*e)->ccache->name, estr); + krb5_free_error_message(context, estr); } } diff --git a/kcm/glue.c b/kcm/glue.c index 8b0d17226..0895f48f0 100644 --- a/kcm/glue.c +++ b/kcm/glue.c @@ -44,15 +44,27 @@ RCSID("$Id$"); #define KCMCACHE(X) ((kcm_ccache)(X)->data.data) #define CACHENAME(X) (KCMCACHE(X)->name) -static const char * -kcmss_get_name(krb5_context context, - krb5_ccache id) +static krb5_error_code +kcmss_get_name_2(krb5_context context, + krb5_ccache id, + const char **name, + const char **col, + const char **sub) { - return CACHENAME(id); + if (name) + *name = CACHENAME(id); + if (col) + *col = NULL; + if (sub) + *sub = CACHENAME(id); + return 0; } static krb5_error_code -kcmss_resolve(krb5_context context, krb5_ccache *id, const char *res) +kcmss_resolve_2(krb5_context context, + krb5_ccache *id, + const char *res, + const char *sub) { return KRB5_FCC_INTERNAL; } @@ -247,10 +259,10 @@ kcmss_get_version(krb5_context context, } static const krb5_cc_ops krb5_kcmss_ops = { - KRB5_CC_OPS_VERSION, + KRB5_CC_OPS_VERSION_5, "KCM", - kcmss_get_name, - kcmss_resolve, + NULL, + NULL, kcmss_gen_new, kcmss_initialize, kcmss_destroy, @@ -263,7 +275,18 @@ static const krb5_cc_ops krb5_kcmss_ops = { kcmss_end_get, kcmss_remove_cred, kcmss_set_flags, - kcmss_get_version + kcmss_get_version, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + kcmss_get_name_2, + kcmss_resolve_2, }; krb5_error_code diff --git a/kcm/headers.h b/kcm/headers.h index 714e02397..603a6b811 100644 --- a/kcm/headers.h +++ b/kcm/headers.h @@ -33,9 +33,9 @@ #ifndef __HEADERS_H__ #define __HEADERS_H__ -#ifdef HAVE_CONFIG_H + #include -#endif + #include #include #include @@ -70,22 +70,21 @@ #ifdef HAVE_LIBUTIL_H #include #endif -#ifdef HAVE_GETPEERUCRED -#include -#endif -#ifdef HAVE_DOOR_CREATE -#include -#include -#endif +#include #include #include #include #include #include +#include #include -#include +#include + +#include + +#include "crypto-headers.h" #endif /* __HEADERS_H__ */ diff --git a/kcm/kcm.8 b/kcm/kcm.8 index 71a1e618c..744ab0f1d 100644 --- a/kcm/kcm.8 +++ b/kcm/kcm.8 @@ -1,102 +1,97 @@ .\" Copyright (c) 2005 Kungliga Tekniska Högskolan -.\" (Royal Institute of Technology, Stockholm, Sweden). -.\" All rights reserved. +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. .\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: .\" -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. .\" -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. .\" -.\" 3. Neither the name of the Institute nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. .\" -.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. .\" .\" $Id$ .\" .Dd May 29, 2005 .Dt KCM 8 -.Os Heimdal +.Os .Sh NAME .Nm kcm -.Nd -is a process based credential cache for Kerberos tickets. +.Nd process-based credential cache for Kerberos tickets. .Sh SYNOPSIS .Nm -.Op Fl -cache-name= Ns Ar cachename +.Op Fl Fl cache-name= Ns Ar cachename .Oo Fl c Ar file \*(Ba Xo -.Fl -config-file= Ns Ar file +.Fl Fl config-file= Ns Ar file .Xc .Oc .Oo Fl g Ar group \*(Ba Xo -.Fl -group= Ns Ar group +.Fl Fl group= Ns Ar group .Xc .Oc -.Op Fl -max-request= Ns Ar size -.Op Fl -disallow-getting-krbtgt -.Op Fl -detach -.Op Fl h | Fl -help +.Op Fl Fl max-request= Ns Ar size +.Op Fl Fl disallow-getting-krbtgt +.Op Fl Fl detach +.Op Fl h | Fl Fl help .Oo Fl k Ar principal \*(Ba Xo -.Fl -system-principal= Ns Ar principal +.Fl Fl system-principal= Ns Ar principal .Xc .Oc .Oo Fl l Ar time \*(Ba Xo -.Fl -lifetime= Ns Ar time +.Fl Fl lifetime= Ns Ar time .Xc .Oc .Oo Fl m Ar mode \*(Ba Xo -.Fl -mode= Ns Ar mode +.Fl Fl mode= Ns Ar mode .Xc .Oc -.Op Fl n | Fl -no-name-constraints +.Op Fl n | Fl Fl no-name-constraints .Oo Fl r Ar time \*(Ba Xo -.Fl -renewable-life= Ns Ar time +.Fl Fl renewable-life= Ns Ar time .Xc .Oc .Oo Fl s Ar path \*(Ba Xo -.Fl -socket-path= Ns Ar path -.Xc -.Oc -.Oo Xo -.Fl -door-path= Ns Ar path +.Fl Fl socket-path= Ns Ar path .Xc .Oc .Oo Fl S Ar principal \*(Ba Xo -.Fl -server= Ns Ar principal +.Fl Fl server= Ns Ar principal .Xc .Oc .Oo Fl t Ar keytab \*(Ba Xo -.Fl -keytab= Ns Ar keytab +.Fl Fl keytab= Ns Ar keytab .Xc .Oc .Oo Fl u Ar user \*(Ba Xo -.Fl -user= Ns Ar user +.Fl Fl user= Ns Ar user .Xc .Oc -.Op Fl v | Fl -version +.Op Fl v | Fl Fl version .Sh DESCRIPTION .Nm is a process based credential cache. To use it, set the .Ev KRB5CCNAME -enviroment variable to +environment variable to .Ql KCM: Ns Ar uid or add the stanza .Bd -literal @@ -123,95 +118,44 @@ The daemon can also keep a SYSTEM credential that server processes can use to access services. One example of usage might be an nss_ldap module that quickly needs to get credentials and doesn't want to renew -the ticket itself. +the ticket itself. .Pp Supported options: .Bl -tag -width Ds -.It Xo -.Fl -cache-name= Ns Ar cachename -.Xc +.It Fl Fl cache-name= Ns Ar cachename system cache name -.It Xo -.Fl c Ar file , -.Fl -config-file= Ns Ar file -.Xc +.It Fl c Ar file , Fl Fl config-file= Ns Ar file location of config file -.It Xo -.Fl g Ar group , -.Fl -group= Ns Ar group -.Xc +.It Fl g Ar group , Fl Fl group= Ns Ar group system cache group -.It Xo -.Fl -max-request= Ns Ar size -.Xc +.It Fl Fl max-request= Ns Ar size max size for a kcm-request -.It Xo -.Fl -disallow-getting-krbtgt -.Xc +.It Fl Fl disallow-getting-krbtgt disallow extracting any krbtgt from the .Nm kcm daemon. -.It Xo -.Fl -detach -.Xc +.It Fl Fl detach detach from console -.It Xo -.Fl h , -.Fl -help -.Xc -.It Xo -.Fl k Ar principal , -.Fl -system-principal= Ns Ar principal -.Xc +.It Fl h , Fl Fl help +.It Fl k Ar principal , Fl Fl system-principal= Ns Ar principal system principal name -.It Xo -.Fl l Ar time , -.Fl -lifetime= Ns Ar time -.Xc +.It Fl l Ar time , Fl Fl lifetime= Ns Ar time lifetime of system tickets -.It Xo -.Fl m Ar mode , -.Fl -mode= Ns Ar mode -.Xc +.It Fl m Ar mode , Fl Fl mode= Ns Ar mode octal mode of system cache -.It Xo -.Fl n , -.Fl -no-name-constraints -.Xc +.It Fl n , Fl Fl no-name-constraints disable credentials cache name constraints -.It Xo -.Fl r Ar time , -.Fl -renewable-life= Ns Ar time -.Xc +.It Fl r Ar time , Fl Fl renewable-life= Ns Ar time renewable lifetime of system tickets -.It Xo -.Fl s Ar path , -.Fl -socket-path= Ns Ar path -.Xc +.It Fl s Ar path , Fl Fl socket-path= Ns Ar path path to kcm domain socket -.It Xo -.Fl -door-path= Ns Ar path -.Xc -path to kcm door socket -.It Xo -.Fl S Ar principal , -.Fl -server= Ns Ar principal -.Xc +.It Fl S Ar principal , Fl Fl server= Ns Ar principal server to get system ticket for -.It Xo -.Fl t Ar keytab , -.Fl -keytab= Ns Ar keytab -.Xc +.It Fl t Ar keytab , Fl Fl keytab= Ns Ar keytab system keytab name -.It Xo -.Fl u Ar user , -.Fl -user= Ns Ar user -.Xc +.It Fl u Ar user , Fl Fl user= Ns Ar user system cache owner -.It Xo -.Fl v , -.Fl -version -.Xc +.It Fl v , Fl Fl version .El .\".Sh ENVIRONMENT .\".Sh FILES diff --git a/kcm/kcm_locl.h b/kcm/kcm_locl.h index 41f82e454..dc0110448 100644 --- a/kcm/kcm_locl.h +++ b/kcm/kcm_locl.h @@ -2,6 +2,8 @@ * Copyright (c) 2005, PADL Software Pty Ltd. * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -65,6 +67,15 @@ struct kcm_ccache_data; struct kcm_creds; +struct kcm_default_cache { + uid_t uid; + pid_t session; /* really au_asid_t */ + char *name; + struct kcm_default_cache *next; +}; + +extern struct kcm_default_cache *default_caches; + struct kcm_creds { kcmuuid_t uuid; krb5_creds cred; @@ -73,16 +84,19 @@ struct kcm_creds { typedef struct kcm_ccache_data { char *name; + kcmuuid_t uuid; unsigned refcnt; uint16_t flags; uint16_t mode; uid_t uid; gid_t gid; + pid_t session; /* really au_asid_t */ krb5_principal client; /* primary client principal */ krb5_principal server; /* primary server principal (TGS if NULL) */ struct kcm_creds *creds; krb5_deltat tkt_life; krb5_deltat renew_life; + int32_t kdc_offset; union { krb5_keytab keytab; krb5_keyblock keyblock; @@ -132,6 +146,7 @@ typedef struct kcm_client { pid_t pid; uid_t uid; gid_t gid; + pid_t session; } kcm_client; #define CLIENT_IS_ROOT(client) ((client)->uid == 0) @@ -149,20 +164,22 @@ struct kcm_op { #define _PATH_KCM_CONF SYSCONFDIR "/kcm.conf" extern krb5_context kcm_context; -extern char *socket_path; -extern char *door_path; extern size_t max_request; extern sig_atomic_t exit_flag; extern int name_constraints; -#ifdef SUPPORT_DETACH extern int detach_from_console; -#endif +extern int daemon_child; +extern int automatic_renewal; +extern int launchd_flag; extern int disallow_getting_krbtgt; #if 0 extern const krb5_cc_ops krb5_kcmss_ops; #endif +void kcm_service(void *, const heim_idata *, const heim_icred, + heim_ipc_complete, heim_sipc_call); + #include #endif /* __KCM_LOCL_H__ */ diff --git a/kcm/log.c b/kcm/log.c index 34f1bbf79..c77d1ffe0 100644 --- a/kcm/log.c +++ b/kcm/log.c @@ -35,30 +35,30 @@ RCSID("$Id$"); -static krb5_log_facility *logf; +static krb5_log_facility *logfac; void kcm_openlog(void) { char **s = NULL, **p; - krb5_initlog(kcm_context, "kcm", &logf); + krb5_initlog(kcm_context, "kcm", &logfac); s = krb5_config_get_strings(kcm_context, NULL, "kcm", "logging", NULL); if(s == NULL) s = krb5_config_get_strings(kcm_context, NULL, "logging", "kcm", NULL); if(s){ for(p = s; *p; p++) - krb5_addlog_dest(kcm_context, logf, *p); + krb5_addlog_dest(kcm_context, logfac, *p); krb5_config_free_strings(s); }else - krb5_addlog_dest(kcm_context, logf, DEFAULT_LOG_DEST); - krb5_set_warn_dest(kcm_context, logf); + krb5_addlog_dest(kcm_context, logfac, DEFAULT_LOG_DEST); + krb5_set_warn_dest(kcm_context, logfac); } char* kcm_log_msg_va(int level, const char *fmt, va_list ap) { char *msg; - krb5_vlog_msg(kcm_context, logf, &msg, level, fmt, ap); + krb5_vlog_msg(kcm_context, logfac, &msg, level, fmt, ap); return msg; } diff --git a/kcm/main.c b/kcm/main.c index c8ba0193c..155983ac1 100644 --- a/kcm/main.c +++ b/kcm/main.c @@ -35,15 +35,10 @@ RCSID("$Id$"); -sig_atomic_t exit_flag = 0; - krb5_context kcm_context = NULL; +extern const char *socket_path; -static RETSIGTYPE -sigterm(int sig) -{ - exit_flag = 1; -} +const char *service_name = "org.h5l.kcm"; static RETSIGTYPE sigusr1(int sig) @@ -76,13 +71,9 @@ main(int argc, char **argv) struct sigaction sa; sa.sa_flags = 0; - sa.sa_handler = sigterm; + sa.sa_handler = sigusr1; sigemptyset(&sa.sa_mask); - sigaction(SIGINT, &sa, NULL); - sigaction(SIGTERM, &sa, NULL); - - sa.sa_handler = sigusr1; sigaction(SIGUSR1, &sa, NULL); sa.sa_handler = sigusr2; @@ -92,18 +83,41 @@ main(int argc, char **argv) sigaction(SIGPIPE, &sa, NULL); } #else - signal(SIGINT, sigterm); - signal(SIGTERM, sigterm); signal(SIGUSR1, sigusr1); signal(SIGUSR2, sigusr2); signal(SIGPIPE, SIG_IGN); #endif -#ifdef SUPPORT_DETACH - if (detach_from_console) - daemon(0, 0); + if (detach_from_console && !launchd_flag && daemon_child == -1) + daemon_child = roken_detach_prep(argc, argv, "--daemon-child"); + rk_pidfile(NULL); + + if (socket_path) + setenv("HEIM_IPC_DIR", socket_path, 1); + + if (launchd_flag) { + heim_sipc mach; + ret = heim_sipc_launchd_mach_init(service_name, kcm_service, NULL, &mach); + if (ret) + krb5_err(kcm_context, 1, ret, "Could not setup launchd service"); + } else { + heim_sipc un; + ret = heim_sipc_service_unix(service_name, kcm_service, NULL, &un); + if (ret) + krb5_err(kcm_context, 1, ret, "Could not setup Unix domain socket service"); + } +#ifdef HAVE_DOOR_CREATE + { + heim_sipc door; + ret = heim_sipc_service_door(service_name, kcm_service, NULL, &door); + if (ret) + krb5_err(kcm_context, 1, ret, "Could not setup door service"); + } #endif - pidfile(NULL); - kcm_loop(); + + roken_detach_finish(NULL, daemon_child); + + heim_ipc_main(); + krb5_free_context(kcm_context); return 0; } diff --git a/kcm/protocol.c b/kcm/protocol.c index 362700767..31f17623d 100644 --- a/kcm/protocol.c +++ b/kcm/protocol.c @@ -2,6 +2,8 @@ * Copyright (c) 2005, PADL Software Pty Ltd. * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -31,8 +33,22 @@ */ #include "kcm_locl.h" +#include -RCSID("$Id$"); +static void +kcm_drop_default_cache(krb5_context context, kcm_client *client, char *name); + + +int +kcm_is_same_session(kcm_client *client, uid_t uid, pid_t session) +{ +#if 0 /* XXX pppd is running in diffrent session the user */ + if (session != -1) + return (client->session == session); + else +#endif + return (client->uid == uid); +} static krb5_error_code kcm_op_noop(krb5_context context, @@ -43,7 +59,7 @@ kcm_op_noop(krb5_context context, { KCM_LOG_REQUEST(context, client, opcode); - return 0; + return 0; } /* @@ -80,19 +96,19 @@ kcm_op_get_name(krb5_context context, ret = krb5_store_stringz(response, ccache->name); if (ret) { - kcm_release_ccache(context, &ccache); + kcm_release_ccache(context, ccache); free(name); return ret; } free(name); - kcm_release_ccache(context, &ccache); + kcm_release_ccache(context, ccache); return 0; } /* * Request: - * + * * Response: * NameZ */ @@ -123,9 +139,9 @@ kcm_op_gen_new(krb5_context context, * Request: * NameZ * Principal - * + * * Response: - * + * */ static krb5_error_code kcm_op_initialize(krb5_context context, @@ -181,7 +197,7 @@ kcm_op_initialize(krb5_context context, ret = kcm_enqueue_event_relative(context, &event); #endif - kcm_release_ccache(context, &ccache); + kcm_release_ccache(context, ccache); return ret; } @@ -189,9 +205,9 @@ kcm_op_initialize(krb5_context context, /* * Request: * NameZ - * + * * Response: - * + * */ static krb5_error_code kcm_op_destroy(krb5_context context, @@ -210,6 +226,8 @@ kcm_op_destroy(krb5_context context, KCM_LOG_REQUEST_NAME(context, client, opcode, name); ret = kcm_ccache_destroy_client(context, client, name); + if (ret == 0) + kcm_drop_default_cache(context, client, name); free(name); @@ -220,9 +238,9 @@ kcm_op_destroy(krb5_context context, * Request: * NameZ * Creds - * + * * Response: - * + * */ static krb5_error_code kcm_op_store(krb5_context context, @@ -260,14 +278,14 @@ kcm_op_store(krb5_context context, if (ret) { free(name); krb5_free_cred_contents(context, &creds); - kcm_release_ccache(context, &ccache); + kcm_release_ccache(context, ccache); return ret; } kcm_ccache_enqueue_default(context, ccache, &creds); free(name); - kcm_release_ccache(context, &ccache); + kcm_release_ccache(context, ccache); return 0; } @@ -280,7 +298,7 @@ kcm_op_store(krb5_context context, * * Response: * Creds - * + * */ static krb5_error_code kcm_op_retrieve(krb5_context context, @@ -334,7 +352,8 @@ kcm_op_retrieve(krb5_context context, ret = kcm_ccache_retrieve_cred(context, ccache, flags, &mcreds, &credp); - if (ret && ((flags & KRB5_GC_CACHED) == 0)) { + if (ret && ((flags & KRB5_GC_CACHED) == 0) && + !krb5_is_config_principal(context, mcreds.server)) { krb5_ccache_data ccdata; /* try and acquire */ @@ -357,7 +376,7 @@ kcm_op_retrieve(krb5_context context, free(name); krb5_free_cred_contents(context, &mcreds); - kcm_release_ccache(context, &ccache); + kcm_release_ccache(context, ccache); if (free_creds) krb5_free_cred_contents(context, credp); @@ -402,9 +421,9 @@ kcm_op_get_principal(krb5_context context, ret = krb5_store_principal(response, ccache->client); free(name); - kcm_release_ccache(context, &ccache); + kcm_release_ccache(context, ccache); - return 0; + return ret; } /* @@ -412,15 +431,15 @@ kcm_op_get_principal(krb5_context context, * NameZ * * Response: - * Cursor - * + * UUIDs + * */ static krb5_error_code -kcm_op_get_first(krb5_context context, - kcm_client *client, - kcm_operation opcode, - krb5_storage *request, - krb5_storage *response) +kcm_op_get_cred_uuid_list(krb5_context context, + kcm_client *client, + kcm_operation opcode, + krb5_storage *request, + krb5_storage *response) { struct kcm_creds *creds; krb5_error_code ret; @@ -448,7 +467,7 @@ kcm_op_get_first(krb5_context context, } } - kcm_release_ccache(context, &ccache); + kcm_release_ccache(context, ccache); return ret; } @@ -462,11 +481,11 @@ kcm_op_get_first(krb5_context context, * Creds */ static krb5_error_code -kcm_op_get_next(krb5_context context, - kcm_client *client, - kcm_operation opcode, - krb5_storage *request, - krb5_storage *response) +kcm_op_get_cred_by_uuid(krb5_context context, + kcm_client *client, + kcm_operation opcode, + krb5_storage *request, + krb5_storage *response) { krb5_error_code ret; kcm_ccache ccache; @@ -489,14 +508,14 @@ kcm_op_get_next(krb5_context context, sret = krb5_storage_read(request, &uuid, sizeof(uuid)); if (sret != sizeof(uuid)) { - kcm_release_ccache(context, &ccache); + kcm_release_ccache(context, ccache); krb5_clear_error_message(context); return KRB5_CC_IO; } c = kcm_ccache_find_cred_uuid(context, ccache, uuid); if (c == NULL) { - kcm_release_ccache(context, &ccache); + kcm_release_ccache(context, ccache); return KRB5_CC_END; } @@ -504,35 +523,7 @@ kcm_op_get_next(krb5_context context, ret = krb5_store_creds(response, &c->cred); HEIMDAL_MUTEX_unlock(&ccache->mutex); - kcm_release_ccache(context, &ccache); - - return ret; -} - -/* - * Request: - * NameZ - * Cursor - * - * Response: - * - */ -static krb5_error_code -kcm_op_end_get(krb5_context context, - kcm_client *client, - kcm_operation opcode, - krb5_storage *request, - krb5_storage *response) -{ - krb5_error_code ret; - char *name; - - ret = krb5_ret_stringz(request, &name); - if (ret) - return ret; - - KCM_LOG_REQUEST_NAME(context, client, opcode, name); - free(name); + kcm_release_ccache(context, ccache); return ret; } @@ -544,7 +535,7 @@ kcm_op_end_get(krb5_context context, * MatchCreds * * Response: - * + * */ static krb5_error_code kcm_op_remove_cred(krb5_context context, @@ -591,7 +582,7 @@ kcm_op_remove_cred(krb5_context context, free(name); krb5_free_cred_contents(context, &mcreds); - kcm_release_ccache(context, &ccache); + kcm_release_ccache(context, ccache); return ret; } @@ -602,7 +593,7 @@ kcm_op_remove_cred(krb5_context context, * Flags * * Response: - * + * */ static krb5_error_code kcm_op_set_flags(krb5_context context, @@ -637,7 +628,7 @@ kcm_op_set_flags(krb5_context context, /* we don't really support any flags yet */ free(name); - kcm_release_ccache(context, &ccache); + kcm_release_ccache(context, ccache); return 0; } @@ -649,7 +640,7 @@ kcm_op_set_flags(krb5_context context, * GID * * Response: - * + * */ static krb5_error_code kcm_op_chown(krb5_context context, @@ -692,7 +683,7 @@ kcm_op_chown(krb5_context context, ret = kcm_chown(context, client, ccache, uid, gid); free(name); - kcm_release_ccache(context, &ccache); + kcm_release_ccache(context, ccache); return ret; } @@ -703,7 +694,7 @@ kcm_op_chown(krb5_context context, * Mode * * Response: - * + * */ static krb5_error_code kcm_op_chmod(krb5_context context, @@ -739,7 +730,7 @@ kcm_op_chmod(krb5_context context, ret = kcm_chmod(context, client, ccache, mode); free(name); - kcm_release_ccache(context, &ccache); + kcm_release_ccache(context, ccache); return ret; } @@ -833,10 +824,10 @@ kcm_op_get_initial_ticket(krb5_context context, if (ret != 0) { krb5_free_principal(context, server); - krb5_free_keyblock(context, &key); + krb5_free_keyblock_contents(context, &key); } - kcm_release_ccache(context, &ccache); + kcm_release_ccache(context, ccache); return ret; } @@ -915,9 +906,12 @@ kcm_op_get_ticket(krb5_context context, HEIMDAL_MUTEX_unlock(&ccache->mutex); + krb5_free_principal(context, server); + if (ret == 0) krb5_free_cred_contents(context, out); + kcm_release_ccache(context, ccache); free(name); return ret; @@ -954,6 +948,13 @@ kcm_op_move_cache(krb5_context context, return ret; } + /* move to ourself is simple, done! */ + if (strcmp(oldname, newname) == 0) { + free(oldname); + free(newname); + return 0; + } + ret = kcm_ccache_resolve_client(context, client, opcode, oldname, &oldid); if (ret) { free(oldname); @@ -969,7 +970,7 @@ kcm_op_move_cache(krb5_context context, if (ret) { free(oldname); - kcm_release_ccache(context, &oldid); + kcm_release_ccache(context, oldid); return ret; } @@ -989,23 +990,708 @@ kcm_op_move_cache(krb5_context context, MOVE(newid, oldid, tkt_life); MOVE(newid, oldid, renew_life); MOVE(newid, oldid, key); - MOVE(newid, oldid, key); + MOVE(newid, oldid, kdc_offset); #undef MOVE } HEIMDAL_MUTEX_unlock(&oldid->mutex); HEIMDAL_MUTEX_unlock(&newid->mutex); - kcm_release_ccache(context, &oldid); - kcm_release_ccache(context, &newid); + kcm_release_ccache(context, oldid); + kcm_release_ccache(context, newid); ret = kcm_ccache_destroy_client(context, client, oldname); + if (ret == 0) + kcm_drop_default_cache(context, client, oldname); free(oldname); return ret; } +static krb5_error_code +kcm_op_get_cache_uuid_list(krb5_context context, + kcm_client *client, + kcm_operation opcode, + krb5_storage *request, + krb5_storage *response) +{ + KCM_LOG_REQUEST(context, client, opcode); + + return kcm_ccache_get_uuids(context, client, opcode, response); +} + +static krb5_error_code +kcm_op_get_cache_by_uuid(krb5_context context, + kcm_client *client, + kcm_operation opcode, + krb5_storage *request, + krb5_storage *response) +{ + krb5_error_code ret; + kcmuuid_t uuid; + ssize_t sret; + kcm_ccache cache; + + KCM_LOG_REQUEST(context, client, opcode); + + sret = krb5_storage_read(request, &uuid, sizeof(uuid)); + if (sret != sizeof(uuid)) { + krb5_clear_error_message(context); + return KRB5_CC_IO; + } + + ret = kcm_ccache_resolve_by_uuid(context, uuid, &cache); + if (ret) + return ret; + + ret = kcm_access(context, client, opcode, cache); + if (ret) + ret = KRB5_FCC_NOFILE; + + if (ret == 0) + ret = krb5_store_stringz(response, cache->name); + + kcm_release_ccache(context, cache); + + return ret; +} + +struct kcm_default_cache *default_caches; + +static krb5_error_code +kcm_op_get_default_cache(krb5_context context, + kcm_client *client, + kcm_operation opcode, + krb5_storage *request, + krb5_storage *response) +{ + struct kcm_default_cache *c; + krb5_error_code ret; + const char *name = NULL; + char *n = NULL; + int aret; + + KCM_LOG_REQUEST(context, client, opcode); + + for (c = default_caches; c != NULL; c = c->next) { + if (kcm_is_same_session(client, c->uid, c->session)) { + name = c->name; + break; + } + } + if (name == NULL) + name = n = kcm_ccache_first_name(client); + + if (name == NULL) { + aret = asprintf(&n, "%d", (int)client->uid); + if (aret != -1) + name = n; + } + if (name == NULL) + return ENOMEM; + ret = krb5_store_stringz(response, name); + if (n) + free(n); + return ret; +} + +static void +kcm_drop_default_cache(krb5_context context, kcm_client *client, char *name) +{ + struct kcm_default_cache **c; + + for (c = &default_caches; *c != NULL; c = &(*c)->next) { + if (!kcm_is_same_session(client, (*c)->uid, (*c)->session)) + continue; + if (strcmp((*c)->name, name) == 0) { + struct kcm_default_cache *h = *c; + *c = (*c)->next; + free(h->name); + free(h); + break; + } + } +} + +static krb5_error_code +kcm_op_set_default_cache(krb5_context context, + kcm_client *client, + kcm_operation opcode, + krb5_storage *request, + krb5_storage *response) +{ + struct kcm_default_cache *c; + krb5_error_code ret; + char *name; + + ret = krb5_ret_stringz(request, &name); + if (ret) + return ret; + + KCM_LOG_REQUEST_NAME(context, client, opcode, name); + + for (c = default_caches; c != NULL; c = c->next) { + if (kcm_is_same_session(client, c->uid, c->session)) + break; + } + if (c == NULL) { + c = malloc(sizeof(*c)); + if (c == NULL) { + free(name); + return ENOMEM; + } + c->session = client->session; + c->uid = client->uid; + c->name = name; + + c->next = default_caches; + default_caches = c; + } else { + free(c->name); + c->name = name; + } + + return 0; +} + +static krb5_error_code +kcm_op_get_kdc_offset(krb5_context context, + kcm_client *client, + kcm_operation opcode, + krb5_storage *request, + krb5_storage *response) +{ + krb5_error_code ret; + kcm_ccache ccache; + char *name; + + ret = krb5_ret_stringz(request, &name); + if (ret) + return ret; + + KCM_LOG_REQUEST_NAME(context, client, opcode, name); + + ret = kcm_ccache_resolve_client(context, client, opcode, name, &ccache); + free(name); + if (ret) + return ret; + + HEIMDAL_MUTEX_lock(&ccache->mutex); + ret = krb5_store_int32(response, ccache->kdc_offset); + HEIMDAL_MUTEX_unlock(&ccache->mutex); + + kcm_release_ccache(context, ccache); + + return ret; +} + +static krb5_error_code +kcm_op_set_kdc_offset(krb5_context context, + kcm_client *client, + kcm_operation opcode, + krb5_storage *request, + krb5_storage *response) +{ + krb5_error_code ret; + kcm_ccache ccache; + int32_t offset; + char *name; + + ret = krb5_ret_stringz(request, &name); + if (ret) + return ret; + + KCM_LOG_REQUEST_NAME(context, client, opcode, name); + + ret = krb5_ret_int32(request, &offset); + if (ret) { + free(name); + return ret; + } + + ret = kcm_ccache_resolve_client(context, client, opcode, name, &ccache); + free(name); + if (ret) + return ret; + + HEIMDAL_MUTEX_lock(&ccache->mutex); + ccache->kdc_offset = offset; + HEIMDAL_MUTEX_unlock(&ccache->mutex); + + kcm_release_ccache(context, ccache); + + return ret; +} + +struct kcm_ntlm_cred { + kcmuuid_t uuid; + char *user; + char *domain; + krb5_data nthash; + uid_t uid; + pid_t session; + struct kcm_ntlm_cred *next; +}; + +static struct kcm_ntlm_cred *ntlm_head; + +static void +free_cred(struct kcm_ntlm_cred *cred) +{ + free(cred->user); + free(cred->domain); + krb5_data_free(&cred->nthash); + free(cred); +} + + +/* + * name + * domain + * ntlm hash + * + * Reply: + * uuid + */ + +static struct kcm_ntlm_cred * +find_ntlm_cred(const char *user, const char *domain, kcm_client *client) +{ + struct kcm_ntlm_cred *c; + + for (c = ntlm_head; c != NULL; c = c->next) + if ((user[0] == '\0' || strcmp(user, c->user) == 0) && + (domain == NULL || strcmp(domain, c->domain) == 0) && + kcm_is_same_session(client, c->uid, c->session)) + return c; + + return NULL; +} + +static krb5_error_code +kcm_op_add_ntlm_cred(krb5_context context, + kcm_client *client, + kcm_operation opcode, + krb5_storage *request, + krb5_storage *response) +{ + struct kcm_ntlm_cred *cred, *c; + krb5_error_code ret; + + cred = calloc(1, sizeof(*cred)); + if (cred == NULL) + return ENOMEM; + + RAND_bytes(cred->uuid, sizeof(cred->uuid)); + + ret = krb5_ret_stringz(request, &cred->user); + if (ret) + goto error; + + ret = krb5_ret_stringz(request, &cred->domain); + if (ret) + goto error; + + ret = krb5_ret_data(request, &cred->nthash); + if (ret) + goto error; + + /* search for dups */ + c = find_ntlm_cred(cred->user, cred->domain, client); + if (c) { + krb5_data hash = c->nthash; + c->nthash = cred->nthash; + cred->nthash = hash; + free_cred(cred); + cred = c; + } else { + cred->next = ntlm_head; + ntlm_head = cred; + } + + cred->uid = client->uid; + cred->session = client->session; + + /* write response */ + (void)krb5_storage_write(response, &cred->uuid, sizeof(cred->uuid)); + + return 0; + + error: + free_cred(cred); + + return ret; +} + +/* + * { "HAVE_NTLM_CRED", NULL }, + * + * input: + * name + * domain + */ + +static krb5_error_code +kcm_op_have_ntlm_cred(krb5_context context, + kcm_client *client, + kcm_operation opcode, + krb5_storage *request, + krb5_storage *response) +{ + struct kcm_ntlm_cred *c; + char *user = NULL, *domain = NULL; + krb5_error_code ret; + + ret = krb5_ret_stringz(request, &user); + if (ret) + goto error; + + ret = krb5_ret_stringz(request, &domain); + if (ret) + goto error; + + if (domain[0] == '\0') { + free(domain); + domain = NULL; + } + + c = find_ntlm_cred(user, domain, client); + if (c == NULL) + ret = ENOENT; + + error: + free(user); + if (domain) + free(domain); + + return ret; +} + +/* + * { "DEL_NTLM_CRED", NULL }, + * + * input: + * name + * domain + */ + +static krb5_error_code +kcm_op_del_ntlm_cred(krb5_context context, + kcm_client *client, + kcm_operation opcode, + krb5_storage *request, + krb5_storage *response) +{ + struct kcm_ntlm_cred **cp, *c; + char *user = NULL, *domain = NULL; + krb5_error_code ret; + + ret = krb5_ret_stringz(request, &user); + if (ret) + goto error; + + ret = krb5_ret_stringz(request, &domain); + if (ret) + goto error; + + for (cp = &ntlm_head; *cp != NULL; cp = &(*cp)->next) { + if (strcmp(user, (*cp)->user) == 0 && strcmp(domain, (*cp)->domain) == 0 && + kcm_is_same_session(client, (*cp)->uid, (*cp)->session)) + { + c = *cp; + *cp = c->next; + + free_cred(c); + break; + } + } + + error: + free(user); + free(domain); + + return ret; +} + +/* + * { "DO_NTLM_AUTH", NULL }, + * + * input: + * name:string + * domain:string + * type2:data + * + * reply: + * type3:data + * flags:int32 + * session-key:data + */ + +#define NTLM_FLAG_SESSIONKEY 1 +#define NTLM_FLAG_NTLM2_SESSION 2 +#define NTLM_FLAG_KEYEX 4 + +static krb5_error_code +kcm_op_do_ntlm(krb5_context context, + kcm_client *client, + kcm_operation opcode, + krb5_storage *request, + krb5_storage *response) +{ + struct kcm_ntlm_cred *c; + struct ntlm_type2 type2; + struct ntlm_type3 type3; + char *user = NULL, *domain = NULL; + struct ntlm_buf ndata, sessionkey; + krb5_data data; + krb5_error_code ret; + uint32_t flags = 0; + + memset(&type2, 0, sizeof(type2)); + memset(&type3, 0, sizeof(type3)); + sessionkey.data = NULL; + sessionkey.length = 0; + + ret = krb5_ret_stringz(request, &user); + if (ret) + goto error; + + ret = krb5_ret_stringz(request, &domain); + if (ret) + goto error; + + if (domain[0] == '\0') { + free(domain); + domain = NULL; + } + + c = find_ntlm_cred(user, domain, client); + if (c == NULL) { + ret = EINVAL; + goto error; + } + + ret = krb5_ret_data(request, &data); + if (ret) + goto error; + + ndata.data = data.data; + ndata.length = data.length; + + ret = heim_ntlm_decode_type2(&ndata, &type2); + krb5_data_free(&data); + if (ret) + goto error; + + if (domain && strcmp(domain, type2.targetname) == 0) { + ret = EINVAL; + goto error; + } + + type3.username = c->user; + type3.flags = type2.flags; + type3.targetname = type2.targetname; + type3.ws = rk_UNCONST("workstation"); + + /* + * NTLM Version 1 if no targetinfo buffer. + */ + + if (1 || type2.targetinfo.length == 0) { + struct ntlm_buf tmpsesskey; + + if (type2.flags & NTLM_NEG_NTLM2_SESSION) { + unsigned char nonce[8]; + + if (RAND_bytes(nonce, sizeof(nonce)) != 1) { + ret = EINVAL; + goto error; + } + + ret = heim_ntlm_calculate_ntlm2_sess(nonce, + type2.challenge, + c->nthash.data, + &type3.lm, + &type3.ntlm); + } else { + ret = heim_ntlm_calculate_ntlm1(c->nthash.data, + c->nthash.length, + type2.challenge, + &type3.ntlm); + + } + if (ret) + goto error; + + ret = heim_ntlm_build_ntlm1_master(c->nthash.data, + c->nthash.length, + &tmpsesskey, + &type3.sessionkey); + if (ret) { + if (type3.lm.data) + free(type3.lm.data); + if (type3.ntlm.data) + free(type3.ntlm.data); + goto error; + } + + free(tmpsesskey.data); + flags |= NTLM_FLAG_SESSIONKEY; +#if 0 + } else { + struct ntlm_buf sessionkey; + unsigned char ntlmv2[16]; + struct ntlm_targetinfo ti; + + /* verify infotarget */ + + ret = heim_ntlm_decode_targetinfo(&type2.targetinfo, 1, &ti); + if(ret) { + _gss_ntlm_delete_sec_context(minor_status, + context_handle, NULL); + *minor_status = ret; + return GSS_S_FAILURE; + } + + if (ti.domainname && strcmp(ti.domainname, name->domain) != 0) { + _gss_ntlm_delete_sec_context(minor_status, + context_handle, NULL); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + ret = heim_ntlm_calculate_ntlm2(ctx->client->key.data, + ctx->client->key.length, + type3.username, + name->domain, + type2.challenge, + &type2.targetinfo, + ntlmv2, + &type3.ntlm); + if (ret) { + _gss_ntlm_delete_sec_context(minor_status, + context_handle, NULL); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = heim_ntlm_build_ntlm1_master(ntlmv2, sizeof(ntlmv2), + &sessionkey, + &type3.sessionkey); + memset(ntlmv2, 0, sizeof(ntlmv2)); + if (ret) { + _gss_ntlm_delete_sec_context(minor_status, + context_handle, NULL); + *minor_status = ret; + return GSS_S_FAILURE; + } + + flags |= NTLM_FLAG_NTLM2_SESSION | + NTLM_FLAG_SESSION; + + if (type3.flags & NTLM_NEG_KEYEX) + flags |= NTLM_FLAG_KEYEX; + + ret = krb5_data_copy(&ctx->sessionkey, + sessionkey.data, sessionkey.length); + free(sessionkey.data); + if (ret) { + _gss_ntlm_delete_sec_context(minor_status, + context_handle, NULL); + *minor_status = ret; + return GSS_S_FAILURE; + } +#endif + } + +#if 0 + if (flags & NTLM_FLAG_NTLM2_SESSION) { + _gss_ntlm_set_key(&ctx->u.v2.send, 0, (ctx->flags & NTLM_NEG_KEYEX), + ctx->sessionkey.data, + ctx->sessionkey.length); + _gss_ntlm_set_key(&ctx->u.v2.recv, 1, (ctx->flags & NTLM_NEG_KEYEX), + ctx->sessionkey.data, + ctx->sessionkey.length); + } else { + flags |= NTLM_FLAG_SESSION; + RC4_set_key(&ctx->u.v1.crypto_recv.key, + ctx->sessionkey.length, + ctx->sessionkey.data); + RC4_set_key(&ctx->u.v1.crypto_send.key, + ctx->sessionkey.length, + ctx->sessionkey.data); + } +#endif + + ret = heim_ntlm_encode_type3(&type3, &ndata, NULL); + if (ret) + goto error; + + data.data = ndata.data; + data.length = ndata.length; + ret = krb5_store_data(response, data); + heim_ntlm_free_buf(&ndata); + if (ret) goto error; + + ret = krb5_store_int32(response, flags); + if (ret) goto error; + + data.data = sessionkey.data; + data.length = sessionkey.length; + + ret = krb5_store_data(response, data); + if (ret) goto error; + + error: + free(type3.username); + heim_ntlm_free_type2(&type2); + free(user); + if (domain) + free(domain); + + return ret; +} + + +/* + * { "GET_NTLM_UUID_LIST", NULL } + * + * reply: + * 1 user domain + * 0 [ end of list ] + */ + +static krb5_error_code +kcm_op_get_ntlm_user_list(krb5_context context, + kcm_client *client, + kcm_operation opcode, + krb5_storage *request, + krb5_storage *response) +{ + struct kcm_ntlm_cred *c; + krb5_error_code ret; + + for (c = ntlm_head; c != NULL; c = c->next) { + if (!kcm_is_same_session(client, c->uid, c->session)) + continue; + + ret = krb5_store_uint32(response, 1); + if (ret) + return ret; + ret = krb5_store_stringz(response, c->user); + if (ret) + return ret; + ret = krb5_store_stringz(response, c->domain); + if (ret) + return ret; + } + return krb5_store_uint32(response, 0); +} + +/* + * + */ static struct kcm_op kcm_ops[] = { { "NOOP", kcm_op_noop }, @@ -1017,20 +1703,31 @@ static struct kcm_op kcm_ops[] = { { "STORE", kcm_op_store }, { "RETRIEVE", kcm_op_retrieve }, { "GET_PRINCIPAL", kcm_op_get_principal }, - { "GET_FIRST", kcm_op_get_first }, - { "GET_NEXT", kcm_op_get_next }, - { "END_GET", kcm_op_end_get }, + { "GET_CRED_UUID_LIST", kcm_op_get_cred_uuid_list }, + { "GET_CRED_BY_UUID", kcm_op_get_cred_by_uuid }, { "REMOVE_CRED", kcm_op_remove_cred }, { "SET_FLAGS", kcm_op_set_flags }, { "CHOWN", kcm_op_chown }, { "CHMOD", kcm_op_chmod }, { "GET_INITIAL_TICKET", kcm_op_get_initial_ticket }, { "GET_TICKET", kcm_op_get_ticket }, - { "MOVE_CACHE", kcm_op_move_cache } + { "MOVE_CACHE", kcm_op_move_cache }, + { "GET_CACHE_UUID_LIST", kcm_op_get_cache_uuid_list }, + { "GET_CACHE_BY_UUID", kcm_op_get_cache_by_uuid }, + { "GET_DEFAULT_CACHE", kcm_op_get_default_cache }, + { "SET_DEFAULT_CACHE", kcm_op_set_default_cache }, + { "GET_KDC_OFFSET", kcm_op_get_kdc_offset }, + { "SET_KDC_OFFSET", kcm_op_set_kdc_offset }, + { "ADD_NTLM_CRED", kcm_op_add_ntlm_cred }, + { "HAVE_USER_CRED", kcm_op_have_ntlm_cred }, + { "DEL_NTLM_CRED", kcm_op_del_ntlm_cred }, + { "DO_NTLM_AUTH", kcm_op_do_ntlm }, + { "GET_NTLM_USER_LIST", kcm_op_get_ntlm_user_list } }; -const char *kcm_op2string(kcm_operation opcode) +const char * +kcm_op2string(kcm_operation opcode) { if (opcode >= sizeof(kcm_ops)/sizeof(kcm_ops[0])) return "Unknown operation"; @@ -1050,6 +1747,7 @@ kcm_dispatch(krb5_context context, krb5_storage *resp_sp = NULL; uint16_t opcode; + krb5_data_zero(resp_data); resp_sp = krb5_storage_emem(); if (resp_sp == NULL) { return ENOMEM; @@ -1082,6 +1780,12 @@ kcm_dispatch(krb5_context context, goto out; } method = kcm_ops[opcode].method; + if (method == NULL) { + kcm_log(0, "Process %d: operation code %s not implemented", + client->pid, kcm_op2string(opcode)); + ret = KRB5_FCC_INTERNAL; + goto out; + } /* seek past place for status code */ krb5_storage_seek(resp_sp, 4, SEEK_SET); @@ -1093,11 +1797,17 @@ out: krb5_storage_free(req_sp); } - krb5_storage_seek(resp_sp, 0, SEEK_SET); - krb5_store_int32(resp_sp, ret); + if (resp_sp) { + krb5_error_code ret2; - ret = krb5_storage_to_data(resp_sp, resp_data); - krb5_storage_free(resp_sp); + krb5_storage_seek(resp_sp, 0, SEEK_SET); + ret2 = krb5_store_int32(resp_sp, ret); + if (ret2 == 0) + ret2 = krb5_storage_to_data(resp_sp, resp_data); + krb5_storage_free(resp_sp); + if (ret2) + ret = ret2; + } return ret; } diff --git a/kcm/renew.c b/kcm/renew.c index ea06208f3..7b31965a2 100644 --- a/kcm/renew.c +++ b/kcm/renew.c @@ -44,6 +44,7 @@ kcm_ccache_refresh(krb5_context context, krb5_kdc_flags flags; krb5_const_realm realm; krb5_ccache_data ccdata; + const char *estr; memset(&in, 0, sizeof(in)); @@ -66,8 +67,10 @@ kcm_ccache_refresh(krb5_context context, if (ccache->server != NULL) { ret = krb5_copy_principal(context, ccache->server, &in.server); if (ret) { + estr = krb5_get_error_message(context, ret); kcm_log(0, "Failed to copy service principal: %s", - krb5_get_err_text(context, ret)); + estr); + krb5_free_error_message(context, estr); goto out; } } else { @@ -75,8 +78,10 @@ kcm_ccache_refresh(krb5_context context, ret = krb5_make_principal(context, &in.server, realm, KRB5_TGS_NAME, realm, NULL); if (ret) { + estr = krb5_get_error_message(context, ret); kcm_log(0, "Failed to make TGS principal for realm %s: %s", - realm, krb5_get_err_text(context, ret)); + realm, estr); + krb5_free_error_message(context, estr); goto out; } } @@ -98,8 +103,10 @@ kcm_ccache_refresh(krb5_context context, &in, &out); if (ret) { + estr = krb5_get_error_message(context, ret); kcm_log(0, "Failed to renew credentials for cache %s: %s", - ccache->name, krb5_get_err_text(context, ret)); + ccache->name, estr); + krb5_free_error_message(context, estr); goto out; } @@ -108,8 +115,10 @@ kcm_ccache_refresh(krb5_context context, ret = kcm_ccache_store_cred_internal(context, ccache, out, 0, credp); if (ret) { + estr = krb5_get_error_message(context, ret); kcm_log(0, "Failed to store credentials for cache %s: %s", - ccache->name, krb5_get_err_text(context, ret)); + ccache->name, estr); + krb5_free_error_message(context, estr); krb5_free_creds(context, out); goto out; } diff --git a/kcm/sessions.c b/kcm/sessions.c new file mode 100644 index 000000000..4e66cc5e8 --- /dev/null +++ b/kcm/sessions.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kcm_locl.h" + +#if 0 +#include +#endif + +void +kcm_session_add(pid_t session_id) +{ + kcm_log(1, "monitor session: %d\n", session_id); +} + +void +kcm_session_setup_handler(void) +{ +#if 0 + au_sdev_handle_t *h; + dispatch_queue_t bgq; + + h = au_sdev_open(AU_SDEVF_ALLSESSIONS); + if (h == NULL) + return; + + bgq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0); + + dispatch_async(bgq, ^{ + for (;;) { + auditinfo_addr_t aio; + int event; + + if (au_sdev_read_aia(h, &event, &aio) != 0) + continue; + + /* + * Ignore everything but END. This should relly be + * CLOSE but since that is delayed until the credential + * is reused, we can't do that + * */ + if (event != AUE_SESSION_END) + continue; + + dispatch_async(dispatch_get_main_queue(), ^{ + kcm_cache_remove_session(aio.ai_asid); + }); + } + }); +#endif +} diff --git a/kdc/524.c b/kdc/524.c deleted file mode 100644 index 76641b389..000000000 --- a/kdc/524.c +++ /dev/null @@ -1,398 +0,0 @@ -/* - * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "kdc_locl.h" - -RCSID("$Id$"); - -#include - -/* - * fetch the server from `t', returning the name in malloced memory in - * `spn' and the entry itself in `server' - */ - -static krb5_error_code -fetch_server (krb5_context context, - krb5_kdc_configuration *config, - const Ticket *t, - char **spn, - hdb_entry_ex **server, - const char *from) -{ - krb5_error_code ret; - krb5_principal sprinc; - - ret = _krb5_principalname2krb5_principal(context, &sprinc, - t->sname, t->realm); - if (ret) { - kdc_log(context, config, 0, "_krb5_principalname2krb5_principal: %s", - krb5_get_err_text(context, ret)); - return ret; - } - ret = krb5_unparse_name(context, sprinc, spn); - if (ret) { - krb5_free_principal(context, sprinc); - kdc_log(context, config, 0, "krb5_unparse_name: %s", - krb5_get_err_text(context, ret)); - return ret; - } - ret = _kdc_db_fetch(context, config, sprinc, HDB_F_GET_SERVER, - NULL, server); - krb5_free_principal(context, sprinc); - if (ret) { - kdc_log(context, config, 0, - "Request to convert ticket from %s for unknown principal %s: %s", - from, *spn, krb5_get_err_text(context, ret)); - if (ret == HDB_ERR_NOENTRY) - ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; - return ret; - } - return 0; -} - -static krb5_error_code -log_524 (krb5_context context, - krb5_kdc_configuration *config, - const EncTicketPart *et, - const char *from, - const char *spn) -{ - krb5_principal client; - char *cpn; - krb5_error_code ret; - - ret = _krb5_principalname2krb5_principal(context, &client, - et->cname, et->crealm); - if (ret) { - kdc_log(context, config, 0, "_krb5_principalname2krb5_principal: %s", - krb5_get_err_text (context, ret)); - return ret; - } - ret = krb5_unparse_name(context, client, &cpn); - if (ret) { - krb5_free_principal(context, client); - kdc_log(context, config, 0, "krb5_unparse_name: %s", - krb5_get_err_text (context, ret)); - return ret; - } - kdc_log(context, config, 1, "524-REQ %s from %s for %s", cpn, from, spn); - free(cpn); - krb5_free_principal(context, client); - return 0; -} - -static krb5_error_code -verify_flags (krb5_context context, - krb5_kdc_configuration *config, - const EncTicketPart *et, - const char *spn) -{ - if(et->endtime < kdc_time){ - kdc_log(context, config, 0, "Ticket expired (%s)", spn); - return KRB5KRB_AP_ERR_TKT_EXPIRED; - } - if(et->flags.invalid){ - kdc_log(context, config, 0, "Ticket not valid (%s)", spn); - return KRB5KRB_AP_ERR_TKT_NYV; - } - return 0; -} - -/* - * set the `et->caddr' to the most appropriate address to use, where - * `addr' is the address the request was received from. - */ - -static krb5_error_code -set_address (krb5_context context, - krb5_kdc_configuration *config, - EncTicketPart *et, - struct sockaddr *addr, - const char *from) -{ - krb5_error_code ret; - krb5_address *v4_addr; - - v4_addr = malloc (sizeof(*v4_addr)); - if (v4_addr == NULL) - return ENOMEM; - - ret = krb5_sockaddr2address(context, addr, v4_addr); - if(ret) { - free (v4_addr); - kdc_log(context, config, 0, "Failed to convert address (%s)", from); - return ret; - } - - if (et->caddr && !krb5_address_search (context, v4_addr, et->caddr)) { - kdc_log(context, config, 0, "Incorrect network address (%s)", from); - krb5_free_address(context, v4_addr); - free (v4_addr); - return KRB5KRB_AP_ERR_BADADDR; - } - if(v4_addr->addr_type == KRB5_ADDRESS_INET) { - /* we need to collapse the addresses in the ticket to a - single address; best guess is to use the address the - connection came from */ - - if (et->caddr != NULL) { - free_HostAddresses(et->caddr); - } else { - et->caddr = malloc (sizeof (*et->caddr)); - if (et->caddr == NULL) { - krb5_free_address(context, v4_addr); - free(v4_addr); - return ENOMEM; - } - } - et->caddr->val = v4_addr; - et->caddr->len = 1; - } else { - krb5_free_address(context, v4_addr); - free(v4_addr); - } - return 0; -} - - -static krb5_error_code -encrypt_v4_ticket(krb5_context context, - krb5_kdc_configuration *config, - void *buf, - size_t len, - krb5_keyblock *skey, - EncryptedData *reply) -{ - krb5_crypto crypto; - krb5_error_code ret; - ret = krb5_crypto_init(context, skey, ETYPE_DES_PCBC_NONE, &crypto); - if (ret) { - free(buf); - kdc_log(context, config, 0, "krb5_crypto_init failed: %s", - krb5_get_err_text(context, ret)); - return ret; - } - - ret = krb5_encrypt_EncryptedData(context, - crypto, - KRB5_KU_TICKET, - buf, - len, - 0, - reply); - krb5_crypto_destroy(context, crypto); - if(ret) { - kdc_log(context, config, 0, "Failed to encrypt data: %s", - krb5_get_err_text(context, ret)); - return ret; - } - return 0; -} - -static krb5_error_code -encode_524_response(krb5_context context, - krb5_kdc_configuration *config, - const char *spn, const EncTicketPart et, - const Ticket *t, hdb_entry_ex *server, - EncryptedData *ticket, int *kvno) -{ - krb5_error_code ret; - int use_2b; - size_t len; - - use_2b = krb5_config_get_bool(context, NULL, "kdc", "use_2b", spn, NULL); - if(use_2b) { - ASN1_MALLOC_ENCODE(EncryptedData, - ticket->cipher.data, ticket->cipher.length, - &t->enc_part, &len, ret); - - if (ret) { - kdc_log(context, config, 0, - "Failed to encode v4 (2b) ticket (%s)", spn); - return ret; - } - - ticket->etype = 0; - ticket->kvno = NULL; - *kvno = 213; /* 2b's use this magic kvno */ - } else { - unsigned char buf[MAX_KTXT_LEN + 4 * 4]; - Key *skey; - - if (!config->enable_v4_cross_realm && strcmp (et.crealm, t->realm) != 0) { - kdc_log(context, config, 0, "524 cross-realm %s -> %s disabled", et.crealm, - t->realm); - return KRB5KDC_ERR_POLICY; - } - - ret = _kdc_encode_v4_ticket(context, config, - buf + sizeof(buf) - 1, sizeof(buf), - &et, &t->sname, &len); - if(ret){ - kdc_log(context, config, 0, - "Failed to encode v4 ticket (%s)", spn); - return ret; - } - ret = _kdc_get_des_key(context, server, TRUE, FALSE, &skey); - if(ret){ - kdc_log(context, config, 0, - "no suitable DES key for server (%s)", spn); - return ret; - } - ret = encrypt_v4_ticket(context, config, buf + sizeof(buf) - len, len, - &skey->key, ticket); - if(ret){ - kdc_log(context, config, 0, - "Failed to encrypt v4 ticket (%s)", spn); - return ret; - } - *kvno = server->entry.kvno; - } - - return 0; -} - -/* - * process a 5->4 request, based on `t', and received `from, addr', - * returning the reply in `reply' - */ - -krb5_error_code -_kdc_do_524(krb5_context context, - krb5_kdc_configuration *config, - const Ticket *t, krb5_data *reply, - const char *from, struct sockaddr *addr) -{ - krb5_error_code ret = 0; - krb5_crypto crypto; - hdb_entry_ex *server = NULL; - Key *skey; - krb5_data et_data; - EncTicketPart et; - EncryptedData ticket; - krb5_storage *sp; - char *spn = NULL; - unsigned char buf[MAX_KTXT_LEN + 4 * 4]; - int kvno = 0; - - if(!config->enable_524) { - ret = KRB5KDC_ERR_POLICY; - kdc_log(context, config, 0, - "Rejected ticket conversion request from %s", from); - goto out; - } - - ret = fetch_server (context, config, t, &spn, &server, from); - if (ret) { - goto out; - } - - ret = hdb_enctype2key(context, &server->entry, t->enc_part.etype, &skey); - if(ret){ - kdc_log(context, config, 0, - "No suitable key found for server (%s) from %s", spn, from); - goto out; - } - ret = krb5_crypto_init(context, &skey->key, 0, &crypto); - if (ret) { - kdc_log(context, config, 0, "krb5_crypto_init failed: %s", - krb5_get_err_text(context, ret)); - goto out; - } - ret = krb5_decrypt_EncryptedData (context, - crypto, - KRB5_KU_TICKET, - &t->enc_part, - &et_data); - krb5_crypto_destroy(context, crypto); - if(ret){ - kdc_log(context, config, 0, - "Failed to decrypt ticket from %s for %s", from, spn); - goto out; - } - ret = decode_EncTicketPart(et_data.data, et_data.length, &et, NULL); - krb5_data_free(&et_data); - if(ret){ - kdc_log(context, config, 0, - "Failed to decode ticket from %s for %s", from, spn); - goto out; - } - - ret = log_524 (context, config, &et, from, spn); - if (ret) { - free_EncTicketPart(&et); - goto out; - } - - ret = verify_flags (context, config, &et, spn); - if (ret) { - free_EncTicketPart(&et); - goto out; - } - - ret = set_address (context, config, &et, addr, from); - if (ret) { - free_EncTicketPart(&et); - goto out; - } - - ret = encode_524_response(context, config, spn, et, t, - server, &ticket, &kvno); - free_EncTicketPart(&et); - - out: - /* make reply */ - memset(buf, 0, sizeof(buf)); - sp = krb5_storage_from_mem(buf, sizeof(buf)); - if (sp) { - krb5_store_int32(sp, ret); - if(ret == 0){ - krb5_store_int32(sp, kvno); - krb5_store_data(sp, ticket.cipher); - /* Aargh! This is coded as a KTEXT_ST. */ - krb5_storage_seek(sp, MAX_KTXT_LEN - ticket.cipher.length, SEEK_CUR); - krb5_store_int32(sp, 0); /* mbz */ - free_EncryptedData(&ticket); - } - ret = krb5_storage_to_data(sp, reply); - reply->length = krb5_storage_seek(sp, 0, SEEK_CUR); - krb5_storage_free(sp); - } else - krb5_data_zero(reply); - if(spn) - free(spn); - if(server) - _kdc_free_ent (context, server); - return ret; -} diff --git a/kdc/Makefile.am b/kdc/Makefile.am index 2c7fd91cc..1d37680cd 100644 --- a/kdc/Makefile.am +++ b/kdc/Makefile.am @@ -2,87 +2,198 @@ include $(top_srcdir)/Makefile.am.common -AM_CPPFLAGS += $(INCLUDE_libintl) $(INCLUDE_krb4) $(INCLUDE_hcrypto) -I$(srcdir)/../lib/krb5 +WFLAGS += $(WFLAGS_ENUM_CONV) + +AM_CPPFLAGS += $(INCLUDE_libintl) $(INCLUDE_openssl_crypto) -I$(srcdir)/../lib/krb5 + +lib_LTLIBRARIES = ipc_csr_authorizer.la \ + negotiate_token_validator.la \ + libkdc.la + +if HAVE_CJWT +lib_LTLIBRARIES += cjwt_token_validator.la +endif +if OPENLDAP +lib_LTLIBRARIES += altsecid_gss_preauth_authorizer.la +endif -lib_LTLIBRARIES = libkdc.la bin_PROGRAMS = string2key sbin_PROGRAMS = kstash -libexec_PROGRAMS = hprop hpropd kdc +libexec_PROGRAMS = hprop hpropd kdc digest-service \ + test_token_validator test_csr_authorizer test_kdc_ca -noinst_PROGRAMS = kdc-replay +noinst_PROGRAMS = kdc-replay kdc-tester -man_MANS = kdc.8 kstash.8 hprop.8 hpropd.8 string2key.8 +man_MANS = bx509d.8 httpkadmind.8 kdc.8 kstash.8 hprop.8 hpropd.8 string2key.8 -hprop_SOURCES = hprop.c mit_dump.c v4_dump.c hprop.h kadb.h +hprop_SOURCES = hprop.c mit_dump.c hprop.h hpropd_SOURCES = hpropd.c hprop.h kstash_SOURCES = kstash.c headers.h string2key_SOURCES = string2key.c headers.h +if HAVE_MICROHTTPD +bx509d_SOURCES = bx509d.c +bx509d_CPPFLAGS = $(AM_CPPFLAGS) $(MICROHTTPD_CFLAGS) +bx509d_LDADD = -ldl \ + $(top_builddir)/lib/hdb/libhdb.la \ + libkdc.la \ + $(MICROHTTPD_LIBS) \ + $(LIB_roken) \ + $(LIB_heimbase) \ + $(LIB_hcrypto) \ + $(top_builddir)/lib/sl/libsl.la \ + $(top_builddir)/lib/asn1/libasn1.la \ + $(top_builddir)/lib/krb5/libkrb5.la \ + $(top_builddir)/lib/hx509/libhx509.la \ + $(top_builddir)/lib/gssapi/libgssapi.la +libexec_PROGRAMS += bx509d + +httpkadmind_SOURCES = httpkadmind.c +httpkadmind_CPPFLAGS = $(AM_CPPFLAGS) $(MICROHTTPD_CFLAGS) +httpkadmind_LDADD = -ldl \ + $(top_builddir)/lib/hdb/libhdb.la \ + $(top_builddir)/lib/kadm5/libkadm5clnt.la \ + $(top_builddir)/lib/kadm5/libkadm5srv.la \ + libkdc.la \ + $(MICROHTTPD_LIBS) \ + $(LIB_roken) \ + $(LIB_heimbase) \ + $(LIB_hcrypto) \ + $(top_builddir)/lib/sl/libsl.la \ + $(top_builddir)/lib/asn1/libasn1.la \ + $(top_builddir)/lib/krb5/libkrb5.la \ + $(top_builddir)/lib/hx509/libhx509.la \ + $(top_builddir)/lib/gssapi/libgssapi.la +libexec_PROGRAMS += httpkadmind +endif + +digest_service_SOURCES = \ + digest-service.c + kdc_SOURCES = connect.c \ config.c \ + announce.c \ main.c +kdc_tester_SOURCES = \ + config.c \ + kdc-tester.c + +test_token_validator_SOURCES = test_token_validator.c +test_csr_authorizer_SOURCES = test_csr_authorizer.c +test_kdc_ca_SOURCES = test_kdc_ca.c + +# Token plugins (for bx509d) +if HAVE_CJWT +cjwt_token_validator_la_SOURCES = cjwt_token_validator.c +cjwt_token_validator_la_CFLAGS = $(CJSON_CFLAGS) $(CJWT_CFLAGS) +cjwt_token_validator_la_LDFLAGS = -module $(CJSON_LIBS) $(CJWT_LIBS) +endif + +negotiate_token_validator_la_SOURCES = negotiate_token_validator.c +negotiate_token_validator_la_LDFLAGS = -module $(LIB_gssapi) +# CSR Authorizer plugins (for kdc/kx509 and bx509d) +ipc_csr_authorizer_la_SOURCES = ipc_csr_authorizer.c +ipc_csr_authorizer_la_LDFLAGS = -module \ + $(top_builddir)/lib/krb5/libkrb5.la \ + $(top_builddir)/lib/hx509/libhx509.la \ + $(top_builddir)/lib/ipc/libheim-ipcc.la \ + $(top_builddir)/lib/roken/libroken.la + +# GSS-API authorization plugins +if OPENLDAP +altsecid_gss_preauth_authorizer_la_SOURCES = altsecid_gss_preauth_authorizer.c +altsecid_gss_preauth_authorizer_la_LDFLAGS = -module \ + $(top_builddir)/lib/gssapi/libgssapi.la \ + $(top_builddir)/lib/krb5/libkrb5.la \ + $(LIB_openldap) +endif + +libkdc_la_CPPFLAGS = -DBUILD_KDC_LIB $(AM_CPPFLAGS) + libkdc_la_SOURCES = \ - kdc-private.h \ - kdc-protos.h \ default_config.c \ + ca.c \ set_dbinfo.c \ digest.c \ + fast.c \ kdc_locl.h \ kerberos5.c \ krb5tgs.c \ pkinit.c \ + pkinit-ec.c \ + mssfu.c \ log.c \ misc.c \ - 524.c \ - kerberos4.c \ - kaserver.c \ kx509.c \ + token_validator.c \ + csr_authorizer.c \ process.c \ - windc.c \ - rx.h + kdc-plugin.c \ + gss_preauth.c +KDC_PROTOS = $(srcdir)/kdc-protos.h $(srcdir)/kdc-private.h -$(libkdc_la_OBJECTS): $(srcdir)/kdc-protos.h $(srcdir)/kdc-private.h +ALL_OBJECTS = $(kdc_OBJECTS) +ALL_OBJECTS += $(kdc_replay_OBJECTS) +ALL_OBJECTS += $(kdc_tester_OBJECTS) +ALL_OBJECTS += $(test_token_validator_OBJECTS) +ALL_OBJECTS += $(test_csr_authorizer_OBJECTS) +ALL_OBJECTS += $(test_kdc_ca_OBJECTS) +ALL_OBJECTS += $(libkdc_la_OBJECTS) +ALL_OBJECTS += $(string2key_OBJECTS) +ALL_OBJECTS += $(kstash_OBJECTS) +ALL_OBJECTS += $(hprop_OBJECTS) +ALL_OBJECTS += $(hpropd_OBJECTS) +ALL_OBJECTS += $(digest_service_OBJECTS) +ALL_OBJECTS += $(bx509d_OBJECTS) +ALL_OBJECTS += $(httpkadmind_OBJECTS) +ALL_OBJECTS += $(cjwt_token_validator_la_OBJECTS) +ALL_OBJECTS += $(test_token_validator_OBJECTS) +ALL_OBJECTS += $(test_csr_authorizer_OBJECTS) +ALL_OBJECTS += $(test_kdc_ca_OBJECTS) +ALL_OBJECTS += $(ipc_csr_authorizer_la_OBJECTS) +ALL_OBJECTS += $(negotiate_token_validator_la_OBJECTS) + +$(ALL_OBJECTS): $(KDC_PROTOS) libkdc_la_LDFLAGS = -version-info 2:0:0 if versionscript libkdc_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-script.map endif + $(libkdc_la_OBJECTS): $(srcdir)/version-script.map -$(srcdir)/kdc-protos.h: - cd $(srcdir) && perl ../cf/make-proto.pl -q -P comment -o kdc-protos.h $(libkdc_la_SOURCES) || rm -f kdc-protos.h +$(srcdir)/kdc-protos.h: $(libkdc_la_SOURCES) + cd $(srcdir) && perl ../cf/make-proto.pl -E KDC_LIB -q -P comment -o kdc-protos.h $(libkdc_la_SOURCES) || rm -f kdc-protos.h -$(srcdir)/kdc-private.h: +$(srcdir)/kdc-private.h: $(libkdc_la_SOURCES) cd $(srcdir) && perl ../cf/make-proto.pl -q -P comment -p kdc-private.h $(libkdc_la_SOURCES) || rm -f kdc-private.h hprop_LDADD = \ $(top_builddir)/lib/hdb/libhdb.la \ - $(LIB_openldap) \ $(top_builddir)/lib/krb5/libkrb5.la \ - $(LIB_kdb) $(LIB_krb4) \ + $(LIB_kdb) \ $(LIB_hcrypto) \ $(top_builddir)/lib/asn1/libasn1.la \ $(LIB_roken) \ - $(DBLIB) + $(DB3LIB) $(DB1LIB) $(LMDBLIB) $(NDBMLIB) hpropd_LDADD = \ $(top_builddir)/lib/hdb/libhdb.la \ - $(LIB_openldap) \ $(top_builddir)/lib/krb5/libkrb5.la \ - $(LIB_kdb) $(LIB_krb4) \ + $(LIB_kdb) \ $(LIB_hcrypto) \ $(top_builddir)/lib/asn1/libasn1.la \ $(LIB_roken) \ - $(DBLIB) + $(DB3LIB) $(DB1LIB) $(LMDBLIB) $(NDBMLIB) if PKINIT LIB_pkinit = $(top_builddir)/lib/hx509/libhx509.la @@ -91,32 +202,62 @@ endif libkdc_la_LIBADD = \ $(LIB_pkinit) \ $(top_builddir)/lib/hdb/libhdb.la \ - $(LIB_openldap) \ $(top_builddir)/lib/krb5/libkrb5.la \ - $(LIB_kdb) $(LIB_krb4) \ + $(top_builddir)/lib/gssapi/libgssapi.la \ + $(top_builddir)/lib/gss_preauth/libgss_preauth.la \ + $(LIB_kdb) \ $(top_builddir)/lib/ntlm/libheimntlm.la \ $(LIB_hcrypto) \ + $(LIB_openssl_crypto) \ $(top_builddir)/lib/asn1/libasn1.la \ $(LIB_roken) \ - $(DBLIB) + $(DB3LIB) $(DB1LIB) $(LMDBLIB) $(NDBMLIB) LDADD = $(top_builddir)/lib/hdb/libhdb.la \ - $(LIB_openldap) \ $(top_builddir)/lib/krb5/libkrb5.la \ - $(LIB_krb4) \ $(LIB_hcrypto) \ $(top_builddir)/lib/asn1/libasn1.la \ $(LIB_roken) \ - $(DBLIB) + $(DB3LIB) $(DB1LIB) $(LMDBLIB) $(NDBMLIB) -kdc_LDADD = libkdc.la $(LDADD) $(LIB_pidfile) -kdc_replay_LDADD = $(kdc_LDADD) +kdc_LDADD = libkdc.la $(LDADD) $(LIB_pidfile) $(CAPNG_LIBS) -include_HEADERS = kdc.h kdc-protos.h +if FRAMEWORK_SECURITY +kdc_LDFLAGS = -framework SystemConfiguration -framework CoreFoundation +endif +kdc_CFLAGS = $(CAPNG_CFLAGS) + +digest_service_LDADD = \ + libkdc.la \ + $(top_builddir)/lib/ntlm/libheimntlm.la \ + $(top_builddir)/lib/ipc/libheim-ipcs.la \ + $(LDADD) $(LIB_pidfile) +kdc_replay_LDADD = libkdc.la $(LDADD) $(LIB_pidfile) +kdc_tester_LDADD = libkdc.la $(LDADD) $(LIB_pidfile) $(LIB_heimbase) +test_token_validator_LDADD = libkdc.la $(LDADD) $(LIB_pidfile) $(LIB_heimbase) $(LIB_gssapi) +test_csr_authorizer_LDADD = libkdc.la \ + $(top_builddir)/lib/hx509/libhx509.la \ + $(LDADD) \ + $(LIB_pidfile) \ + $(LIB_heimbase) \ + $(top_builddir)/lib/ipc/libheim-ipcs.la +test_kdc_ca_LDADD = libkdc.la $(top_builddir)/lib/hx509/libhx509.la $(LDADD) $(LIB_pidfile) $(LIB_heimbase) + +include_HEADERS = kdc.h $(srcdir)/kdc-protos.h + +noinst_HEADERS = $(srcdir)/kdc-private.h krb5dir = $(includedir)/krb5 -krb5_HEADERS = windc_plugin.h +krb5_HEADERS = kdc-audit.h kdc-plugin.h kdc-accessors.h token_validator_plugin.h csr_authorizer_plugin.h gss_preauth_authorizer_plugin.h build_HEADERZ = $(krb5_HEADERS) # XXX -EXTRA_DIST = $(man_MANS) version-script.map +EXTRA_DIST = \ + hprop-version.rc \ + hpropd-version.rc \ + kdc-version.rc \ + kstash-version.rc \ + libkdc-version.rc \ + string2key-version.rc \ + libkdc-exports.def \ + NTMakefile $(man_MANS) version-script.map diff --git a/kdc/NTMakefile b/kdc/NTMakefile new file mode 100644 index 000000000..aca65b104 --- /dev/null +++ b/kdc/NTMakefile @@ -0,0 +1,167 @@ +######################################################################## +# +# Copyright (c) 2009-2016, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=kdc + +!include ../windows/NTMakefile.w32 + +intcflags=-I$(OBJ) -I$(SRC)\lib\gssapi -I$(OBJDIR)\lib\gssapi -I$(OBJDIR)\lib\gss_preauth -DBUILD_KDC_LIB + +BINPROGRAMS=$(BINDIR)\string2key.exe + +SBINPROGRAMS=$(SBINDIR)\kstash.exe + +LIBEXECPROGRAMS= \ + $(LIBEXECDIR)\hprop.exe \ + $(LIBEXECDIR)\hpropd.exe \ + $(LIBEXECDIR)\kdc.exe \ +# $(LIBEXECDIR)\digest-service.exe + +NOINST_PROGRAMS=$(OBJ)\kdc-replay.exe + +INCFILES=\ + $(INCDIR)\kdc.h \ + $(INCDIR)\kdc-protos.h \ + $(INCDIR)\kdc-private.h \ + $(INCDIR)\krb5\kdc-audit.h \ + $(INCDIR)\krb5\kdc-plugin.h \ + $(INCDIR)\krb5\kdc-accessors.h + +all:: $(INCFILES) $(LIBKDC) $(BINPROGRAMS) $(SBINPROGRAMS) $(LIBEXECPROGRAMS) + +clean:: + -$(RM) $(LIBKDC) + -$(RM) $(BINPROGRAMS:.exe=.*) $(SBINPROGRAMS:.exe=.*) $(LIBEXECPROGRAMS:.exe=.*) + +BIN_LIBS=\ + $(LIBHDB) \ + $(LIBHEIMDAL) \ + $(LIBROKEN) \ + $(LIBVERS) + +$(LIBEXECDIR)\hprop.exe: $(OBJ)\hprop.obj $(OBJ)\mit_dump.obj $(BIN_LIBS) $(OBJ)\hprop-version.res + $(EXECONLINK) + $(EXEPREP) + +$(LIBEXECDIR)\hpropd.exe: $(OBJ)\hpropd.obj $(BIN_LIBS) $(OBJ)\hpropd-version.res + $(EXECONLINK) + $(EXEPREP) + +$(SBINDIR)\kstash.exe: $(OBJ)\kstash.obj $(BIN_LIBS) $(OBJ)\kstash-version.res + $(EXECONLINK) + $(EXEPREP) + +$(BINDIR)\string2key.exe: $(OBJ)\string2key.obj $(BIN_LIBS) $(OBJ)\string2key-version.res + $(EXECONLINK) + $(EXEPREP) + +$(BINDIR)\digest-service.exe: $(OBJ)\digest-service.obj $(BIN_LIBS) + $(EXECONLINK) + $(EXEPREP) + +$(LIBEXECDIR)\kdc.exe: \ + $(OBJ)\connect.obj $(OBJ)\config.obj $(OBJ)\announce.obj \ + $(OBJ)\main.obj $(OBJ)\kdc-version.res \ + $(LIBKDC) $(BIN_LIBS) $(LIB_openssl_crypto) + $(EXECONLINK) + $(EXEPREP) + +LIBKDC_OBJS=\ + $(OBJ)\default_config.obj \ + $(OBJ)\ca.obj \ + $(OBJ)\kx509.obj \ + $(OBJ)\set_dbinfo.obj \ + $(OBJ)\digest.obj \ + $(OBJ)\fast.obj \ + $(OBJ)\kerberos5.obj \ + $(OBJ)\krb5tgs.obj \ + $(OBJ)\pkinit.obj \ + $(OBJ)\pkinit-ec.obj \ + $(OBJ)\mssfu.obj \ + $(OBJ)\log.obj \ + $(OBJ)\misc.obj \ + $(OBJ)\kx509.obj \ + $(OBJ)\token_validator.obj \ + $(OBJ)\csr_authorizer.obj \ + $(OBJ)\process.obj \ + $(OBJ)\kdc-plugin.obj \ + $(OBJ)\gss_preauth.obj + +LIBKDC_LIBS=\ + $(LIBHDB) \ + $(LIBGSS_PREAUTH) \ + $(LIBGSSAPI) \ + $(LIBHEIMBASE) \ + $(LIBHEIMDAL) \ + $(LIBHEIMNTLM) \ + $(LIB_openssl_crypto) \ + $(LIBROKEN) + +LIBKDCRES=$(OBJ)\libkdc-version.res + +$(LIBEXECDIR)\libkdc.dll: $(LIBKDC_OBJS) $(LIBKDC_LIBS) $(LIBKDCRES) + $(DLLGUILINK) -implib:$(LIBKDC) -def:libkdc-exports.def + $(DLLPREP_NODIST) + +$(LIBKDC): $(LIBEXECDIR)\libkdc.dll + +clean:: + -$(RM) $(LIBEXECDIR)\libkdc.* + +libkdc_la_SOURCES = \ + default_config.c \ + ca.c \ + set_dbinfo.c \ + digest.c \ + fast.c \ + kdc_locl.h \ + kerberos5.c \ + krb5tgs.c \ + pkinit.c \ + pkinit-ec.c \ + mssfu.c \ + log.c \ + misc.c \ + kx509.c \ + token_validator.c \ + csr_authorizer.c \ + process.c \ + kdc-plugin.c \ + gss_preauth.c + +$(OBJ)\kdc-protos.h: $(libkdc_la_SOURCES) + cd $(SRCDIR) + $(PERL) ..\cf\make-proto.pl -E KDC_LIB -q -P remove -o $@ $(libkdc_la_SOURCES) \ + || $(RM) $@ + +$(OBJ)\kdc-private.h: $(libkdc_la_SOURCES) + $(PERL) ..\cf\make-proto.pl -q -P remove -p $@ $(libkdc_la_SOURCES) \ + || $(RM) $@ diff --git a/kdc/altsecid_gss_preauth_authorizer.c b/kdc/altsecid_gss_preauth_authorizer.c new file mode 100644 index 000000000..17d3ee31b --- /dev/null +++ b/kdc/altsecid_gss_preauth_authorizer.c @@ -0,0 +1,548 @@ +/* + * Copyright (c) 2021, PADL Software Pty Ltd. + * All rights reserved. + * + * Portions Copyright (c) 2004 Kungliga Tekniska Högskolan + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This plugin authorizes federated GSS-API pre-authentication clients by + * querying an AD DC in the KDC realm for the altSecurityIdentities + * attribute. + * + * For example, GSS-API initiator foo@AAA.H5L.SE using the eap-aes128 + * mechanism to authenticate in realm H5L.SE would require a user entry + * where altSecurityIdentities equals either: + * + * EAP:foo@AAA.H5L.SE + * EAP-AES128:foo@AAA.H5L.SE + * + * (Stripping the mechanism name after the hyphen is a convention + * intended to allow mechanism variants to be grouped together.) + * + * Once the user entry is found, the name is canonicalized by reading the + * sAMAccountName attribute and concatenating it with the KDC realm, + * specifically the canonicalized realm of the WELLKNOWN/FEDERATED HDB + * entry. + * + * The KDC will need to have access to a default credentials cache, or + * OpenLDAP will need to be linked against a version of Cyrus SASL and + * Heimdal that supports keytab credentials. + */ + +#include "kdc_locl.h" + +#include +#include +#include + +#include +#include + +#include + +#include "gss_preauth_authorizer_plugin.h" + +#ifndef PAC_REQUESTOR_SID +#define PAC_REQUESTOR_SID 18 +#endif + +struct ad_server_tuple { + HEIM_TAILQ_ENTRY(ad_server_tuple) link; + char *realm; + LDAP *ld; +#ifdef LDAP_OPT_X_SASL_GSS_CREDS + gss_cred_id_t gss_cred; +#endif +}; + +struct altsecid_gss_preauth_authorizer_context { + HEIM_TAILQ_HEAD(ad_server_tuple_list, ad_server_tuple) servers; +}; + +static int +sasl_interact(LDAP *ld, unsigned flags, void *defaults, void *interact) +{ + return LDAP_SUCCESS; +} + +#ifdef LDAP_OPT_X_SASL_GSS_CREDS +static krb5_error_code +ad_acquire_cred(krb5_context context, + krb5_const_realm realm, + struct ad_server_tuple *server) +{ + const char *keytab_name = NULL; + char *keytab_name_buf = NULL; + krb5_error_code ret; + + OM_uint32 major, minor; + gss_key_value_element_desc client_keytab; + gss_key_value_set_desc cred_store; + gss_OID_set_desc desired_mechs; + + desired_mechs.count = 1; + desired_mechs.elements = GSS_KRB5_MECHANISM; + + keytab_name = krb5_config_get_string(context, NULL, "kdc", realm, + "gss_altsecid_authorizer_keytab_name", NULL); + if (keytab_name == NULL) + keytab_name = krb5_config_get_string(context, NULL, "kdc", + "gss_altsecid_authorizer_keytab_name", NULL); + if (keytab_name == NULL) { + ret = _krb5_kt_client_default_name(context, &keytab_name_buf); + if (ret) + return ret; + + keytab_name = keytab_name_buf; + } + + client_keytab.key = "client_keytab"; + client_keytab.value = keytab_name; + + cred_store.count = 1; + cred_store.elements = &client_keytab; + + major = gss_acquire_cred_from(&minor, GSS_C_NO_NAME, GSS_C_INDEFINITE, + &desired_mechs, GSS_C_INITIATE, + &cred_store, &server->gss_cred, NULL, NULL); + if (GSS_ERROR(major)) + ret = minor ? minor : KRB5_KT_NOTFOUND; + else + ret = 0; + + krb5_xfree(keytab_name_buf); + + return ret; +} +#endif + +static krb5_boolean +is_recoverable_ldap_err_p(int lret) +{ + return + (lret == LDAP_SERVER_DOWN || + lret == LDAP_TIMEOUT || + lret == LDAP_UNAVAILABLE || + lret == LDAP_BUSY || + lret == LDAP_CONNECT_ERROR); +} + +static krb5_error_code +ad_connect(krb5_context context, + krb5_const_realm realm, + struct ad_server_tuple *server) +{ + krb5_error_code ret; + struct { + char *server; + int port; + } *s, *servers = NULL; + size_t i, num_servers = 0; + + if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns", + NULL)) { + ret = KRB5KDC_ERR_SVC_UNAVAILABLE; + krb5_set_error_message(context, ret, "DNS blocked when finding AD DC"); + return ret; + } + + { + struct rk_dns_reply *r; + struct rk_resource_record *rr; + char *domain; + + asprintf(&domain, "_ldap._tcp.%s", realm); + if (domain == NULL) { + ret = krb5_enomem(context); + goto out; + } + + r = rk_dns_lookup(domain, "SRV"); + free(domain); + if (r == NULL) { + krb5_set_error_message(context, KRB5KDC_ERR_SVC_UNAVAILABLE, + "Couldn't find AD DC in DNS"); + ret = KRB5KDC_ERR_SVC_UNAVAILABLE; + goto out; + } + + for (rr = r->head ; rr != NULL; rr = rr->next) { + if (rr->type != rk_ns_t_srv) + continue; + s = realloc(servers, sizeof(*servers) * (num_servers + 1)); + if (s == NULL) { + ret = krb5_enomem(context); + rk_dns_free_data(r); + goto out; + } + servers = s; + num_servers++; + servers[num_servers - 1].port = rr->u.srv->port; + servers[num_servers - 1].server = strdup(rr->u.srv->target); + } + rk_dns_free_data(r); + } + +#ifdef LDAP_OPT_X_SASL_GSS_CREDS + if (server->gss_cred == GSS_C_NO_CREDENTIAL) { + ret = ad_acquire_cred(context, realm, server); + if (ret) + goto out; + } +#endif + + for (i = 0; i < num_servers; i++) { + int lret, version = LDAP_VERSION3; + LDAP *ld; + char *url = NULL; + + asprintf(&url, "ldap://%s:%d", servers[i].server, servers[i].port); + if (url == NULL) { + ret = krb5_enomem(context); + goto out; + } + + lret = ldap_initialize(&ld, url); + free(url); + if (lret != LDAP_SUCCESS) + continue; + + ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version); + ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); +#ifdef LDAP_OPT_X_SASL_GSS_CREDS + ldap_set_option(ld, LDAP_OPT_X_SASL_GSS_CREDS, server->gss_cred); +#endif + + lret = ldap_sasl_interactive_bind_s(ld, NULL, "GSS-SPNEGO", + NULL, NULL, LDAP_SASL_QUIET, + sasl_interact, NULL); + if (lret != LDAP_SUCCESS) { + krb5_set_error_message(context, 0, + "Couldn't bind to AD DC %s:%d: %s", + servers[i].server, servers[i].port, + ldap_err2string(lret)); + ldap_unbind_ext_s(ld, NULL, NULL); + continue; + } + + server->ld = ld; + break; + } + + ret = (server->ld != NULL) ? 0 : KRB5_KDC_UNREACH; + +out: + for (i = 0; i < num_servers; i++) + free(servers[i].server); + free(servers); + + if (ret && server->ld) { + ldap_unbind_ext_s(server->ld, NULL, NULL); + server->ld = NULL; + } + + return ret; +} + +static krb5_error_code +ad_lookup(krb5_context context, + krb5_const_realm realm, + struct ad_server_tuple *server, + gss_const_name_t initiator_name, + gss_const_OID mech_type, + krb5_principal *canon_principal, + kdc_data_t *requestor_sid) +{ + krb5_error_code ret; + OM_uint32 minor; + const char *mech_type_str, *p; + char *filter = NULL; + gss_buffer_desc initiator_name_buf = GSS_C_EMPTY_BUFFER; + LDAPMessage *m = NULL, *m0; + char *basedn = NULL; + int lret; + char *attrs[] = { "sAMAccountName", "objectSid", NULL }; + struct berval **values = NULL; + + *canon_principal = NULL; + if (requestor_sid) + *requestor_sid = NULL; + + mech_type_str = gss_oid_to_name(mech_type); + if (mech_type_str == NULL) { + ret = KRB5_PREAUTH_BAD_TYPE; /* should never happen */ + goto out; + } + + ret = KRB5_KDC_ERR_CLIENT_NOT_TRUSTED; + + if (GSS_ERROR(gss_display_name(&minor, initiator_name, + &initiator_name_buf, NULL))) + goto out; + + if ((p = strrchr(mech_type_str, '-')) != NULL) { + asprintf(&filter, "(&(objectClass=user)" + "(|(altSecurityIdentities=%.*s:%.*s)(altSecurityIdentities=%s:%.*s)))", + (int)(p - mech_type_str), mech_type_str, + (int)initiator_name_buf.length, (char *)initiator_name_buf.value, + mech_type_str, + (int)initiator_name_buf.length, + (char *)initiator_name_buf.value); + } else { + asprintf(&filter, "(&(objectClass=user)(altSecurityIdentities=%s:%.*s))", + mech_type_str, + (int)initiator_name_buf.length, + (char *)initiator_name_buf.value); + } + if (filter == NULL) + goto enomem; + + lret = ldap_domain2dn(realm, &basedn); + if (lret != LDAP_SUCCESS) + goto out; + + lret = ldap_search_ext_s(server->ld, basedn, LDAP_SCOPE_SUBTREE, + filter, attrs, 0, + NULL, NULL, NULL, 1, &m); + if (lret == LDAP_SIZELIMIT_EXCEEDED) + ret = KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE; + else if (is_recoverable_ldap_err_p(lret)) + ret = KRB5KDC_ERR_SVC_UNAVAILABLE; + if (lret != LDAP_SUCCESS) + goto out; + + m0 = ldap_first_entry(server->ld, m); + if (m0 == NULL) + goto out; + + values = ldap_get_values_len(server->ld, m0, "sAMAccountName"); + if (values == NULL || + ldap_count_values_len(values) == 0) + goto out; + + ret = krb5_make_principal(context, canon_principal, realm, + values[0]->bv_val, NULL); + if (ret) + goto out; + + if (requestor_sid) { + ldap_value_free_len(values); + + values = ldap_get_values_len(server->ld, m0, "objectSid"); + if (values == NULL || + ldap_count_values_len(values) == 0) + goto out; + + *requestor_sid = kdc_data_create(values[0]->bv_val, values[0]->bv_len); + if (*requestor_sid == NULL) + goto enomem; + } + + goto out; + +enomem: + ret = krb5_enomem(context); + goto out; + +out: + if (ret) { + krb5_free_principal(context, *canon_principal); + *canon_principal = NULL; + + if (requestor_sid) { + kdc_object_release(*requestor_sid); + *requestor_sid = NULL; + } + } + + ldap_value_free_len(values); + ldap_msgfree(m); + ldap_memfree(basedn); + free(filter); + gss_release_buffer(&minor, &initiator_name_buf); + + return ret; +} + +static KRB5_LIB_CALL krb5_error_code +authorize(void *ctx, + astgs_request_t r, + gss_const_name_t initiator_name, + gss_const_OID mech_type, + OM_uint32 ret_flags, + krb5_boolean *authorized, + krb5_principal *mapped_name) +{ + struct altsecid_gss_preauth_authorizer_context *c = ctx; + struct ad_server_tuple *server = NULL; + krb5_error_code ret; + krb5_context context = kdc_request_get_context((kdc_request_t)r); + const hdb_entry *client = kdc_request_get_client(r); + krb5_const_principal server_princ = kdc_request_get_server_princ(r); + krb5_const_realm realm = krb5_principal_get_realm(context, client->principal); + krb5_boolean reconnect_p = FALSE; + krb5_boolean is_tgs; + kdc_data_t requestor_sid = NULL; + + *authorized = FALSE; + *mapped_name = NULL; + + if (!krb5_principal_is_federated(context, client->principal) || + (ret_flags & GSS_C_ANON_FLAG)) + return KRB5_PLUGIN_NO_HANDLE; + + is_tgs = krb5_principal_is_krbtgt(context, server_princ); + + HEIM_TAILQ_FOREACH(server, &c->servers, link) { + if (strcmp(realm, server->realm) == 0) + break; + } + + if (server == NULL) { + server = calloc(1, sizeof(*server)); + if (server == NULL) + return krb5_enomem(context); + + server->realm = strdup(realm); + if (server->realm == NULL) { + free(server); + return krb5_enomem(context); + } + + HEIM_TAILQ_INSERT_HEAD(&c->servers, server, link); + } + + do { + if (server->ld == NULL) { + ret = ad_connect(context, realm, server); + if (ret) + return ret; + } + + ret = ad_lookup(context, realm, server, + initiator_name, mech_type, + mapped_name, is_tgs ? &requestor_sid : NULL); + if (ret == KRB5KDC_ERR_SVC_UNAVAILABLE) { + ldap_unbind_ext_s(server->ld, NULL, NULL); + server->ld = NULL; + + /* try to reconnect iff we haven't already tried */ + reconnect_p = !reconnect_p; + } + + *authorized = (ret == 0); + } while (reconnect_p); + + if (requestor_sid) { + kdc_request_set_attribute((kdc_request_t)r, + HSTR("org.h5l.gss-pa-requestor-sid"), requestor_sid); + kdc_object_release(requestor_sid); + } + + return ret; +} + +static KRB5_LIB_CALL krb5_error_code +finalize_pac(void *ctx, astgs_request_t r) +{ + kdc_data_t requestor_sid; + + requestor_sid = kdc_request_get_attribute((kdc_request_t)r, + HSTR("org.h5l.gss-pa-requestor-sid")); + if (requestor_sid == NULL) + return 0; + + kdc_audit_setkv_object((kdc_request_t)r, "gss_requestor_sid", requestor_sid); + + return kdc_request_add_pac_buffer(r, PAC_REQUESTOR_SID, + kdc_data_get_data(requestor_sid)); +} + +static KRB5_LIB_CALL krb5_error_code +init(krb5_context context, void **contextp) +{ + struct altsecid_gss_preauth_authorizer_context *c; + + c = calloc(1, sizeof(*c)); + if (c == NULL) + return krb5_enomem(context); + + HEIM_TAILQ_INIT(&c->servers); + + *contextp = c; + return 0; +} + +static KRB5_LIB_CALL void +fini(void *context) +{ + struct altsecid_gss_preauth_authorizer_context *c = context; + struct ad_server_tuple *server, *next; + OM_uint32 minor; + + HEIM_TAILQ_FOREACH_SAFE(server, &c->servers, link, next) { + free(server->realm); + ldap_unbind_ext_s(server->ld, NULL, NULL); +#ifdef LDAP_OPT_X_SASL_GSS_CREDS + gss_release_cred(&minor, &server->gss_cred); +#endif + free(server); + } +} + +static krb5plugin_gss_preauth_authorizer_ftable plug_desc = + { 1, init, fini, authorize, finalize_pac }; + +static krb5plugin_gss_preauth_authorizer_ftable *plugs[] = { &plug_desc }; + +static uintptr_t +altsecid_gss_preauth_authorizer_get_instance(const char *libname) +{ + if (strcmp(libname, "krb5") == 0) + return krb5_get_instance(libname); + if (strcmp(libname, "kdc") == 0) + return kdc_get_instance(libname); + return 0; +} + +krb5_plugin_load_ft kdc_gss_preauth_authorizer_plugin_load; + +krb5_error_code KRB5_CALLCONV +kdc_gss_preauth_authorizer_plugin_load(heim_pcontext context, + krb5_get_instance_func_t *get_instance, + size_t *num_plugins, + krb5_plugin_common_ftable_cp **plugins) +{ + *get_instance = altsecid_gss_preauth_authorizer_get_instance; + *num_plugins = sizeof(plugs) / sizeof(plugs[0]); + *plugins = (krb5_plugin_common_ftable_cp *)plugs; + return 0; +} diff --git a/kdc/announce.c b/kdc/announce.c new file mode 100644 index 000000000..cf3fdc363 --- /dev/null +++ b/kdc/announce.c @@ -0,0 +1,544 @@ +/* + * Copyright (c) 2008 Apple Inc. All Rights Reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of Apple Inc. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Apple Inc. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#include "kdc_locl.h" + +#if defined(__APPLE__) && defined(HAVE_GCD) + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +static krb5_kdc_configuration *announce_config; +static krb5_context announce_context; + +struct entry { + DNSRecordRef recordRef; + char *domain; + char *realm; +#define F_EXISTS 1 +#define F_PUSH 2 + int flags; + struct entry *next; +}; + +/* #define REGISTER_SRV_RR */ + +static struct entry *g_entries = NULL; +static CFStringRef g_hostname = NULL; +static DNSServiceRef g_dnsRef = NULL; +static SCDynamicStoreRef g_store = NULL; +static dispatch_queue_t g_queue = NULL; + +#define LOG(...) asl_log(NULL, NULL, ASL_LEVEL_INFO, __VA_ARGS__) + +static void create_dns_sd(void); +static void destroy_dns_sd(void); +static void update_all(SCDynamicStoreRef, CFArrayRef, void *); + + +/* parameters */ +static CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac"); + + +static char * +CFString2utf8(CFStringRef string) +{ + size_t size; + char *str; + + size = 1 + CFStringGetMaximumSizeForEncoding(CFStringGetLength(string), kCFStringEncodingUTF8); + str = malloc(size); + if (str == NULL) + return NULL; + + if (CFStringGetCString(string, str, size, kCFStringEncodingUTF8) == false) { + free(str); + return NULL; + } + return str; +} + +/* + * + */ + +static void +retry_timer(void) +{ + dispatch_source_t s; + dispatch_time_t t; + + s = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, + 0, 0, g_queue); + t = dispatch_time(DISPATCH_TIME_NOW, 5ull * NSEC_PER_SEC); + dispatch_source_set_timer(s, t, 0, NSEC_PER_SEC); + dispatch_source_set_event_handler(s, ^{ + create_dns_sd(); + dispatch_release(s); + }); + dispatch_resume(s); +} + +/* + * + */ + +static void +create_dns_sd(void) +{ + DNSServiceErrorType error; + dispatch_source_t s; + + error = DNSServiceCreateConnection(&g_dnsRef); + if (error) { + retry_timer(); + return; + } + + dispatch_suspend(g_queue); + + s = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, + DNSServiceRefSockFD(g_dnsRef), + 0, g_queue); + + dispatch_source_set_event_handler(s, ^{ + DNSServiceErrorType ret = DNSServiceProcessResult(g_dnsRef); + /* on error tear down and set timer to recreate */ + if (ret != kDNSServiceErr_NoError && ret != kDNSServiceErr_Transient) { + dispatch_source_cancel(s); + } + }); + + dispatch_source_set_cancel_handler(s, ^{ + destroy_dns_sd(); + retry_timer(); + dispatch_release(s); + }); + + dispatch_resume(s); + + /* Do the first update ourself */ + update_all(g_store, NULL, NULL); + dispatch_resume(g_queue); +} + +static void +domain_add(const char *domain, const char *realm, int flag) +{ + struct entry *e; + + for (e = g_entries; e != NULL; e = e->next) { + if (strcmp(domain, e->domain) == 0 && strcmp(realm, e->realm) == 0) { + e->flags |= flag; + return; + } + } + + LOG("Adding realm %s to domain %s", realm, domain); + + e = calloc(1, sizeof(*e)); + if (e == NULL) + return; + e->domain = strdup(domain); + e->realm = strdup(realm); + if (e->domain == NULL || e->realm == NULL) { + free(e->domain); + free(e->realm); + free(e); + return; + } + e->flags = flag | F_PUSH; /* if we allocate, we push */ + e->next = g_entries; + g_entries = e; +} + +struct addctx { + int flags; + const char *realm; +}; + +static void +domains_add(const void *key, const void *value, void *context) +{ + char *str = CFString2utf8((CFStringRef)value); + struct addctx *ctx = context; + + if (str == NULL) + return; + if (str[0] != '\0') + domain_add(str, ctx->realm, F_EXISTS | ctx->flags); + free(str); +} + + +static void +dnsCallback(DNSServiceRef sdRef __attribute__((unused)), + DNSRecordRef RecordRef __attribute__((unused)), + DNSServiceFlags flags __attribute__((unused)), + DNSServiceErrorType errorCode __attribute__((unused)), + void *context __attribute__((unused))) +{ +} + +#ifdef REGISTER_SRV_RR + +/* + * Register DNS SRV rr for the realm. + */ + +static const char *register_names[2] = { + "_kerberos._tcp", + "_kerberos._udp" +}; + +static struct { + DNSRecordRef *val; + size_t len; +} srvRefs = { NULL, 0 }; + +static void +register_srv(const char *realm, const char *hostname, int port) +{ + unsigned char target[1024]; + int i; + int size; + + /* skip registering LKDC realms */ + if (strncmp(realm, "LKDC:", 5) == 0) + return; + + /* encode SRV-RR */ + target[0] = 0; /* priority */ + target[1] = 0; /* priority */ + target[2] = 0; /* weight */ + target[3] = 0; /* weigth */ + target[4] = (port >> 8) & 0xff; /* port */ + target[5] = (port >> 0) & 0xff; /* port */ + + size = dn_comp(hostname, target + 6, sizeof(target) - 6, NULL, NULL); + if (size < 0) + return; + + size += 6; + + LOG("register SRV rr for realm %s hostname %s:%d", realm, hostname, port); + + for (i = 0; i < sizeof(register_names)/sizeof(register_names[0]); i++) { + char name[kDNSServiceMaxDomainName]; + DNSServiceErrorType error; + void *ptr; + + ptr = realloc(srvRefs.val, sizeof(srvRefs.val[0]) * (srvRefs.len + 1)); + if (ptr == NULL) + errx(1, "malloc: out of memory"); + srvRefs.val = ptr; + + DNSServiceConstructFullName(name, NULL, register_names[i], realm); + + error = DNSServiceRegisterRecord(g_dnsRef, + &srvRefs.val[srvRefs.len], + kDNSServiceFlagsUnique | kDNSServiceFlagsShareConnection, + 0, + name, + kDNSServiceType_SRV, + kDNSServiceClass_IN, + size, + target, + 0, + dnsCallback, + NULL); + if (error) { + LOG("Failed to register SRV rr for realm %s: %d", realm, error); + } else + srvRefs.len++; + } +} + +static void +unregister_srv_realms(void) +{ + if (g_dnsRef) { + for (i = 0; i < srvRefs.len; i++) + DNSServiceRemoveRecord(g_dnsRef, srvRefs.val[i], 0); + } + free(srvRefs.val); + srvRefs.len = 0; + srvRefs.val = NULL; +} + +static void +register_srv_realms(CFStringRef host) +{ + krb5_error_code ret; + char *hostname; + size_t i; + + /* first unregister old names */ + + hostname = CFString2utf8(host); + if (hostname == NULL) + return; + + for(i = 0; i < announce_config->num_db; i++) { + char **realms, **r; + + if (announce_config->db[i]->hdb_get_realms == NULL) + continue; + + ret = (announce_config->db[i]->hdb_get_realms)(announce_context, &realms); + if (ret == 0) { + for (r = realms; r && *r; r++) + register_srv(*r, hostname, 88); + krb5_free_host_realm(announce_context, realms); + } + } + + free(hostname); +} +#endif /* REGISTER_SRV_RR */ + +static void +update_dns(void) +{ + DNSServiceErrorType error; + struct entry **e = &g_entries; + char *hostname; + + hostname = CFString2utf8(g_hostname); + if (hostname == NULL) + return; + + while (*e != NULL) { + /* remove if this wasn't updated */ + if (((*e)->flags & F_EXISTS) == 0) { + struct entry *drop = *e; + *e = (*e)->next; + + LOG("Deleting realm %s from domain %s", + drop->realm, drop->domain); + + if (drop->recordRef && g_dnsRef) + DNSServiceRemoveRecord(g_dnsRef, drop->recordRef, 0); + free(drop->domain); + free(drop->realm); + free(drop); + continue; + } + if ((*e)->flags & F_PUSH) { + struct entry *update = *e; + char *dnsdata, *name; + size_t len; + + len = strlen(update->realm); + asprintf(&dnsdata, "%c%s", (int)len, update->realm); + if (dnsdata == NULL) + errx(1, "malloc"); + + asprintf(&name, "_kerberos.%s.%s", hostname, update->domain); + if (name == NULL) + errx(1, "malloc"); + + if (update->recordRef) + DNSServiceRemoveRecord(g_dnsRef, update->recordRef, 0); + + error = DNSServiceRegisterRecord(g_dnsRef, + &update->recordRef, + kDNSServiceFlagsShared | kDNSServiceFlagsAllowRemoteQuery, + 0, + name, + kDNSServiceType_TXT, + kDNSServiceClass_IN, + len+1, + dnsdata, + 0, + dnsCallback, + NULL); + free(name); + free(dnsdata); + if (error) + errx(1, "failure to update entry for %s/%s", + update->domain, update->realm); + } + e = &(*e)->next; + } + free(hostname); +} + +static void +update_entries(SCDynamicStoreRef store, const char *realm, int flags) +{ + CFDictionaryRef btmm; + + /* we always announce in the local domain */ + domain_add("local", realm, F_EXISTS | flags); + + /* announce btmm */ + btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac); + if (btmm) { + struct addctx addctx; + + addctx.flags = flags; + addctx.realm = realm; + + CFDictionaryApplyFunction(btmm, domains_add, &addctx); + CFRelease(btmm); + } +} + +static void +update_all(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info) +{ + struct entry *e; + CFStringRef host; + int i, flags = 0; + + LOG("something changed, running update"); + + host = SCDynamicStoreCopyLocalHostName(store); + if (host == NULL) + return; + + if (g_hostname == NULL || CFStringCompare(host, g_hostname, 0) != kCFCompareEqualTo) { + if (g_hostname) + CFRelease(g_hostname); + g_hostname = CFRetain(host); + flags = F_PUSH; /* if hostname has changed, force push */ + +#ifdef REGISTER_SRV_RR + register_srv_realms(g_hostname); +#endif + } + + for (e = g_entries; e != NULL; e = e->next) + e->flags &= ~(F_EXISTS|F_PUSH); + + for(i = 0; i < announce_config->num_db; i++) { + krb5_error_code ret; + char **realms, **r; + + if (announce_config->db[i]->hdb_get_realms == NULL) + continue; + + ret = (announce_config->db[i]->hdb_get_realms)(announce_context, announce_config->db[i], &realms); + if (ret == 0) { + for (r = realms; r && *r; r++) + update_entries(store, *r, flags); + krb5_free_host_realm(announce_context, realms); + } + } + + update_dns(); + + CFRelease(host); +} + +static void +delete_all(void) +{ + struct entry *e; + + for (e = g_entries; e != NULL; e = e->next) + e->flags &= ~(F_EXISTS|F_PUSH); + + update_dns(); + if (g_entries != NULL) + errx(1, "Failed to remove all bonjour entries"); +} + +static void +destroy_dns_sd(void) +{ + if (g_dnsRef == NULL) + return; + + delete_all(); +#ifdef REGISTER_SRV_RR + unregister_srv_realms(); +#endif + + DNSServiceRefDeallocate(g_dnsRef); + g_dnsRef = NULL; +} + + +static SCDynamicStoreRef +register_notification(void) +{ + SCDynamicStoreRef store; + CFStringRef computerNameKey; + CFMutableArrayRef keys; + + computerNameKey = SCDynamicStoreKeyCreateHostNames(kCFAllocatorDefault); + + store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("Network watcher"), + update_all, NULL); + if (store == NULL) + errx(1, "SCDynamicStoreCreate"); + + keys = CFArrayCreateMutable(kCFAllocatorDefault, 2, &kCFTypeArrayCallBacks); + if (keys == NULL) + errx(1, "CFArrayCreateMutable"); + + CFArrayAppendValue(keys, computerNameKey); + CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac); + + if (SCDynamicStoreSetNotificationKeys(store, keys, NULL) == false) + errx(1, "SCDynamicStoreSetNotificationKeys"); + + CFRelease(computerNameKey); + CFRelease(keys); + + if (!SCDynamicStoreSetDispatchQueue(store, g_queue)) + errx(1, "SCDynamicStoreSetDispatchQueue"); + + return store; +} +#endif + +void +bonjour_announce(krb5_context context, krb5_kdc_configuration *config) +{ +#if defined(__APPLE__) && defined(HAVE_GCD) + g_queue = dispatch_queue_create("com.apple.kdc_announce", NULL); + if (!g_queue) + errx(1, "dispatch_queue_create"); + + g_store = register_notification(); + announce_config = config; + announce_context = context; + + create_dns_sd(); +#endif +} diff --git a/kdc/bx509d.8 b/kdc/bx509d.8 new file mode 100644 index 000000000..f94015568 --- /dev/null +++ b/kdc/bx509d.8 @@ -0,0 +1,480 @@ +.\" Copyright (c) 2020 Kungliga Tekniska Högskolan +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.Dd January 2, 2020 +.Dt BX509 8 +.Os HEIMDAL +.Sh NAME +.Nm bx509d +.Nd Authentication Bridge for Bearer tokens, Kerberos, and PKIX +.Sh SYNOPSIS +.Nm +.Op Fl h | Fl Fl help +.Op Fl Fl version +.Op Fl H Ar HOSTNAME +.Op Fl d | Fl Fl daemon +.Op Fl Fl allow-GET +.Op Fl Fl no-allow-GET +.Op Fl Fl csrf-protection-type= Ns Ar CSRF-PROTECTION-TYPE +.Op Fl Fl csrf-header= Ns Ar HEADER-NAME +.Op Fl Fl csrf-key-file= Ns Ar FILE +.Op Fl Fl reverse-proxied +.Op Fl p Ar port number (default: 443) +.Op Fl Fl cache-dir= Ns Ar DIRECTORY +.Op Fl Fl cert= Ns Ar HX509-STORE +.Op Fl Fl private-key= Ns Ar HX509-STORE +.Op Fl t | Fl Fl thread-per-client +.Oo Fl v \*(Ba Xo +.Fl Fl verbose= Ns Ar run verbosely +.Xc +.Oc +.Sh DESCRIPTION +Serves RESTful (HTTPS) GETs of +.Ar /get-cert , +.Ar /get-tgt , +.Ar /get-tgts , +and +.Ar /get-negotiate-token , +end-points that implement various experimental Heimdal features: +.Bl -bullet -compact -offset indent +.It +.Li an online CA service over HTTPS, +.It +.Li a kinit-over-HTTPS service, and +.It +.Li a Negotiate token over HTTPS service. +.El +.Pp +As well, a +.Ar /health +service can be used for checking service status. +.Pp +Supported options: +.Bl -tag -width Ds +.It Xo +.Fl h , +.Fl Fl help +.Xc +Print usage message. +.It Xo +.Fl Fl version +.Xc +Print version. +.It Xo +.Fl H Ar HOSTNAME +.Xc +Expected audience(s) of bearer tokens (i.e., acceptor name). +.It Xo +.Fl Fl allow-GET +.Xc +If given, then HTTP GET will be allowed for the various +end-points other than +.Ar /health . +Otherwise only HEAD and POST will be allowed. +By default GETs are allowed, but this will change soon. +.It Xo +.Fl Fl no-allow-GET +.Xc +If given then HTTP GETs will be rejected for the various +end-points other than +.Ar /health . +.It Xo +.Fl Fl csrf-protection-type= Ns Ar CSRF-PROTECTION-TYPE +.Xc +Possible values of +.Ar CSRF-PROTECTION-TYPE +are +.Bl -bullet -compact -offset indent +.It +.Li GET-with-header +.It +.Li GET-with-token +.It +.Li POST-with-header +.It +.Li POST-with-token +.El +This may be given multiple times. +The default is to require CSRF tokens for POST requests, and to +require neither a non-simple header nor a CSRF token for GET +requests. +.Pp +See +.Sx CROSS-SITE REQUEST FORGERY PROTECTION . +.It Xo +.Fl Fl csrf-header= Ns Ar HEADER-NAME +.Xc +If given, then all requests other than to the +.Ar /health +service must have the given request +.Ar HEADER-NAME +set (the value is irrelevant). +The +.Ar HEADER-NAME +must be a request header name such that a request having it makes +it not a +.Dq simple +request (see the Cross-Origin Resource Sharing specification). +Defaults to +.Ar X-CSRF . +.It Xo +.Fl Fl csrf-key-file= Ns Ar FILE +.Xc +If given, this file must contain a 16 byte binary key for keying +the HMAC used in CSRF token construction. +.It Xo +.Fl d , +.Fl Fl daemon +.Xc +Detach from TTY and run in the background. +.It Xo +.Fl Fl reverse-proxied +.Xc +Serves HTTP instead of HTTPS, accepting only looped-back +connections. +.It Xo +.Fl p Ar port number (default: 443) +.Xc +PORT +.It Xo +.Fl Fl cache-dir= Ns Ar DIRECTORY +.Xc +Directory for various caches. +If not specified then a temporary directory will be made. +.It Xo +.Fl Fl cert= Ns Ar HX509-STORE +.Xc +Certificate file path (PEM) for HTTPS service. +May contain private key as well. +.It Xo +.Fl Fl private-key= Ns Ar HX509-STORE +.Xc +Private key file path (PEM), if the private key is not stored +along with the certificiate. +.It Xo +.Fl t , +.Fl Fl thread-per-client +.Xc +Uses a thread per-client instead of as many threads as there are +CPUs. +.It Xo +.Fl v , +.Fl Fl verbose= Ns Ar run verbosely +.Xc +verbose +.El +.Sh HTTP APIS +All HTTP APIs served by this program accept POSTs, with all +request parameters given as URI query parameters and/or as +form data in the POST request body, in either +.Ar application/x-www-form-urlencoded +or +.Ar multipart/formdata . +If request parameters are given both as URI query parameters +and as POST forms, then they are merged into a set. +.Pp +If GETs are enabled, then request parameters must be supplied +only as URI query parameters, as GET requests do not have request +bodies. +.Pp +URI query parameters must be of the form +.Ar param0=value¶m1=value... +.Pp +Some request parameters can only have one value. +If multiple values are given for such parameters, then either an +error will be produced, or only the first URI query parameter +value will be used, or the first POST form data parameter will be +used. +Other request parameters can have multiple values. +See below. +.Sh CROSS-SITE REQUEST FORGERY PROTECTION +.Em None +of the resources service by this service are intended to be +executed by web pages. +.Pp +All the resources provided by this service are +.Dq safe +in the sense that they do not change server-side state besides +logging, and in that they are idempotent, but they are +only safe to execute +.Em if and only if +the requesting party is trusted to see the response. +Since none of these resources are intended to be used from web +pages, it is important that web pages not be able to execute them +.Em and +observe the responses. +.Pp +In a web browser context, pages from other origins will be able +to attempt requests to this service, but should never be able to +see the responses because browsers normally wouldn't allow that. +Nonetheless, anti cross site request forgery (CSRF) protection +may be desirable. +.Pp +This service provides the following CSRF protection features: +.Bl -tag -width Ds -offset indent +.It requests are rejected if they have a +.Dq Referer +(except the experimental /get-negotiate-token end-point) +.It the service can be configured to require a header that would make the +request not Dq simple +.It GETs can be disabled (see options), thus requiring POSTs +.It GETs can be required to have a CSRF token (see below) +.It POSTs can be required to have a CSRF token +.El +.Pp +The experimental +.Ar /get-negotiate-token +end-point, however, always accepts +.Dq Referer +requests. +.Pp +To obtain a CSRF token, first execute the request without the +CSRF token, and the resulting error +response will include a +.Ar X-CSRF-Token +response header. +.Pp +To execute a request with a CSRF token, first obtain a CSRF token +as described above, then copy the token to the request as the +value of the request's +.Ar X-CSRF-Token +header. +.Sh ONLINE CERTIFICATION AUTHORITY HTTP API +This service provides an HTTP-based Certification Authority (CA). +CA credentials and configuration are specified in the +.Va [bx509] +section of +.Xr krb5.conf 5 . +.Pp +The protocol consists of a +.Ar GET +of +.Ar /get-cert +with the base-63 encoding of a DER encoding of a PKCS#10 +.Ar CertificationRequest +(Certificate Signing Request, or CSR) in a +.Ar csr +required request parameter. +In a successful request, the response body will contain a PEM +encoded end entity certificate and certification chain. +.Pp +Or +.Ar GET +of +.Ar /bx509 , +as this used to be called. +.Pp +Authentication is required. +Unauthenticated requests will elicit a 401 response. +.Pp +Authorization is required. +Unauthorized requests will elicit a 403 response. +.Pp +Subject Alternative Names (SANs) and Extended Key Usage values +may be requested, both in-band in the CSR as a requested +extensions attribute, and/or via optional request parameters. +.Pp +Supported request parameters: +.Bl -tag -width Ds -offset indent +.It Li csr = Va base64-encoded-DER-encoded-CSR +.It Li dNSName = Va hostname +.It Li rfc822Name = Va email-address +.It Li xMPPName = Va XMPP-address +.It Li krb5PrincipalName = Va Kerberos-principal-name +.It Li ms-upn = Va UPN +.It Li eku = Va OID +.It Li lifetime = Va lifetime +.El +.Pp +More than one name or EKU may be requested. +.Pp +Certificate lifetimes are expressed as a decimal number and +an optional unit (which defaults to +.Dq day +). +.Sh NEGOTIATE TOKEN HTTP API +This service provides an HTTP-based Negotiate token service. +This service requires a certification authority (CA) issuer +credential as it impersonates client principals to the KDC using +PKINIT client certificates it issues itself. +.Pp +The protocol consists of a +.Ar GET +of +.Ar /get-negotiate-token +with a +.Ar target = Ar service@host +request parameter. +.Pp +In a successful request, the response body will contain a +Negotiate token for the authenticated client principal to the +requested target. +.Pp +Authentication is required. +Unauthenticated requests will elicit a 401 response. +.Pp +Subject Alternative Names (SANs) and Extended Key Usage values +may be requested, both in-band in the CSR as a requested +extensions attribute, and/or via optional request parameters. +.Pp +Supported request parameters: +.Bl -tag -width Ds -offset indent +.It Li target = Va service@hostname +.It Li redirect = Va URI +.El +.Pp +If a redirect URI is given and a matching +.Va Referer +header is included in the request, then the response will be a +redirect to that URI with the Negotiate token in an +.Va Authorization +header that the user-agent should copy to the redirected request. +.Pp +The certification authority configuration is the same as for the +.Va /get-cert +end-point, but as configured in the +.Va [get-tgt] +section of +.Xr krb5.conf 5 . +.Sh TGT HTTP API +This service provides an HTTP-based "kinit" service. +This service requires a certification authority (CA) issuer +credential as it impersonates client principals to the KDC using +PKINIT client certificates it issues itself. +.Pp +The protocol consists of a +.Ar GET +of +.Ar /get-tgt . +.Pp +Supported request parameters: +.Bl -tag -width Ds -offset indent +.It Li cname = Va principal-name +.It Li address = Va IP-address +.It Li lifetime = Va relative-time +.El +.Pp +In a successful request, the response body will contain a TGT and +its session key encoded as a "ccache" file contents. +.Pp +Authentication is required. +Unauthenticated requests will elicit a 401 response. +.Pp +Authorization is required, where the authorization check is the +same as for +.Va /get-cert +by the authenticated client principal to get a certificate with +a PKINIT SAN for itself or the requested principal if a +.Va cname +request parameter was included. +.Pp +Unauthorized requests will elicit a 403 response. +.Pp +Requested IP addresses will be added to the issued TGT if +allowed. +The IP address of the client will be included if address-less +TGTs are not allowed. +See the +.Va [get-tgt] +section of +.Xr krb5.conf 5 . +.Pp +The certification authority configuration is the same as for the +.Va /get-cert +end-point, but as configured in the +.Va [get-tgt] +section of +.Xr krb5.conf 5 . +.Sh BATCH TGT HTTP API +Some sites may have special users that operate batch jobs systems +and that can impersonate many others by obtaining TGTs for them, +and which +.Dq prestash +credentials for those users in their credentials caches. +To support these sytems, a +.Ar GET +of +.Ar /get-tgts +with multiple +.Ar cname +request parameters will return those principals' TGTs (if the +caller is authorized). +.Pp +This is similar to the +.Ar /get-tgt +end-point, but a) multiple +.Ar cname +request parameter values may be given, and b) the caller's +principal name is not used as a default for the +.Ar cname +request parameter. +The +.Ar address +and +.Ar lifetime +request parameters are honored. +.Pp +For successful +.Ar GETs +the response body is a sequence of JSON texts each of which is a +JSON object with two keys: +.Bl -tag -width Ds -offset indent +.It Ar ccache +with a base64-encoded FILE-type ccache; +.It Ar name +the name of the principal whose credentials are in that ccache. +.El +.Sh NOTES +A future release may split all these end-points into separate +services. +.Sh ENVIRONMENT +.Bl -tag -width Ds +.It Ev KRB5_CONFIG +The file name of +.Pa krb5.conf , +the default being +.Pa /etc/krb5.conf . +.El +.Sh FILES +Configuration parameters are specified in +.Ar /etc/krb5.conf . +.Bl -tag -width Ds +.It Pa /etc/krb5.conf +.El +.\".Sh EXAMPLES +.Sh DIAGNOSTICS +See logging section of +.Nm krb5.conf.5 +.Sh SEE ALSO +.Xr krb5.conf 5 +.\".Sh STANDARDS +.\".Sh HISTORY +.\".Sh AUTHORS +.\".Sh BUGS diff --git a/kdc/bx509d.c b/kdc/bx509d.c new file mode 100644 index 000000000..793012baf --- /dev/null +++ b/kdc/bx509d.c @@ -0,0 +1,3175 @@ +/* + * Copyright (c) 2019 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file implements a RESTful HTTPS API to an online CA, as well as an + * HTTP/Negotiate token issuer, as well as a way to get TGTs. + * + * Users are authenticated with Negotiate and/or Bearer. + * + * This is essentially a RESTful online CA sharing some code with the KDC's + * kx509 online CA, and also a proxy for PKINIT and GSS-API (Negotiate). + * + * See the manual page for HTTP API details. + * + * TBD: + * - rewrite to not use libmicrohttpd but an alternative more appropriate to + * Heimdal's license (though libmicrohttpd will do) + * - there should be an end-point for fetching an issuer's chain + * + * NOTES: + * - We use krb5_error_code values as much as possible. Where we need to use + * MHD_NO because we got that from an mhd function and cannot respond with + * an HTTP response, we use (krb5_error_code)-1, and later map that to + * MHD_NO. + * + * (MHD_NO is an ENOMEM-cannot-even-make-a-static-503-response level event.) + */ + +/* + * Theory of operation: + * + * - We use libmicrohttpd (MHD) for the HTTP(S) implementation. + * + * - MHD has an online request processing model: + * + * - all requests are handled via the `dh' and `dh_cls' closure arguments + * of `MHD_start_daemon()'; ours is called `route()' + * + * - `dh' is called N+1 times: + * - once to allocate a request context + * - once for every N chunks of request body + * - once to process the request and produce a response + * + * - the response cannot begin to be produced before consuming the whole + * request body (for requests that have a body) + * (this seems like a bug in MHD) + * + * - the response body can be produced over multiple calls (i.e., in an + * online manner) + * + * - Our `route()' processes any POST request body form data / multipart by + * treating all the key/value pairs as if they had been additional URI query + * parameters. + * + * - Then `route()' calls a handler appropriate to the URI local-part with the + * request context, and the handler produces a response in one call. + * + * I.e., we turn the online MHD request processing into not-online. Our + * handlers are presented with complete requests and must produce complete + * responses in one call. + * + * - `route()' also does any authentication and CSRF protection so that the + * request handlers don't have to. + * + * This non-online request handling approach works for most everything we want + * to do. However, for /get-tgts with very large numbers of principals, we + * might have to revisit this, using MHD_create_response_from_callback() or + * MHD_create_response_from_pipe() (and a thread to do the actual work of + * producing the body) instead of MHD_create_response_from_buffer(). + */ + +#define _XOPEN_SOURCE_EXTENDED 1 +#define _DEFAULT_SOURCE 1 +#define _BSD_SOURCE 1 +#define _GNU_SOURCE 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "kdc_locl.h" +#include "token_validator_plugin.h" +#include +#include +#include +#include +#include +#include +#include "../lib/hx509/hx_locl.h" +#include + +#define heim_pcontext krb5_context +#define heim_pconfig krb5_context +#include + +#if MHD_VERSION < 0x00097002 || defined(MHD_YES) +/* libmicrohttpd changed these from int valued macros to an enum in 0.9.71 */ +#ifdef MHD_YES +#undef MHD_YES +#undef MHD_NO +#endif +enum MHD_Result { MHD_NO = 0, MHD_YES = 1 }; +#define MHD_YES 1 +#define MHD_NO 0 +typedef int heim_mhd_result; +#else +typedef enum MHD_Result heim_mhd_result; +#endif + +enum k5_creds_kind { K5_CREDS_EPHEMERAL, K5_CREDS_CACHED }; + +/* + * This is to keep track of memory we need to free, mainly because we had to + * duplicate data from the MHD POST form data processor. + */ +struct free_tend_list { + void *freeme1; + void *freeme2; + struct free_tend_list *next; +}; + +/* Per-request context data structure */ +typedef struct bx509_request_desc { + /* Common elements for Heimdal request/response services */ + HEIM_SVC_REQUEST_DESC_COMMON_ELEMENTS; + + struct MHD_Connection *connection; + struct MHD_PostProcessor *pp; + struct MHD_Response *response; + krb5_times token_times; + time_t req_life; + hx509_request req; + struct free_tend_list *free_list; + const char *for_cname; + const char *target; + const char *redir; + const char *method; + size_t post_data_size; + size_t san_idx; /* For /get-tgts */ + enum k5_creds_kind cckind; + char *pkix_store; + char *tgts_filename; + FILE *tgts; + char *ccname; + char *freeme1; + char *csrf_token; + krb5_addresses tgt_addresses; /* For /get-tgt */ + char frombuf[128]; +} *bx509_request_desc; + +static void +audit_trail(bx509_request_desc r, krb5_error_code ret) +{ + const char *retname = NULL; + + /* Get a symbolic name for some error codes */ +#define CASE(x) case x : retname = #x; break + switch (ret) { + CASE(ENOMEM); + CASE(EACCES); + CASE(HDB_ERR_NOT_FOUND_HERE); + CASE(HDB_ERR_WRONG_REALM); + CASE(HDB_ERR_EXISTS); + CASE(HDB_ERR_KVNO_NOT_FOUND); + CASE(HDB_ERR_NOENTRY); + CASE(HDB_ERR_NO_MKEY); + CASE(KRB5KDC_ERR_BADOPTION); + CASE(KRB5KDC_ERR_CANNOT_POSTDATE); + CASE(KRB5KDC_ERR_CLIENT_NOTYET); + CASE(KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN); + CASE(KRB5KDC_ERR_ETYPE_NOSUPP); + CASE(KRB5KDC_ERR_KEY_EXPIRED); + CASE(KRB5KDC_ERR_NAME_EXP); + CASE(KRB5KDC_ERR_NEVER_VALID); + CASE(KRB5KDC_ERR_NONE); + CASE(KRB5KDC_ERR_NULL_KEY); + CASE(KRB5KDC_ERR_PADATA_TYPE_NOSUPP); + CASE(KRB5KDC_ERR_POLICY); + CASE(KRB5KDC_ERR_PREAUTH_FAILED); + CASE(KRB5KDC_ERR_PREAUTH_REQUIRED); + CASE(KRB5KDC_ERR_SERVER_NOMATCH); + CASE(KRB5KDC_ERR_SERVICE_EXP); + CASE(KRB5KDC_ERR_SERVICE_NOTYET); + CASE(KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN); + CASE(KRB5KDC_ERR_TRTYPE_NOSUPP); + CASE(KRB5KRB_ERR_RESPONSE_TOO_BIG); + /* XXX Add relevant error codes */ + case 0: + retname = "SUCCESS"; + break; + default: + retname = NULL; + break; + } + + /* Let's save a few bytes */ + if (retname && strncmp("KRB5KDC_", retname, sizeof("KRB5KDC_") - 1) == 0) + retname += sizeof("KRB5KDC_") - 1; +#undef PREFIX + heim_audit_trail((heim_svc_req_desc)r, ret, retname); +} + +static krb5_log_facility *logfac; +static pthread_key_t k5ctx; + +static krb5_error_code +get_krb5_context(krb5_context *contextp) +{ + krb5_error_code ret; + + if ((*contextp = pthread_getspecific(k5ctx))) + return 0; + if ((ret = krb5_init_context(contextp))) + return *contextp = NULL, ret; + if (logfac) + krb5_set_log_dest(*contextp, logfac); + (void) pthread_setspecific(k5ctx, *contextp); + return *contextp ? 0 : ENOMEM; +} + +typedef enum { + CSRF_PROT_UNSPEC = 0, + CSRF_PROT_GET_WITH_HEADER = 1, + CSRF_PROT_GET_WITH_TOKEN = 2, + CSRF_PROT_POST_WITH_HEADER = 8, + CSRF_PROT_POST_WITH_TOKEN = 16, +} csrf_protection_type; + +static csrf_protection_type csrf_prot_type = CSRF_PROT_UNSPEC; +static int port = -1; +static int allow_GET_flag = -1; +static int help_flag; +static int daemonize; +static int daemon_child_fd = -1; +static int verbose_counter; +static int version_flag; +static int reverse_proxied_flag; +static int thread_per_client_flag; +struct getarg_strings audiences; +static getarg_strings csrf_prot_type_strs; +static const char *csrf_header = "X-CSRF"; +static const char *cert_file; +static const char *priv_key_file; +static const char *cache_dir; +static const char *csrf_key_file; +static char *impersonation_key_fn; + +static char csrf_key[16]; + +static krb5_error_code resp(struct bx509_request_desc *, int, + enum MHD_ResponseMemoryMode, const char *, + const void *, size_t, const char *); +static krb5_error_code bad_req(struct bx509_request_desc *, krb5_error_code, int, + const char *, ...) + HEIMDAL_PRINTF_ATTRIBUTE((__printf__, 4, 5)); + +static krb5_error_code bad_enomem(struct bx509_request_desc *, krb5_error_code); +static krb5_error_code bad_400(struct bx509_request_desc *, krb5_error_code, char *); +static krb5_error_code bad_401(struct bx509_request_desc *, char *); +static krb5_error_code bad_403(struct bx509_request_desc *, krb5_error_code, char *); +static krb5_error_code bad_404(struct bx509_request_desc *, const char *); +static krb5_error_code bad_405(struct bx509_request_desc *, const char *); +static krb5_error_code bad_500(struct bx509_request_desc *, krb5_error_code, const char *); +static krb5_error_code bad_503(struct bx509_request_desc *, krb5_error_code, const char *); +static heim_mhd_result validate_csrf_token(struct bx509_request_desc *r); + +static int +validate_token(struct bx509_request_desc *r) +{ + krb5_error_code ret; + krb5_principal cprinc = NULL; + const char *token; + const char *host; + char token_type[64]; /* Plenty */ + char *p; + krb5_data tok; + size_t host_len, brk, i; + + memset(&r->token_times, 0, sizeof(r->token_times)); + host = MHD_lookup_connection_value(r->connection, MHD_HEADER_KIND, + MHD_HTTP_HEADER_HOST); + if (host == NULL) + return bad_400(r, EINVAL, "Host header is missing"); + + /* Exclude port number here (IPv6-safe because of the below) */ + host_len = ((p = strchr(host, ':'))) ? p - host : strlen(host); + + token = MHD_lookup_connection_value(r->connection, MHD_HEADER_KIND, + MHD_HTTP_HEADER_AUTHORIZATION); + if (token == NULL) + return bad_401(r, "Authorization token is missing"); + brk = strcspn(token, " \t"); + if (token[brk] == '\0' || brk > sizeof(token_type) - 1) + return bad_401(r, "Authorization token is missing"); + memcpy(token_type, token, brk); + token_type[brk] = '\0'; + token += brk + 1; + tok.length = strlen(token); + tok.data = (void *)(uintptr_t)token; + + for (i = 0; i < audiences.num_strings; i++) + if (strncasecmp(host, audiences.strings[i], host_len) == 0 && + audiences.strings[i][host_len] == '\0') + break; + if (i == audiences.num_strings) + return bad_403(r, EINVAL, "Host: value is not accepted here"); + + r->sname = strdup(host); /* No need to check for ENOMEM here */ + + ret = kdc_validate_token(r->context, NULL /* realm */, token_type, &tok, + (const char **)&audiences.strings[i], 1, + &cprinc, &r->token_times); + if (ret) + return bad_403(r, ret, "Token validation failed"); + if (cprinc == NULL) + return bad_403(r, ret, "Could not extract a principal name " + "from token"); + ret = krb5_unparse_name(r->context, cprinc, &r->cname); + krb5_free_principal(r->context, cprinc); + if (ret) + return bad_503(r, ret, "Could not parse principal name"); + return ret; +} + +static void +generate_key(hx509_context context, + const char *key_name, + const char *gen_type, + unsigned long gen_bits, + char **fn) +{ + struct hx509_generate_private_context *key_gen_ctx = NULL; + hx509_private_key key = NULL; + hx509_certs certs = NULL; + hx509_cert cert = NULL; + int ret; + + if (strcmp(gen_type, "rsa") != 0) + errx(1, "Only RSA keys are supported at this time"); + + if (asprintf(fn, "PEM-FILE:%s/.%s_priv_key.pem", + cache_dir, key_name) == -1 || + *fn == NULL) + err(1, "Could not set up private key for %s", key_name); + + ret = _hx509_generate_private_key_init(context, + ASN1_OID_ID_PKCS1_RSAENCRYPTION, + &key_gen_ctx); + if (ret == 0) + ret = _hx509_generate_private_key_bits(context, key_gen_ctx, gen_bits); + if (ret == 0) + ret = _hx509_generate_private_key(context, key_gen_ctx, &key); + if (ret == 0) + cert = hx509_cert_init_private_key(context, key, NULL); + if (ret == 0) + ret = hx509_certs_init(context, *fn, + HX509_CERTS_CREATE | HX509_CERTS_UNPROTECT_ALL, + NULL, &certs); + if (ret == 0) + ret = hx509_certs_add(context, certs, cert); + if (ret == 0) + ret = hx509_certs_store(context, certs, 0, NULL); + if (ret) + hx509_err(context, 1, ret, "Could not generate and save private key " + "for %s", key_name); + + _hx509_generate_private_key_free(&key_gen_ctx); + hx509_private_key_free(&key); + hx509_certs_free(&certs); + hx509_cert_free(cert); +} + +static void +k5_free_context(void *ctx) +{ + krb5_free_context(ctx); +} + +#ifndef HAVE_UNLINKAT +static int +unlink1file(const char *dname, const char *name) +{ + char p[PATH_MAX]; + + if (strlcpy(p, dname, sizeof(p)) < sizeof(p) && + strlcat(p, "/", sizeof(p)) < sizeof(p) && + strlcat(p, name, sizeof(p)) < sizeof(p)) + return unlink(p); + return ERANGE; +} +#endif + +static void +rm_cache_dir(void) +{ + struct dirent *e; + DIR *d; + + /* + * This works, but not on Win32: + * + * (void) simple_execlp("rm", "rm", "-rf", cache_dir, NULL); + * + * We make no directories in `cache_dir', so we need not recurse. + */ + if ((d = opendir(cache_dir)) == NULL) + return; + + while ((e = readdir(d))) { +#ifdef HAVE_UNLINKAT + /* + * Because unlinkat() takes a directory FD, implementing one for + * libroken is tricky at best. Instead we might want to implement an + * rm_dash_rf() function in lib/roken. + */ + (void) unlinkat(dirfd(d), e->d_name, 0); +#else + (void) unlink1file(cache_dir, e->d_name); +#endif + } + (void) closedir(d); + (void) rmdir(cache_dir); +} + +static krb5_error_code +mk_pkix_store(char **pkix_store) +{ + char *s = NULL; + int ret = ENOMEM; + int fd; + + if (*pkix_store) { + const char *fn = strchr(*pkix_store, ':'); + + fn = fn ? fn + 1 : *pkix_store; + (void) unlink(fn); + } + + free(*pkix_store); + *pkix_store = NULL; + if (asprintf(&s, "PEM-FILE:%s/pkix-XXXXXX", cache_dir) == -1 || + s == NULL) { + free(s); + return ret; + } + if ((fd = mkstemp(s + sizeof("PEM-FILE:") - 1)) == -1) { + free(s); + return errno; + } + (void) close(fd); + *pkix_store = s; + return 0; +} + +static krb5_error_code +resp(struct bx509_request_desc *r, + int http_status_code, + enum MHD_ResponseMemoryMode rmmode, + const char *content_type, + const void *body, + size_t bodylen, + const char *token) +{ + int mret = MHD_YES; + + if (r->response) + return MHD_YES; + + (void) gettimeofday(&r->tv_end, NULL); + if (http_status_code == MHD_HTTP_OK || + http_status_code == MHD_HTTP_TEMPORARY_REDIRECT) + audit_trail(r, 0); + + r->response = MHD_create_response_from_buffer(bodylen, rk_UNCONST(body), + rmmode); + if (r->response == NULL) + return -1; + if (r->csrf_token) + mret = MHD_add_response_header(r->response, "X-CSRF-Token", r->csrf_token); + if (mret == MHD_YES) + mret = MHD_add_response_header(r->response, MHD_HTTP_HEADER_CACHE_CONTROL, + "no-store, max-age=0"); + if (mret == MHD_YES && http_status_code == MHD_HTTP_UNAUTHORIZED) { + mret = MHD_add_response_header(r->response, + MHD_HTTP_HEADER_WWW_AUTHENTICATE, + "Bearer"); + if (mret == MHD_YES) + mret = MHD_add_response_header(r->response, + MHD_HTTP_HEADER_WWW_AUTHENTICATE, + "Negotiate"); + } else if (mret == MHD_YES && http_status_code == MHD_HTTP_TEMPORARY_REDIRECT) { + const char *redir; + + /* XXX Move this */ + redir = MHD_lookup_connection_value(r->connection, MHD_GET_ARGUMENT_KIND, + "redirect"); + mret = MHD_add_response_header(r->response, MHD_HTTP_HEADER_LOCATION, + redir); + if (mret != MHD_NO && token) + mret = MHD_add_response_header(r->response, + MHD_HTTP_HEADER_AUTHORIZATION, + token); + } + if (mret == MHD_YES && content_type) { + mret = MHD_add_response_header(r->response, + MHD_HTTP_HEADER_CONTENT_TYPE, + content_type); + } + if (mret == MHD_YES) + mret = MHD_queue_response(r->connection, http_status_code, r->response); + MHD_destroy_response(r->response); + return mret == MHD_NO ? -1 : 0; +} + +static krb5_error_code +bad_reqv(struct bx509_request_desc *r, + krb5_error_code code, + int http_status_code, + const char *fmt, + va_list ap) +{ + krb5_error_code ret; + const char *k5msg = NULL; + const char *emsg = NULL; + char *formatted = NULL; + char *msg = NULL; + + heim_audit_setkv_number((heim_svc_req_desc)r, "http-status-code", + http_status_code); + (void) gettimeofday(&r->tv_end, NULL); + if (code == ENOMEM) { + if (r->context) + krb5_log_msg(r->context, logfac, 1, NULL, "Out of memory"); + audit_trail(r, code); + return resp(r, http_status_code, MHD_RESPMEM_PERSISTENT, + NULL, fmt, strlen(fmt), NULL); + } + + if (code) { + if (r->context) + emsg = k5msg = krb5_get_error_message(r->context, code); + else if (code > -1) + emsg = strerror(code); + else + emsg = "Unknown error"; + } + + ret = vasprintf(&formatted, fmt, ap); + if (code) { + if (ret > -1 && formatted) + ret = asprintf(&msg, "%s: %s (%d)", formatted, emsg, (int)code); + } else { + msg = formatted; + formatted = NULL; + } + heim_audit_addreason((heim_svc_req_desc)r, "%s", msg); + audit_trail(r, code); + if (r->context) + krb5_free_error_message(r->context, k5msg); + + if (ret == -1 || msg == NULL) { + if (r->context) + krb5_log_msg(r->context, logfac, 1, NULL, "Out of memory"); + return resp(r, MHD_HTTP_SERVICE_UNAVAILABLE, MHD_RESPMEM_PERSISTENT, + NULL, "Out of memory", sizeof("Out of memory") - 1, NULL); + } + + ret = resp(r, http_status_code, MHD_RESPMEM_MUST_COPY, + NULL, msg, strlen(msg), NULL); + free(formatted); + free(msg); + return ret == -1 ? -1 : code; +} + +static krb5_error_code +bad_req(struct bx509_request_desc *r, + krb5_error_code code, + int http_status_code, + const char *fmt, + ...) +{ + krb5_error_code ret; + va_list ap; + + va_start(ap, fmt); + ret = bad_reqv(r, code, http_status_code, fmt, ap); + va_end(ap); + return ret; +} + +static krb5_error_code +bad_enomem(struct bx509_request_desc *r, krb5_error_code ret) +{ + return bad_req(r, ret, MHD_HTTP_SERVICE_UNAVAILABLE, + "Out of memory"); +} + +static krb5_error_code +bad_400(struct bx509_request_desc *r, int ret, char *reason) +{ + return bad_req(r, ret, MHD_HTTP_BAD_REQUEST, "%s", reason); +} + +static krb5_error_code +bad_401(struct bx509_request_desc *r, char *reason) +{ + return bad_req(r, EACCES, MHD_HTTP_UNAUTHORIZED, "%s", reason); +} + +static krb5_error_code +bad_403(struct bx509_request_desc *r, krb5_error_code ret, char *reason) +{ + return bad_req(r, ret, MHD_HTTP_FORBIDDEN, "%s", reason); +} + +static krb5_error_code +bad_404(struct bx509_request_desc *r, const char *name) +{ + return bad_req(r, ENOENT, MHD_HTTP_NOT_FOUND, + "Resource not found: %s", name); +} + +static krb5_error_code +bad_405(struct bx509_request_desc *r, const char *method) +{ + return bad_req(r, EPERM, MHD_HTTP_METHOD_NOT_ALLOWED, + "Method not supported: %s", method); +} + +static krb5_error_code +bad_413(struct bx509_request_desc *r) +{ + return bad_req(r, E2BIG, MHD_HTTP_METHOD_NOT_ALLOWED, + "POST request body too large"); +} + +static krb5_error_code +bad_500(struct bx509_request_desc *r, + krb5_error_code ret, + const char *reason) +{ + return bad_req(r, ret, MHD_HTTP_INTERNAL_SERVER_ERROR, + "Internal error: %s", reason); +} + +static krb5_error_code +bad_503(struct bx509_request_desc *r, + krb5_error_code ret, + const char *reason) +{ + return bad_req(r, ret, MHD_HTTP_SERVICE_UNAVAILABLE, + "Service unavailable: %s", reason); +} + +static krb5_error_code +good_bx509(struct bx509_request_desc *r) +{ + krb5_error_code ret; + const char *fn; + size_t bodylen; + void *body; + + /* + * This `fn' thing is just to quiet linters that think "hey, strchr() can + * return NULL so...", but here we've build `r->pkix_store' and know it has + * a ':'. + */ + if (r->pkix_store == NULL) + return bad_503(r, EINVAL, "Internal error"); /* Quiet warnings */ + fn = strchr(r->pkix_store, ':'); + fn = fn ? fn + 1 : r->pkix_store; + ret = rk_undumpdata(fn, &body, &bodylen); + if (ret) + return bad_503(r, ret, "Could not recover issued certificate " + "from PKIX store"); + + (void) gettimeofday(&r->tv_end, NULL); + ret = resp(r, MHD_HTTP_OK, MHD_RESPMEM_MUST_COPY, "application/x-pem-file", + body, bodylen, NULL); + free(body); + return ret; +} + +static heim_mhd_result +bx509_param_cb(void *d, + enum MHD_ValueKind kind, + const char *key, + const char *val) +{ + struct bx509_request_desc *r = d; + heim_oid oid = { 0, 0 }; + + if (strcmp(key, "eku") == 0 && val) { + heim_audit_addkv((heim_svc_req_desc)r, KDC_AUDIT_VIS, "requested_eku", + "%s", val); + r->error_code = der_parse_heim_oid(val, ".", &oid); + if (r->error_code == 0) + r->error_code = hx509_request_add_eku(r->context->hx509ctx, r->req, &oid); + der_free_oid(&oid); + } else if (strcmp(key, "dNSName") == 0 && val) { + heim_audit_addkv((heim_svc_req_desc)r, KDC_AUDIT_VIS, + "requested_dNSName", "%s", val); + r->error_code = hx509_request_add_dns_name(r->context->hx509ctx, r->req, val); + } else if (strcmp(key, "rfc822Name") == 0 && val) { + heim_audit_addkv((heim_svc_req_desc)r, KDC_AUDIT_VIS, + "requested_rfc822Name", "%s", val); + r->error_code = hx509_request_add_email(r->context->hx509ctx, r->req, val); + } else if (strcmp(key, "xMPPName") == 0 && val) { + heim_audit_addkv((heim_svc_req_desc)r, KDC_AUDIT_VIS, + "requested_xMPPName", "%s", val); + r->error_code = hx509_request_add_xmpp_name(r->context->hx509ctx, r->req, + val); + } else if (strcmp(key, "krb5PrincipalName") == 0 && val) { + heim_audit_addkv((heim_svc_req_desc)r, KDC_AUDIT_VIS, + "requested_krb5PrincipalName", "%s", val); + r->error_code = hx509_request_add_pkinit(r->context->hx509ctx, r->req, + val); + } else if (strcmp(key, "ms-upn") == 0 && val) { + heim_audit_addkv((heim_svc_req_desc)r, KDC_AUDIT_VIS, + "requested_ms_upn", "%s", val); + r->error_code = hx509_request_add_ms_upn_name(r->context->hx509ctx, r->req, + val); + } else if (strcmp(key, "registeredID") == 0 && val) { + heim_audit_addkv((heim_svc_req_desc)r, KDC_AUDIT_VIS, + "requested_registered_id", "%s", val); + r->error_code = der_parse_heim_oid(val, ".", &oid); + if (r->error_code == 0) + r->error_code = hx509_request_add_registered(r->context->hx509ctx, r->req, + &oid); + der_free_oid(&oid); + } else if (strcmp(key, "csr") == 0 && val) { + heim_audit_setkv_bool((heim_svc_req_desc)r, "requested_csr", TRUE); + r->error_code = 0; /* Handled upstairs */ + } else if (strcmp(key, "lifetime") == 0 && val) { + r->req_life = parse_time(val, "day"); + } else { + /* Produce error for unknown params */ + heim_audit_setkv_bool((heim_svc_req_desc)r, "requested_unknown", TRUE); + krb5_set_error_message(r->context, r->error_code = ENOTSUP, + "Query parameter %s not supported", key); + } + return r->error_code == 0 ? MHD_YES : MHD_NO /* Stop iterating */; +} + +static krb5_error_code +authorize_CSR(struct bx509_request_desc *r, + krb5_data *csr, + krb5_const_principal p) +{ + krb5_error_code ret; + + ret = hx509_request_parse_der(r->context->hx509ctx, csr, &r->req); + if (ret) + return bad_req(r, ret, MHD_HTTP_SERVICE_UNAVAILABLE, + "Could not parse CSR"); + r->error_code = 0; + (void) MHD_get_connection_values(r->connection, MHD_GET_ARGUMENT_KIND, + bx509_param_cb, r); + ret = r->error_code; + if (ret) + return bad_req(r, ret, MHD_HTTP_SERVICE_UNAVAILABLE, + "Could not handle query parameters"); + + ret = kdc_authorize_csr(r->context, "bx509", r->req, p); + if (ret) + return bad_403(r, ret, "Not authorized to requested certificate"); + return ret; +} + +/* + * hx509_certs_iter_f() callback to assign a private key to the first cert in a + * store. + */ +static int HX509_LIB_CALL +set_priv_key(hx509_context context, void *d, hx509_cert c) +{ + (void) _hx509_cert_assign_key(c, (hx509_private_key)d); + return -1; /* stop iteration */ +} + +static krb5_error_code +store_certs(hx509_context context, + const char *store, + hx509_certs store_these, + hx509_private_key key) +{ + krb5_error_code ret; + hx509_certs certs = NULL; + + ret = hx509_certs_init(context, store, HX509_CERTS_CREATE, NULL, + &certs); + if (ret == 0) { + if (key) + (void) hx509_certs_iter_f(context, store_these, set_priv_key, key); + hx509_certs_merge(context, certs, store_these); + } + if (ret == 0) + hx509_certs_store(context, certs, 0, NULL); + hx509_certs_free(&certs); + return ret; +} + +/* Setup a CSR for bx509() */ +static krb5_error_code +do_CA(struct bx509_request_desc *r, const char *csr) +{ + krb5_error_code ret = 0; + krb5_principal p; + hx509_certs certs = NULL; + krb5_data d; + ssize_t bytes; + char *csr2, *q; + + /* + * Work around bug where microhttpd decodes %2b to + then + to space. That + * bug does not affect other base64 special characters that get URI + * %-encoded. + */ + if ((csr2 = strdup(csr)) == NULL) + return bad_enomem(r, ENOMEM); + for (q = strchr(csr2, ' '); q; q = strchr(q + 1, ' ')) + *q = '+'; + + ret = krb5_parse_name(r->context, r->cname, &p); + if (ret) { + free(csr2); + return bad_req(r, ret, MHD_HTTP_SERVICE_UNAVAILABLE, + "Could not parse principal name"); + } + + /* Set CSR */ + if ((d.data = malloc(strlen(csr2))) == NULL) { + krb5_free_principal(r->context, p); + free(csr2); + return bad_enomem(r, ENOMEM); + } + + bytes = rk_base64_decode(csr2, d.data); + free(csr2); + if (bytes < 0) + ret = errno ? errno : EINVAL; + else + d.length = bytes; + if (ret) { + krb5_free_principal(r->context, p); + free(d.data); + return bad_500(r, ret, "Invalid base64 encoding of CSR"); + } + + /* + * Parses and validates the CSR, adds external extension requests from + * query parameters, then checks authorization. + */ + ret = authorize_CSR(r, &d, p); + free(d.data); + d.data = 0; + d.length = 0; + if (ret) { + krb5_free_principal(r->context, p); + return ret; /* authorize_CSR() calls bad_req() */ + } + + /* Issue the certificate */ + ret = kdc_issue_certificate(r->context, "bx509", logfac, r->req, p, + &r->token_times, r->req_life, + 1 /* send_chain */, &certs); + krb5_free_principal(r->context, p); + if (ret) { + if (ret == KRB5KDC_ERR_POLICY || ret == EACCES) + return bad_403(r, ret, + "Certificate request denied for policy reasons"); + return bad_500(r, ret, "Certificate issuance failed"); + } + + /* Setup PKIX store */ + if ((ret = mk_pkix_store(&r->pkix_store))) + return bad_500(r, ret, + "Could not create PEM store for issued certificate"); + + ret = store_certs(r->context->hx509ctx, r->pkix_store, certs, NULL); + hx509_certs_free(&certs); + if (ret) + return bad_500(r, ret, "Failed to convert issued" + " certificate and chain to PEM"); + return 0; +} + +/* Copied from kdc/connect.c */ +static void +addr_to_string(krb5_context context, + struct sockaddr *addr, + char *str, + size_t len) +{ + krb5_error_code ret; + krb5_address a; + + ret = krb5_sockaddr2address(context, addr, &a); + if (ret == 0) { + ret = krb5_print_address(&a, str, len, &len); + krb5_free_address(context, &a); + } + if (ret) + snprintf(str, len, "", addr->sa_family); +} + +static void clean_req_desc(struct bx509_request_desc *); + +static krb5_error_code +set_req_desc(struct MHD_Connection *connection, + const char *method, + const char *url, + struct bx509_request_desc **rp) +{ + struct bx509_request_desc *r; + const union MHD_ConnectionInfo *ci; + const char *token; + krb5_error_code ret; + + *rp = NULL; + if ((r = calloc(1, sizeof(*r))) == NULL) + return ENOMEM; + (void) gettimeofday(&r->tv_start, NULL); + + ret = get_krb5_context(&r->context); + r->connection = connection; + r->response = NULL; + r->pp = NULL; + r->request.data = ""; + r->request.length = sizeof(""); + r->from = r->frombuf; + r->tgt_addresses.len = 0; + r->tgt_addresses.val = 0; + r->hcontext = r->context ? r->context->hcontext : NULL; + r->config = NULL; + r->logf = logfac; + r->csrf_token = NULL; + r->free_list = NULL; + r->method = method; + r->reqtype = url; + r->target = r->redir = NULL; + r->pkix_store = NULL; + r->for_cname = NULL; + r->freeme1 = NULL; + r->reason = NULL; + r->tgts_filename = NULL; + r->tgts = NULL; + r->ccname = NULL; + r->reply = NULL; + r->sname = NULL; + r->cname = NULL; + r->addr = NULL; + r->req = NULL; + r->req_life = 0; + r->error_code = ret; + r->kv = heim_dict_create(10); + r->attributes = heim_dict_create(1); + if (ret == 0 && (r->kv == NULL || r->attributes == NULL)) + r->error_code = ret = ENOMEM; + ci = MHD_get_connection_info(connection, + MHD_CONNECTION_INFO_CLIENT_ADDRESS); + if (ci) { + r->addr = ci->client_addr; + addr_to_string(r->context, r->addr, r->frombuf, sizeof(r->frombuf)); + } + + heim_audit_addkv((heim_svc_req_desc)r, 0, "method", "GET"); + heim_audit_addkv((heim_svc_req_desc)r, 0, "endpoint", "%s", r->reqtype); + token = MHD_lookup_connection_value(r->connection, MHD_HEADER_KIND, + MHD_HTTP_HEADER_AUTHORIZATION); + if (token && r->kv) { + const char *token_end; + + if ((token_end = strchr(token, ' ')) == NULL || + (token_end - token) > INT_MAX || (token_end - token) < 2) + heim_audit_addkv((heim_svc_req_desc)r, 0, "auth", ""); + else + heim_audit_addkv((heim_svc_req_desc)r, 0, "auth", "%.*s", + (int)(token_end - token), token); + + } + + if (ret == 0) + *rp = r; + else + clean_req_desc(r); + return ret; +} + +static void +clean_req_desc(struct bx509_request_desc *r) +{ + if (!r) + return; + while (r->free_list) { + struct free_tend_list *ftl = r->free_list; + r->free_list = r->free_list->next; + free(ftl->freeme1); + free(ftl->freeme2); + free(ftl); + } + if (r->pkix_store) { + const char *fn = strchr(r->pkix_store, ':'); + + /* + * This `fn' thing is just to quiet linters that think "hey, strchr() can + * return NULL so...", but here we've build `r->pkix_store' and know it has + * a ':'. + */ + fn = fn ? fn + 1 : r->pkix_store; + (void) unlink(fn); + } + krb5_free_addresses(r->context, &r->tgt_addresses); + hx509_request_free(&r->req); + heim_release(r->attributes); + heim_release(r->reason); + heim_release(r->kv); + if (r->ccname && r->cckind == K5_CREDS_EPHEMERAL) { + const char *fn = r->ccname; + + if (strncmp(fn, "FILE:", sizeof("FILE:") - 1) == 0) + fn += sizeof("FILE:") - 1; + (void) unlink(fn); + } + if (r->tgts) + (void) fclose(r->tgts); + if (r->tgts_filename) { + (void) unlink(r->tgts_filename); + free(r->tgts_filename); + } + /* No need to destroy r->response */ + if (r->pp) + MHD_destroy_post_processor(r->pp); + free(r->csrf_token); + free(r->pkix_store); + free(r->freeme1); + free(r->ccname); + free(r->cname); + free(r->sname); + free(r); +} + +/* Implements GETs of /bx509 */ +static krb5_error_code +bx509(struct bx509_request_desc *r) +{ + krb5_error_code ret; + const char *csr; + + /* Get required inputs */ + csr = MHD_lookup_connection_value(r->connection, MHD_GET_ARGUMENT_KIND, + "csr"); + if (csr == NULL) + return bad_400(r, EINVAL, "CSR is missing"); + + if (r->cname == NULL) + return bad_403(r, EINVAL, + "Could not extract principal name from token"); + + /* Parse CSR, add extensions from parameters, authorize, issue cert */ + if ((ret = do_CA(r, csr))) + return ret; + + /* Read and send the contents of the PKIX store */ + krb5_log_msg(r->context, logfac, 1, NULL, "Issued certificate to %s", + r->cname); + return good_bx509(r); +} + +/* + * princ_fs_encode_sz() and princ_fs_encode() encode a principal name to be + * safe for use as a file name. They function very much like URL encoders, but + * '~' and '.' also get encoded, and '@' does not. + * + * A corresponding decoder is not needed. + * + * XXX Maybe use krb5_cc_default_for()! + */ +static size_t +princ_fs_encode_sz(const char *in) +{ + size_t sz = strlen(in); + + while (*in) { + unsigned char c = *(const unsigned char *)(in++); + + if (isalnum(c)) + continue; + switch (c) { + case '@': + case '-': + case '_': + continue; + default: + sz += 2; + } + } + return sz; +} + +static char * +princ_fs_encode(const char *in) +{ + size_t len = strlen(in); + size_t sz = princ_fs_encode_sz(in); + size_t i, k; + char *s; + + if ((s = malloc(sz + 1)) == NULL) + return NULL; + s[sz] = '\0'; + + for (i = k = 0; i < len; i++) { + char c = in[i]; + + switch (c) { + case '@': + case '-': + case '_': + s[k++] = c; + break; + default: + if (isalnum((unsigned char)c)) { + s[k++] = c; + } else { + s[k++] = '%'; + s[k++] = "0123456789abcdef"[(c&0xff)>>4]; + s[k++] = "0123456789abcdef"[(c&0x0f)]; + } + } + } + return s; +} + + +/* + * Find an existing, live ccache for `princ' in `cache_dir' or acquire Kerberos + * creds for `princ' with PKINIT and put them in a ccache in `cache_dir'. + */ +static krb5_error_code +find_ccache(krb5_context context, const char *princ, char **ccname) +{ + krb5_error_code ret = ENOMEM; + krb5_ccache cc = NULL; + time_t life; + char *s = NULL; + + *ccname = NULL; + + /* + * Name the ccache after the principal. The principal may have special + * characters in it, such as / or \ (path component separarot), or shell + * special characters, so princ_fs_encode() it to make a ccache name. + */ + if ((s = princ_fs_encode(princ)) == NULL || + asprintf(ccname, "FILE:%s/%s.cc", cache_dir, s) == -1 || + *ccname == NULL) { + free(s); + return ENOMEM; + } + free(s); + + if ((ret = krb5_cc_resolve(context, *ccname, &cc))) { + /* krb5_cc_resolve() suceeds even if the file doesn't exist */ + free(*ccname); + *ccname = NULL; + cc = NULL; + } + + /* Check if we have a good enough credential */ + if (ret == 0 && + (ret = krb5_cc_get_lifetime(context, cc, &life)) == 0 && life > 60) { + krb5_cc_close(context, cc); + return 0; + } + if (cc) + krb5_cc_close(context, cc); + return ret ? ret : ENOENT; +} + +static krb5_error_code +get_ccache(struct bx509_request_desc *r, krb5_ccache *cc, int *won) +{ + krb5_error_code ret = 0; + char *temp_ccname = NULL; + const char *fn = NULL; + time_t life; + int fd = -1; + + /* + * Open and lock a .new ccache file. Use .new to avoid garbage files on + * crash. + * + * We can race with other threads to do this, so we loop until we + * definitively win or definitely lose the race. We win when we have a) an + * open FD that is b) flock'ed, and c) we observe with lstat() that the + * file we opened and locked is the same as on disk after locking. + * + * We don't close the FD until we're done. + * + * If we had a proper anon MEMORY ccache, we could instead use that for a + * temporary ccache, and then the initialization of and move to the final + * FILE ccache would take care to mkstemp() and rename() into place. + * fcc_open() basically does a similar thing. + */ + *cc = NULL; + *won = -1; + if (asprintf(&temp_ccname, "%s.ccnew", r->ccname) == -1 || + temp_ccname == NULL) + ret = ENOMEM; + if (ret == 0) + fn = temp_ccname + sizeof("FILE:") - 1; + if (ret == 0) do { + struct stat st1, st2; + /* + * Open and flock the temp ccache file. + * + * XXX We should really a) use _krb5_xlock(), or move that into + * lib/roken anyways, b) abstract this loop into a utility function in + * lib/roken. + */ + if (fd != -1) { + (void) close(fd); + fd = -1; + } + errno = 0; + memset(&st1, 0, sizeof(st1)); + memset(&st2, 0xff, sizeof(st2)); + if (ret == 0 && + ((fd = open(fn, O_RDWR | O_CREAT, 0600)) == -1 || + flock(fd, LOCK_EX) == -1 || + (lstat(fn, &st1) == -1 && errno != ENOENT) || + fstat(fd, &st2) == -1)) + ret = errno; + if (ret == 0 && errno == 0 && + st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino) { + if (S_ISREG(st1.st_mode)) + break; + if (unlink(fn) == -1) + ret = errno; + } + } while (ret == 0); + + /* Check if we lost any race to acquire Kerberos creds */ + if (ret == 0) + ret = krb5_cc_resolve(r->context, temp_ccname, cc); + if (ret == 0) { + ret = krb5_cc_get_lifetime(r->context, *cc, &life); + if (ret == 0 && life > 60) + *won = 0; /* We lost the race, but we win: we get to do less work */ + *won = 1; + ret = 0; + } + free(temp_ccname); + if (fd != -1) + (void) close(fd); /* Drops the flock */ + return ret; +} + +/* + * Acquire credentials for `princ' using PKINIT and the PKIX credentials in + * `pkix_store', then place the result in the ccache named `ccname' (which will + * be in our own private `cache_dir'). + * + * XXX This function could be rewritten using gss_acquire_cred_from() and + * gss_store_cred_into() provided we add new generic cred store key/value pairs + * for PKINIT. + */ +static krb5_error_code +do_pkinit(struct bx509_request_desc *r, enum k5_creds_kind kind) +{ + krb5_get_init_creds_opt *opt = NULL; + krb5_init_creds_context ctx = NULL; + krb5_error_code ret = 0; + krb5_ccache temp_cc = NULL; + krb5_ccache cc = NULL; + krb5_principal p = NULL; + const char *crealm; + const char *cname = r->for_cname ? r->for_cname : r->cname; + + if (kind == K5_CREDS_CACHED) { + int won = -1; + + ret = get_ccache(r, &temp_cc, &won); + if (ret || !won) + goto out; + /* + * We won the race to do PKINIT. Setup to acquire Kerberos creds with + * PKINIT. + * + * We should really make sure that gss_acquire_cred_from() can do this + * for us. We'd add generic cred store key/value pairs for PKIX cred + * store, trust anchors, and so on, and acquire that way, then + * gss_store_cred_into() to save it in a FILE ccache. + */ + } else { + ret = krb5_cc_new_unique(r->context, "FILE", NULL, &temp_cc); + } + + if (ret == 0) + ret = krb5_parse_name(r->context, cname, &p); + if (ret == 0) + crealm = krb5_principal_get_realm(r->context, p); + if (ret == 0) + ret = krb5_get_init_creds_opt_alloc(r->context, &opt); + if (ret == 0) + krb5_get_init_creds_opt_set_default_flags(r->context, "kinit", crealm, + opt); + if (ret == 0 && kind == K5_CREDS_EPHEMERAL && + !krb5_config_get_bool_default(r->context, NULL, TRUE, + "get-tgt", "no_addresses", NULL)) { + krb5_addresses addr; + + ret = _krb5_parse_address_no_lookup(r->context, r->frombuf, &addr); + if (ret == 0) + ret = krb5_append_addresses(r->context, &r->tgt_addresses, + &addr); + } + if (ret == 0) { + if (r->tgt_addresses.len == 0) + ret = krb5_get_init_creds_opt_set_addressless(r->context, opt, 1); + else + krb5_get_init_creds_opt_set_address_list(opt, &r->tgt_addresses); + } + if (ret == 0) + ret = krb5_get_init_creds_opt_set_pkinit(r->context, opt, p, + r->pkix_store, + NULL, /* pkinit_anchor */ + NULL, /* anchor_chain */ + NULL, /* pkinit_crl */ + 0, /* flags */ + NULL, /* prompter */ + NULL, /* prompter data */ + NULL /* password */); + if (ret == 0) + ret = krb5_init_creds_init(r->context, p, + NULL /* prompter */, + NULL /* prompter data */, + 0 /* start_time */, + opt, &ctx); + + /* + * Finally, do the AS exchange w/ PKINIT, extract the new Kerberos creds + * into temp_cc, and rename into place. Note that krb5_cc_move() closes + * the source ccache, so we set temp_cc = NULL if it succeeds. + */ + if (ret == 0) + ret = krb5_init_creds_get(r->context, ctx); + if (ret == 0) + ret = krb5_init_creds_store(r->context, ctx, temp_cc); + if (kind == K5_CREDS_CACHED) { + if (ret == 0) + ret = krb5_cc_resolve(r->context, r->ccname, &cc); + if (ret == 0) + ret = krb5_cc_move(r->context, temp_cc, cc); + if (ret == 0) + temp_cc = NULL; + } else if (ret == 0 && kind == K5_CREDS_EPHEMERAL) { + ret = krb5_cc_get_full_name(r->context, temp_cc, &r->ccname); + } + +out: + if (ctx) + krb5_init_creds_free(r->context, ctx); + krb5_get_init_creds_opt_free(r->context, opt); + krb5_free_principal(r->context, p); + krb5_cc_close(r->context, temp_cc); + krb5_cc_close(r->context, cc); + return ret; +} + +static krb5_error_code +load_priv_key(krb5_context context, const char *fn, hx509_private_key *key) +{ + hx509_private_key *keys = NULL; + krb5_error_code ret; + hx509_certs certs = NULL; + + *key = NULL; + ret = hx509_certs_init(context->hx509ctx, fn, 0, NULL, &certs); + if (ret == ENOENT) + return 0; + if (ret == 0) + ret = _hx509_certs_keys_get(context->hx509ctx, certs, &keys); + if (ret == 0 && keys[0] == NULL) + ret = ENOENT; /* XXX Better error please */ + if (ret == 0) + *key = _hx509_private_key_ref(keys[0]); + if (ret) + krb5_set_error_message(context, ret, "Could not load private " + "impersonation key from %s for PKINIT: %s", fn, + hx509_get_error_string(context->hx509ctx, ret)); + _hx509_certs_keys_free(context->hx509ctx, keys); + hx509_certs_free(&certs); + return ret; +} + +static krb5_error_code +k5_do_CA(struct bx509_request_desc *r) +{ + SubjectPublicKeyInfo spki; + hx509_private_key key = NULL; + krb5_error_code ret = 0; + krb5_principal p = NULL; + hx509_request req = NULL; + hx509_certs certs = NULL; + KeyUsage ku = int2KeyUsage(0); + const char *cname = r->for_cname ? r->for_cname : r->cname; + + memset(&spki, 0, sizeof(spki)); + ku.digitalSignature = 1; + + /* Make a CSR (halfway -- we don't need to sign it here) */ + /* XXX Load impersonation key just once?? */ + ret = load_priv_key(r->context, impersonation_key_fn, &key); + if (ret == 0) + ret = hx509_request_init(r->context->hx509ctx, &req); + if (ret == 0) + ret = krb5_parse_name(r->context, cname, &p); + if (ret == 0) + ret = hx509_private_key2SPKI(r->context->hx509ctx, key, &spki); + if (ret == 0) + hx509_request_set_SubjectPublicKeyInfo(r->context->hx509ctx, req, + &spki); + free_SubjectPublicKeyInfo(&spki); + if (ret == 0) + ret = hx509_request_add_pkinit(r->context->hx509ctx, req, cname); + if (ret == 0) + ret = hx509_request_add_eku(r->context->hx509ctx, req, + &asn1_oid_id_pkekuoid); + + /* Mark it authorized */ + if (ret == 0) + ret = hx509_request_authorize_san(req, 0); + if (ret == 0) + ret = hx509_request_authorize_eku(req, 0); + if (ret == 0) + hx509_request_authorize_ku(req, ku); + + /* Issue the certificate */ + if (ret == 0) + ret = kdc_issue_certificate(r->context, "get-tgt", logfac, req, p, + &r->token_times, r->req_life, + 1 /* send_chain */, &certs); + krb5_free_principal(r->context, p); + hx509_request_free(&req); + p = NULL; + + if (ret == KRB5KDC_ERR_POLICY || ret == EACCES) { + hx509_private_key_free(&key); + return bad_403(r, ret, + "Certificate request denied for policy reasons"); + } + if (ret == ENOMEM) { + hx509_private_key_free(&key); + return bad_503(r, ret, "Certificate issuance failed"); + } + if (ret) { + hx509_private_key_free(&key); + return bad_500(r, ret, "Certificate issuance failed"); + } + + /* Setup PKIX store and extract the certificate chain into it */ + ret = mk_pkix_store(&r->pkix_store); + if (ret == 0) + ret = store_certs(r->context->hx509ctx, r->pkix_store, certs, key); + hx509_private_key_free(&key); + hx509_certs_free(&certs); + if (ret) + return bad_500(r, ret, + "Could not create PEM store for issued certificate"); + return 0; +} + +/* Get impersonated Kerberos credentials for `cprinc' */ +static krb5_error_code +k5_get_creds(struct bx509_request_desc *r, enum k5_creds_kind kind) +{ + krb5_error_code ret; + const char *cname = r->for_cname ? r->for_cname : r->cname; + + /* If we have a live ccache for `cprinc', we're done */ + r->cckind = kind; + if (kind == K5_CREDS_CACHED && + (ret = find_ccache(r->context, cname, &r->ccname)) == 0) + return ret; /* Success */ + + /* + * Else we have to acquire a credential for them using their bearer token + * for authentication (and our keytab / initiator credentials perhaps). + */ + if ((ret = k5_do_CA(r))) + return ret; /* k5_do_CA() calls bad_req() */ + + if (ret == 0) + ret = do_pkinit(r, kind); + return ret; +} + +/* Accumulate strings */ +static void +acc_str(char **acc, char *adds, size_t addslen) +{ + char *tmp = NULL; + int l = addslen <= INT_MAX ? (int)addslen : INT_MAX; + + if (asprintf(&tmp, "%s%s%.*s", + *acc ? *acc : "", + *acc ? "; " : "", l, adds) > -1 && + tmp) { + free(*acc); + *acc = tmp; + } +} + +static char * +fmt_gss_error(OM_uint32 code, gss_OID mech) +{ + gss_buffer_desc buf; + OM_uint32 major, minor; + OM_uint32 type = mech == GSS_C_NO_OID ? GSS_C_GSS_CODE: GSS_C_MECH_CODE; + OM_uint32 more = 0; + char *r = NULL; + + do { + major = gss_display_status(&minor, code, type, mech, &more, &buf); + if (!GSS_ERROR(major)) + acc_str(&r, (char *)buf.value, buf.length); + gss_release_buffer(&minor, &buf); + } while (!GSS_ERROR(major) && more); + return r; +} + +static char * +fmt_gss_errors(const char *r, OM_uint32 major, OM_uint32 minor, gss_OID mech) +{ + char *ma, *mi, *s; + + ma = fmt_gss_error(major, GSS_C_NO_OID); + mi = mech == GSS_C_NO_OID ? NULL : fmt_gss_error(minor, mech); + if (asprintf(&s, "%s: %s%s%s", r, + ma ? ma : "Out of memory", + mi ? ": " : "", + mi ? mi : "") > -1 && + s) { + free(ma); + free(mi); + return s; + } + free(mi); + return ma; +} + +/* GSS-API error */ +static krb5_error_code +bad_req_gss(struct bx509_request_desc *r, + OM_uint32 major, + OM_uint32 minor, + gss_OID mech, + int http_status_code, + const char *reason) +{ + krb5_error_code ret; + char *msg = fmt_gss_errors(reason, major, minor, mech); + + if (major == GSS_S_BAD_NAME || major == GSS_S_BAD_NAMETYPE) + http_status_code = MHD_HTTP_BAD_REQUEST; + + if (msg) + ret = resp(r, http_status_code, MHD_RESPMEM_MUST_COPY, NULL, + msg, strlen(msg), NULL); + else + ret = resp(r, http_status_code, MHD_RESPMEM_MUST_COPY, NULL, + "Out of memory while formatting GSS error message", + sizeof("Out of memory while formatting GSS error message") - 1, NULL); + free(msg); + return ret; +} + +/* Make an HTTP/Negotiate token */ +static krb5_error_code +mk_nego_tok(struct bx509_request_desc *r, + char **nego_tok, + size_t *nego_toksz) +{ + gss_key_value_element_desc kv[1] = { { "ccache", r->ccname } }; + gss_key_value_set_desc store = { 1, kv }; + gss_buffer_desc token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc name = GSS_C_EMPTY_BUFFER; + gss_cred_id_t cred = GSS_C_NO_CREDENTIAL; + gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; + gss_name_t iname = GSS_C_NO_NAME; + gss_name_t aname = GSS_C_NO_NAME; + OM_uint32 major, minor, junk; + krb5_error_code ret; /* More like a system error code here */ + const char *cname = r->for_cname ? r->for_cname : r->cname; + char *token_b64 = NULL; + + *nego_tok = NULL; + *nego_toksz = 0; + + /* Import initiator name */ + name.length = strlen(cname); + name.value = rk_UNCONST(cname); + major = gss_import_name(&minor, &name, GSS_KRB5_NT_PRINCIPAL_NAME, &iname); + if (major != GSS_S_COMPLETE) + return bad_req_gss(r, major, minor, GSS_C_NO_OID, + MHD_HTTP_SERVICE_UNAVAILABLE, + "Could not import cprinc parameter value as " + "Kerberos principal name"); + + /* Import target acceptor name */ + name.length = strlen(r->target); + name.value = rk_UNCONST(r->target); + major = gss_import_name(&minor, &name, GSS_C_NT_HOSTBASED_SERVICE, &aname); + if (major != GSS_S_COMPLETE) { + (void) gss_release_name(&junk, &iname); + return bad_req_gss(r, major, minor, GSS_C_NO_OID, + MHD_HTTP_SERVICE_UNAVAILABLE, + "Could not import target parameter value as " + "Kerberos principal name"); + } + + /* Acquire a credential from the given ccache */ + major = gss_add_cred_from(&minor, cred, iname, GSS_KRB5_MECHANISM, + GSS_C_INITIATE, GSS_C_INDEFINITE, 0, &store, + &cred, NULL, NULL, NULL); + (void) gss_release_name(&junk, &iname); + if (major != GSS_S_COMPLETE) { + (void) gss_release_name(&junk, &aname); + return bad_req_gss(r, major, minor, GSS_KRB5_MECHANISM, + MHD_HTTP_FORBIDDEN, "Could not acquire credentials " + "for requested cprinc"); + } + + major = gss_init_sec_context(&minor, cred, &ctx, aname, + GSS_KRB5_MECHANISM, 0, GSS_C_INDEFINITE, + NULL, GSS_C_NO_BUFFER, NULL, &token, NULL, + NULL); + (void) gss_delete_sec_context(&junk, &ctx, GSS_C_NO_BUFFER); + (void) gss_release_name(&junk, &aname); + (void) gss_release_cred(&junk, &cred); + if (major != GSS_S_COMPLETE) + return bad_req_gss(r, major, minor, GSS_KRB5_MECHANISM, + MHD_HTTP_SERVICE_UNAVAILABLE, "Could not acquire " + "Negotiate token for requested target"); + + /* Encode token, output */ + ret = rk_base64_encode(token.value, token.length, &token_b64); + (void) gss_release_buffer(&junk, &token); + if (ret > 0) + ret = asprintf(nego_tok, "Negotiate %s", token_b64); + free(token_b64); + if (ret < 0 || *nego_tok == NULL) + return bad_req(r, errno, MHD_HTTP_SERVICE_UNAVAILABLE, + "Could not allocate memory for encoding Negotiate " + "token"); + *nego_toksz = ret; + return 0; +} + +static krb5_error_code +bnegotiate_get_target(struct bx509_request_desc *r) +{ + const char *target; + const char *redir; + const char *referer; /* misspelled on the wire, misspelled here, FYI */ + const char *authority; + const char *local_part; + char *s1 = NULL; + char *s2 = NULL; + + target = MHD_lookup_connection_value(r->connection, MHD_GET_ARGUMENT_KIND, + "target"); + redir = MHD_lookup_connection_value(r->connection, MHD_GET_ARGUMENT_KIND, + "redirect"); + referer = MHD_lookup_connection_value(r->connection, MHD_HEADER_KIND, + MHD_HTTP_HEADER_REFERER); + if (target != NULL && redir == NULL) { + r->target = target; + return 0; + } + if (target == NULL && redir == NULL) + return bad_400(r, EINVAL, + "Query missing 'target' or 'redirect' parameter value"); + if (target != NULL && redir != NULL) + return bad_403(r, EACCES, + "Only one of 'target' or 'redirect' parameter allowed"); + if (redir != NULL && referer == NULL) + return bad_403(r, EACCES, + "Redirect request without Referer header nor allowed"); + + if (strncmp(referer, "https://", sizeof("https://") - 1) != 0 || + strncmp(redir, "https://", sizeof("https://") - 1) != 0) + return bad_403(r, EACCES, + "Redirect requests permitted only for https referrers"); + + /* Parse out authority from each URI, redirect and referrer */ + authority = redir + sizeof("https://") - 1; + if ((local_part = strchr(authority, '/')) == NULL) + local_part = authority + strlen(authority); + if ((s1 = strndup(authority, local_part - authority)) == NULL) + return bad_enomem(r, ENOMEM); + + authority = referer + sizeof("https://") - 1; + if ((local_part = strchr(authority, '/')) == NULL) + local_part = authority + strlen(authority); + if ((s2 = strndup(authority, local_part - authority)) == NULL) { + free(s1); + return bad_enomem(r, ENOMEM); + } + + /* Both must match */ + if (strcasecmp(s1, s2) != 0) { + free(s2); + free(s1); + return bad_403(r, EACCES, "Redirect request does not match referer"); + } + free(s2); + + if (strchr(s1, '@')) { + free(s1); + return bad_403(r, EACCES, + "Redirect request authority has login information"); + } + + /* Extract hostname portion of authority and format GSS name */ + if (strchr(s1, ':')) + *strchr(s1, ':') = '\0'; + if (asprintf(&r->freeme1, "HTTP@%s", s1) == -1 || r->freeme1 == NULL) { + free(s1); + return bad_enomem(r, ENOMEM); + } + + r->target = r->freeme1; + r->redir = redir; + free(s1); + return 0; +} + +/* + * Implements /bnegotiate end-point. + * + * Query parameters (mutually exclusive): + * + * - target= + * - redirect= + * + * If the redirect query parameter is set then the Referer: header must be as + * well, and the authority of the redirect and Referer URIs must be the same. + */ +static krb5_error_code +bnegotiate(struct bx509_request_desc *r) +{ + krb5_error_code ret; + size_t nego_toksz = 0; + char *nego_tok = NULL; + + ret = bnegotiate_get_target(r); + if (ret) + return ret; /* bnegotiate_get_target() calls bad_req() */ + heim_audit_addkv((heim_svc_req_desc)r, KDC_AUDIT_VIS, "target", "%s", + r->target ? r->target : ""); + heim_audit_setkv_bool((heim_svc_req_desc)r, "redir", !!r->redir); + + /* + * Make sure we have Kerberos credentials for cprinc. If we have them + * cached from earlier, this will be fast (all local), else it will involve + * taking a file lock and talking to the KDC using kx509 and PKINIT. + * + * Perhaps we could use S4U instead, which would speed up the slow path a + * bit. + */ + ret = k5_get_creds(r, K5_CREDS_CACHED); + if (ret) + return bad_403(r, ret, + "Could not acquire Kerberos credentials using PKINIT"); + + /* Acquire the Negotiate token and output it */ + if (ret == 0 && r->ccname != NULL) + ret = mk_nego_tok(r, &nego_tok, &nego_toksz); + + if (ret == 0) { + /* Look ma', Negotiate as an OAuth-like token system! */ + if (r->redir) + ret = resp(r, MHD_HTTP_TEMPORARY_REDIRECT, MHD_RESPMEM_PERSISTENT, + NULL, "", 0, nego_tok); + else + ret = resp(r, MHD_HTTP_OK, MHD_RESPMEM_MUST_COPY, + "application/x-negotiate-token", nego_tok, nego_toksz, + NULL); + } + + free(nego_tok); + return ret; +} + +static krb5_error_code +authorize_TGT_REQ(struct bx509_request_desc *r) +{ + krb5_principal p = NULL; + krb5_error_code ret; + const char *for_cname = r->for_cname ? r->for_cname : r->cname; + + if (for_cname == r->cname || strcmp(r->cname, r->for_cname) == 0) + return 0; + + ret = hx509_request_init(r->context->hx509ctx, &r->req); + if (ret) + return bad_500(r, ret, "Out of resources"); + heim_audit_addkv((heim_svc_req_desc)r, KDC_AUDIT_VIS, + "requested_krb5PrincipalName", "%s", for_cname); + ret = hx509_request_add_eku(r->context->hx509ctx, r->req, + ASN1_OID_ID_PKEKUOID); + if (ret == 0) + ret = hx509_request_add_pkinit(r->context->hx509ctx, r->req, + for_cname); + if (ret == 0) + ret = krb5_parse_name(r->context, r->cname, &p); + if (ret == 0) + ret = kdc_authorize_csr(r->context, "get-tgt", r->req, p); + krb5_free_principal(r->context, p); + hx509_request_free(&r->req); + r->req = NULL; + if (ret) + return bad_403(r, ret, "Not authorized to requested TGT"); + return ret; +} + +static heim_mhd_result +get_tgt_param_cb(void *d, + enum MHD_ValueKind kind, + const char *key, + const char *val) +{ + struct bx509_request_desc *r = d; + + if (strcmp(key, "address") == 0 && val) { + if (!krb5_config_get_bool_default(r->context, NULL, + FALSE, + "get-tgt", "allow_addresses", NULL)) { + krb5_set_error_message(r->context, r->error_code = ENOTSUP, + "Query parameter %s not allowed", key); + } else { + krb5_addresses addresses; + + r->error_code = _krb5_parse_address_no_lookup(r->context, val, + &addresses); + if (r->error_code == 0) + r->error_code = krb5_append_addresses(r->context, &r->tgt_addresses, + &addresses); + krb5_free_addresses(r->context, &addresses); + } + } else if (strcmp(key, "cname") == 0) { + /* Handled upstairs */ + ; + } else if (strcmp(key, "lifetime") == 0 && val) { + r->req_life = parse_time(val, "day"); + } else { + /* Produce error for unknown params */ + heim_audit_setkv_bool((heim_svc_req_desc)r, "requested_unknown", TRUE); + krb5_set_error_message(r->context, r->error_code = ENOTSUP, + "Query parameter %s not supported", key); + } + return r->error_code == 0 ? MHD_YES : MHD_NO /* Stop iterating */; +} + +/* + * Implements /get-tgt end-point. + * + * Query parameters: + * + * - cname= (client principal name, if not the same as the authenticated + * name, then this will be impersonated if allowed; may be + * given only once) + * + * - address= (IP address to add as a ticket address; may be given + * multiple times) + * + * - lifetime=