#!/bin/bash
#
# $Id: archive-queue 68 2004-08-31 07:49:33Z guillem $
#
# Copyright (C) 2003 Robert Millan <rmh@debian.org>
# Copyright (C) 2003, 2004 Guillem Jover <guillem@debian.org>
#
# 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.
#

# Import library

. archive-lib

######
# data validation functions

verify_symlink_attack ()
{
  changes_file=$1

  if [ -L $changes_file ]; then
    return 1
  else
    return 0
  fi
}

verify_size ()
{
  local changes_file=$1
  local changes_size=`stat -c "%s" $changes_file`

  if [ $changes_size -gt 100000 ]; then
    return 1
  else
    return 0
  fi
}

verify_gpg_signature ()
{
  local changes_file=$1
  local archive_file=$2
  local verify_result="`gpg $archive_keyrings --no-tty --status-fd=2 --verify $changes_file 2>&1`"

  if wrong=`echo "$verify_result" | grep '^\[GNUPG:\] BADSIG '`; then
    return 1
  elif good=`echo "$verify_result" | grep '^\[GNUPG:\] GOODSIG '`; then
    local signed_by="`echo "$good" | cut -d\  -f4-`"
    changes_strip < $changes_file \
      | formail -a"Signed-By: $signed_by" > $archive_file
    return 0
  else
    return 1
  fi
}

verify_md5sums ()
{
  local archive_file=$1
  local files=`fetch_secure_files $archive_file`

  if err=`mv $files $unchecked_dir` ; then
    log queue "mv_unchecked_success ${archive_file##*/}"

    if fetch_md5sums < $archive_file | \
       ( cd $unchecked_dir; md5sum.textutils -c >& /dev/null ); then
      return 0
    else
      return 1
    fi
  else
    script_error "verify_md5sums" "$err"
    log queue "mv_unchecked_failed ${archive_file##*/}"
    return 1
  fi

}

verify_suite ()
{
  local archive_file=$1
  local target_suite=`fetch_field "Distribution" < $archive_file`
  local c_target_suite=`canonic_suite $target_suite`

  for suite in $suite_list; do
    if [ "`canonic_suite $suite`" = "$c_target_suite" ]; then
      return 0
    fi
  done

  return 1
}

verify_arch ()
{
  local archive_file=$1
  local target_arches=`fetch_field "Architecture" < $archive_file`
  local suite=`fetch_field "Distribution" < $archive_file`

  for arch in $target_arches; do
    if ! valid_arch $suite $arch; then
      return 1
    fi
  done

  return 0
}

# file output

queue_accepted ()
{
  local changes_file=$1
  local archive_file=$2
  local signer=$3
  local files=`fetch_secure_files $archive_file`
  local files_install="$files $changes_file $archive_file"

  files_owner_perms $files_install

  if err=`mv $files_install $accepted_dir` ; then
    log queue "mv_accepted_success ${archive_file##*/}"
    notice_accepted $changes_file "$files" "$signer"
    return 0
  else
    script_error "queue_accepted" "$err"
    log queue "mv_accepted_failed ${archive_file##*/}"
    return 1
  fi
}

queue_rejected ()
{
  local outcome=$1
  local changes_file=$2
  local archive_file=$3
  local signer=$4
  local files=

  mkdir -p $rejected_daily_dir

  if [ "$signer" ]; then
    files="`fetch_secure_files $archive_file` $changes_file $archive_file"
  else
    files=$changes_file
  fi

  if err=`mv $files $rejected_daily_dir` ; then
    log queue "mv_rejected_success ${archive_file##*/}"
    notice_rejected $changes_file "$outcome" "$signer"
    return 0
  else
    script_error "queue_rejected" "$err"
    log queue "mv_rejected_failed ${archive_file##*/}"
    return 1
  fi
}

# message output

notice_rejected ()
{
  local changes_file=${1##*/}
  local outcome=$2
  local signer=$3

  ( cat <<-HERE
Uploader: $signer
Host: `hostname -f`
Rejected: $changes_file
Reason: $outcome
HERE
  ) | msg_queue "$changes_file REJECTED" "$signer"
}


notice_accepted ()
{
  local changes_file=${1##*/}
  local files=$2
  local signer=$3

  ( cat <<-HERE
Uploader: $signer
Host: `hostname -f`
Accepted: $changes_file
Files:
$files
HERE
  ) | msg_queue "$changes_file ACCEPTED" "$signer"
}

script_error ()
{
  # echo "$@" | mail -s "Error in `basename $0` ($1): $2" $archive_maint
  log queue "Error in `basename $0` ($1): $2"
}

#
# main
#

cd $incoming_dir

shopt -s nullglob

for changes_file in *.changes; do

  cd $incoming_dir

  if ! fuser $changes_file; then
    mv -f $changes_file $unchecked_dir/$changes_file

    changes_file=$unchecked_dir/$changes_file
    archive_file=$unchecked_dir/$(basename $changes_file changes)archive

    if ! verify_symlink_attack $changes_file; then
      queue_rejected "error-symlink-attack" $changes_file
      continue
    fi

    if ! verify_size $changes_file; then
      queue_rejected "toobig-changes-file" $changes_file
      continue
    fi

    if ! verify_gpg_signature $changes_file $archive_file; then
      queue_rejected "wrong-signature" $changes_file
      continue
    fi

    signer=`fetch_field "Signed-By" < $archive_file`

    if ! verify_md5sums $archive_file; then
      queue_rejected "wrong-md5sums" $changes_file $archive_file "$signer"
      continue
    fi

    cd $unchecked_dir

    if ! verify_suite $archive_file; then
      queue_rejected "wrong-suite" $changes_file $archive_file "$signer"
      continue
    fi

    if ! verify_arch $archive_file; then
      queue_rejected "wrong-arch" $changes_file $archive_file "$signer"
      continue
    fi

    queue_accepted $changes_file $archive_file "$signer"
  fi
done

cd -

