2 # Program to build and sign debian packages, and upload those to a public reprepro repository.
3 # Copyright (c) 2015 Santiago Bassett <santiago.bassett@gmail.com>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software Foundation,
17 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 # CONFIGURATION VARIABLES
24 source_file="ossec-hids-${ossec_version}.tar.gz"
25 #packages=(ossec-hids ossec-hids-agent) # only options available
26 packages=(ossec-hids ossec-hids-agent)
28 # codenames=(sid jessie wheezy precise trusty utopic)
29 codenames=(sid jessie wheezy precise trusty utopic)
31 # For Debian use: sid, jessie or wheezy (hardcoded in update_changelog function)
32 # For Ubuntu use: lucid, precise, trusty or utopic
33 codenames_ubuntu=(precise trusty utopic)
34 codenames_debian=(sid jessie wheezy)
36 # architectures=(amd64 i386) only options available
37 architectures=(amd64 i386)
44 debian_files_path="/home/ubuntu/debian_files"
47 scriptpath=$( cd $(dirname $0) ; pwd -P )
48 logfile=$scriptpath/ossec_packages.log
52 # Function to write to LOG_FILE
56 if [ ! -e "$logfile" ] ; then
61 local logtime=`date "+%Y-%m-%d %H:%M:%S"`
62 echo $logtime": $text" | tee -a $logfile;
68 # Check if element is in an array
69 # Arguments: element array
73 for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
84 This tool can be used to generate OSSEC packages for Ubuntu and Debian.
86 CONFIGURATION: The script is currently configured with the following variables:
87 * Packages: ${packages[*]}.
88 * Distributions: ${codenames[*]}.
89 * Architectures: ${architectures[*]}.
90 * OSSEC version: ${ossec_version}.
91 * Source file: ${source_file}.
92 * Signing key: ${signing_key}.
94 USAGE: Command line arguments available:
95 -h | --help Displays this help.
96 -u | --update Updates chroot environments.
97 -d | --download Downloads source file and prepares source directories.
98 -b | --build Builds deb packages.
99 -s | --sync Synchronizes with the apt-get repository.
105 # Reads latest package version from changelog file
106 # Argument: changelog_file
108 read_package_version()
110 if [ ! -e "$1" ] ; then
111 echo "Error: Changelog file $1 does not exist" | write_log
114 local regex="^ossec-hids[A-Za-z-]* \([0-9]+.*[0-9]*.*[0-9]*-([0-9]+)[A-Za-z]*\)"
117 if [[ $line =~ $regex ]]; then
118 package_version="${BASH_REMATCH[1]}"
122 local check_regex='^[0-9]+$'
123 if ! [[ ${package_version} =~ ${check_regex} ]]; then
124 echo "Error: Package version could not be read from $1" | write_log
131 # Updates changelog file with new codename, date and debdist.
132 # Arguments: changelog_file codename
136 local changelog_file=$1
137 local changelog_file_tmp="${changelog_file}.tmp"
140 if [ ! -e "$1" ] ; then
141 echo "Error: Changelog file $1 does not exist" | write_log
145 local check_codenames=( ${codenames_debian[*]} ${codenames_ubuntu[*]} )
146 if ! contains_element $codename ${check_codenames[*]} ; then
147 echo "Error: Codename $codename not contained in codenames for Debian or Ubuntu" | write_log
152 if [ $codename = "sid" ]; then
153 local debdist="unstable"
154 elif [ $codename = "jessie" ]; then
155 local debdist="testing"
156 elif [ $codename = "wheezy" ]; then
157 local debdist="stable"
161 if contains_element $codename ${codenames_ubuntu[*]} ; then
162 local debdist=$codename
166 local changelogtime=$(date -R)
167 local last_date_changed=0
169 local regex1="^(ossec-hids[A-Za-z-]* \([0-9]+.*[0-9]*.*[0-9]*-[0-9]+)[A-Za-z]*\)"
170 local regex2="( -- [[:alnum:]]*[^>]*> )[[:alnum:]]*,"
172 if [ -f ${changelog_file_tmp} ]; then
173 rm -f ${changelog_file_tmp}
175 touch ${changelog_file_tmp}
177 IFS='' #To preserve line leading whitespaces
180 if [[ $line =~ $regex1 ]]; then
181 line="${BASH_REMATCH[1]}$codename) $debdist; urgency=low"
183 if [[ $line =~ $regex2 ]] && [ $last_date_changed -eq 0 ]; then
184 line="${BASH_REMATCH[1]}$changelogtime"
187 echo "$line" >> ${changelog_file_tmp}
188 done < ${changelog_file}
190 mv ${changelog_file_tmp} ${changelog_file}
195 # Update chroot environments
199 for codename in ${codenames[@]}
201 for arch in ${architectures[@]}
203 echo "Updating chroot environment: ${codename}-${arch}" | write_log
204 if sudo DIST=$codename ARCH=$arch pbuilder update ; then
205 echo "Successfully updated chroot environment: ${codename}-${arch}" | write_log
207 echo "Error: Problem detected updating chroot environment: ${codename}-${arch}" | write_log
215 # Downloads packages and prepare source directories.
216 # This is needed before building the packages.
221 # Checking that Debian files exist for this version
222 for package in ${packages[*]}
224 if [ ! -d ${debian_files_path}/${ossec_version}/$package/debian ]; then
225 echo "Error: Couldn't find debian files directory for $package, version ${ossec_version}" | write_log
231 if wget -O $scriptpath/${source_file} -U ossec https://github.com/ossec/ossec-hids/archive/${ossec_version}.tar.gz ; then
232 echo "Successfully downloaded source file ${source_file} from ossec.net" | write_log
234 echo "Error: File ${source_file} was could not be downloaded" | write_log
238 # Uncompressing files
239 tmp_directory=$(echo ${source_file} | sed -e 's/.tar.gz$//')
240 if [ -d ${scriptpath}/${tmp_directory} ]; then
241 echo " + Deleting previous directory ${scriptpath}/${tmp_directory}" | write_log
242 sudo rm -rf ${scriptpath}/${tmp_directory}
244 tar -xvzf ${scriptpath}/${source_file}
245 if [ ! -d ${scriptpath}/${tmp_directory} ]; then
246 echo "Error: Couldn't find uncompressed directory, named ${tmp_directory}" | write_log
250 # Organizing directories structure
251 for package in ${packages[*]}
253 if [ -d ${scriptpath}/$package ]; then
254 echo " + Deleting previous source directory ${scriptpath}/$package" | write_log
255 sudo rm -rf ${scriptpath}/$package
257 mkdir $scriptpath/$package
258 cp -pr $scriptpath/${tmp_directory} $scriptpath/$package/$package-${ossec_version}
259 cp -p $scriptpath/${source_file} $scriptpath/$package/${package}_${ossec_version}.orig.tar.gz
260 cp -pr ${debian_files_path}/${ossec_version}/$package/debian $scriptpath/$package/${package}-${ossec_version}/debian
262 rm -rf $scriptpath/${tmp_directory}
264 echo "The packages directories for ${packages[*]} version ${ossec_version} have been successfully prepared." | write_log
274 for package in ${packages[@]}
276 for codename in ${codenames[@]}
278 for arch in ${architectures[@]}
281 echo "Building Debian package ${package} ${codename}-${arch}" | write_log
283 local source_path="$scriptpath/${package}/${package}-${ossec_version}"
284 local changelog_file="${source_path}/debian/changelog"
285 if [ ! -f ${changelog_file} ] ; then
286 echo "Error: Couldn't find changelog file for ${package}-${ossec_version}" | write_log
290 # Updating changelog file with new codename, date and debdist.
291 if update_changelog ${changelog_file} ${codename} ; then
292 echo " + Changelog file ${changelog_file} updated for $package ${codename}-${arch}" | write_log
294 echo "Error: Changelog file ${changelog_file} for $package ${codename}-${arch} could not be updated" | write_log
298 # Setting up global variable package_version, used for deb_file and changes_file
299 read_package_version ${changelog_file}
300 local deb_file="${package}_${ossec_version}-${package_version}${codename}_${arch}.deb"
301 local changes_file="${package}_${ossec_version}-${package_version}${codename}_${arch}.changes"
302 local dsc_file="${package}_${ossec_version}-${package_version}${codename}.dsc"
303 local results_dir="/var/cache/pbuilder/${codename}-${arch}/result/${package}"
304 local base_tgz="/var/cache/pbuilder/${codename}-${arch}-base.tgz"
305 local cache_dir="/var/cache/pbuilder/${codename}-${arch}/aptcache"
307 # Creating results directory if it does not exist
308 if [ ! -d ${results_dir} ]; then
309 sudo mkdir -p ${results_dir}
312 # Building the package
314 if sudo /usr/bin/pdebuild --use-pdebuild-internal --architecture ${arch} --buildresult ${results_dir} -- --basetgz \
315 ${base_tgz} --distribution ${codename} --architecture ${arch} --aptcache ${cache_dir} --override-config ; then
316 echo " + Successfully built Debian package ${package} ${codename}-${arch}" | write_log
318 echo "Error: Could not build package $package ${codename}-${arch}" | write_log
322 # Checking that resulting debian package exists
323 if [ ! -f ${results_dir}/${deb_file} ] ; then
324 echo "Error: Could not find ${results_dir}/${deb_file}" | write_log
328 # Checking that package has at least 50 files to confirm it has been built correctly
329 local files=$(sudo /usr/bin/dpkg --contents ${results_dir}/${deb_file} | wc -l)
330 if [ "${files}" -lt "50" ]; then
331 echo "Error: Package ${package} ${codename}-${arch} contains only ${files} files" | write_log
332 echo "Error: Check that the Debian package has been built correctly" | write_log
335 echo " + Package ${results_dir}/${deb_file} ${codename}-${arch} contains ${files} files" | write_log
338 # Signing Debian package
339 if [ ! -f "${results_dir}/${changes_file}" ] || [ ! -f "${results_dir}/${dsc_file}" ] ; then
340 echo "Error: Could not find dsc and changes file in ${results_dir}" | write_log
343 sudo /usr/bin/expect -c "
344 spawn sudo debsign --re-sign -k${signing_key} ${results_dir}/${changes_file}
345 expect -re \".*Enter passphrase:.*\"
346 send \"${signing_pass}\r\"
347 expect -re \".*Enter passphrase:.*\"
348 send \"${signing_pass}\r\"
349 expect -re \".*Successfully signed dsc and changes files.*\"
351 if [ $? -eq 0 ] ; then
352 echo " + Successfully signed Debian package ${changes_file} ${codename}-${arch}" | write_log
354 echo "Error: Could not sign Debian package ${changes_file} ${codename}-${arch}" | write_log
358 # Verifying signed changes and dsc files
359 if sudo gpg --verify "${results_dir}/${dsc_file}" && sudo gpg --verify "${results_dir}/${changes_file}" ; then
360 echo " + Successfully verified GPG signature for files ${dsc_file} and ${changes_file}" | write_log
362 echo "Error: Could not verify GPG signature for ${dsc_file} and ${changes_file}" | write_log
366 echo "Successfully built and signed Debian package ${package} ${codename}-${arch}" | write_log
373 # Synchronizes with the external repository, uploading new packages and ubstituting old ones.
376 for package in ${packages[@]}
378 for codename in ${codenames[@]}
380 for arch in ${architectures[@]}
383 # Reading package version from changelog file
384 local source_path="$scriptpath/${package}/${package}-${ossec_version}"
385 local changelog_file="${source_path}/debian/changelog"
386 if [ ! -f ${changelog_file} ] ; then
387 echo "Error: Couldn't find ${changelog_file} for package ${package} ${codename}-${arch}" | write_log
391 # Setting up global variable package_version, used for deb_file and changes_file.
392 read_package_version ${changelog_file}
393 local deb_file="${package}_${ossec_version}-${package_version}${codename}_${arch}.deb"
394 local changes_file="${package}_${ossec_version}-${package_version}${codename}_${arch}.changes"
395 local results_dir="/var/cache/pbuilder/${codename}-${arch}/result/${package}"
396 if [ ! -f ${results_dir}/${deb_file} ] || [ ! -f ${results_dir}/${changes_file} ] ; then
397 echo "Error: Couldn't find ${deb_file} or ${changes_file}" | write_log
401 # Uploading package to repository
403 echo "Uploading package ${changes_file} for ${codename} to OSSEC repository" | write_log
404 if sudo /usr/bin/dupload --nomail -f --to ossec-repository ${changes_file} ; then
405 echo " + Successfully uploaded package ${changes_file} for ${codename} to OSSEC repository" | write_log
407 echo "Error: Could not upload package ${changes_file} for ${codename} to the repository" | write_log
411 # Checking if it is an Ubuntu package
412 if contains_element $codename ${codenames_ubuntu[*]} ; then
418 # Moving package to the right directory at the OSSEC apt repository server
419 echo " + Adding package /opt/incoming/${deb_file} to server repository for ${codename} distribution" | write_log
420 if [ $is_ubuntu -eq 1 ]; then
421 remove_package="cd /var/www/repos/apt/ubuntu; reprepro -A ${arch} remove ${codename} ${package}"
422 include_package="cd /var/www/repos/apt/ubuntu; reprepro includedeb ${codename} /opt/incoming/${deb_file}"
424 remove_package="cd /var/www/repos/apt/debian; reprepro -A ${arch} remove ${codename} ${package}"
425 include_package="cd /var/www/repos/apt/debian; reprepro includedeb ${codename} /opt/incoming/${deb_file}"
429 spawn sudo ssh root@ossec-repository \"${remove_package}\"
430 expect -re \"Not removed as not found.*\" { exit 1 }
431 expect -re \".*enter passphrase:.*\" { send \"${signing_pass}\r\" }
432 expect -re \".*enter passphrase:.*\" { send \"${signing_pass}\r\" }
433 expect -re \".*deleting.*\"
437 spawn sudo ssh root@ossec-repository \"${include_package}\"
438 expect -re \"Skipping inclusion.*\" { exit 1 }
439 expect -re \".*enter passphrase:.*\"
440 send \"${signing_pass}\r\"
441 expect -re \".*enter passphrase:.*\"
442 send \"${signing_pass}\r\"
443 expect -re \".*Exporting.*\"
445 echo "Successfully added package ${deb_file} to server repository for ${codename} distribution" | write_log
452 # If there are no arguments, display help
453 if [ $# -eq 0 ]; then
458 # Reading command line arguments
486 echo "Unknown command line argument."
493 # vim: tabstop=2 expandtab shiftwidth=2 softtabstop=2