#!/usr/bin/env bash # # TROUBLESHOOTING # - If you see 'undefined reference to `AES_encrypt'', # make sure you have openssl installed. # If libcrypto.a is in a non-standard directory, try ./build -L[your-lib-dir] # - If you see 'undefined reference to `clock_gettime'', # try ./build -lrt instead. # - If you see 'x86.S:202: Error: junk at end of line, first unrecognized character is `,'', # try commenting the line in lib/bcrypt/x86.S. # - Take a look at the "Optional features" section. Some features have dependencies, # either make sure you have them or disable those features. # eg. mpw_color=0 ./build # # BUGS # masterpassword@lyndir.com # # AUTHOR # Maarten Billemont # cd "${BASH_SOURCE%/*}" shopt -s extglob set -e ### CONFIGURATION # Targets to build. if [[ $targets ]]; then read -ra targets <<< "$targets" else # Default targets. # Modify here or override using targets='mpw mpw-bench' ./build targets=( mpw # C CLI version of Master Password, requires libsodium or openssl-dev. #mpw-bench # C CLI Master Password benchmark utility. #mpw-tests # C Master Password algorithm test suite, requires libxml2. ) fi # Optional features. mpw_color=${mpw_color:-1} # Colorized Identicon, requires libncurses-dev. mpw_sodium=${mpw_sodium:-1} # Use libsodium if available instead of cperciva's libscrypt. # Default build flags. export CFLAGS="-O3 $CFLAGS" export LDFLAGS="$LDFLAGS" # Distribution specific configuration. # Homebrew - openssl for scrypt if hash brew 2>/dev/null; then opensslPath=$(brew --prefix openssl) CFLAGS+=" -I$opensslPath/include" LDFLAGS+=" -L$opensslPath/lib" fi ### DEPENDENCIES digest() { openssl sha -sha256 -binary < "$1" | od -t x1 -An -v | tr -d '[:space:]' } fetch() { if hash wget 2>/dev/null; then wget -O "${1##*/}" "$1" elif hash curl 2>/dev/null; then curl "$1" > "${1##*/}" fi } unpack() { printf 'Verifying package: %s, against digest: %s...' "$1" "$2" [[ $(digest "$1") = $2 ]] || { printf ' mismatch!\n' echo 2>&1 "Downloaded package doesn't match digest." exit 1 } printf ' OK!\n' if [[ $1 = *.tar.gz || $1 = *.tgz ]]; then tar -xvzf "$1" elif [[ $1 = *.tar.bz2 || $1 = *.tbz2 ]]; then tar -xvjf "$1" elif [[ $1 = *.tar ]]; then tar -xvf "$1" else echo 2>&1 "Don't know how to unpack: $1" fi files=( * ) if [[ -d $files ]] && (( ${#files[@]} == 1 )); then mv "$files"/* . rmdir "$files" fi } fetchSource() ( local name=${PWD##*/} source .source if [[ -e .unpacked ]]; then true elif [[ $pkg && -e "${pkg##*/}" ]]; then [[ -e src ]] || { echo echo "Unpacking: $name, using package..." ( mkdir src && cd src && unpack "../${pkg##*/}" "$pkg_sha256" ) touch .unpacked } elif [[ $git ]] && hash git 2>/dev/null; then [[ -e .git ]] || { echo echo "Fetching: $name, using git..." git clone "$git" src touch .unpacked } elif [[ $svn ]] && hash git 2>/dev/null && [[ -x "$(git --exec-path)/git-svn" ]]; then [[ -e .git ]] || { echo echo "Fetching: $name, using git-svn..." git svn clone --prefix=origin/ --stdlayout "$svn" src touch .unpacked } elif [[ $svn ]] && hash svn 2>/dev/null; then [[ -e .svn ]] || { echo echo "Fetching: $name, using svn..." svn checkout "$svn/trunk" src touch .unpacked } elif [[ $pkg ]]; then [[ -e src ]] || { echo echo "Fetching: $name, using package..." fetch "$pkg" ( mkdir src && cd src && unpack "../${pkg##*/}" "$pkg_sha256" ) touch .unpacked } else echo >&2 "error: Missing git-svn or svn." echo >&2 "error: Please install either or manually check out the sources" echo >&2 "error: from: $home" echo >&2 "error: into: $PWD/src" exit 1 fi if [[ ! -e .patched ]] && (( ${#patches[@]} )); then pushd src for patch in "${patches[@]}"; do echo echo "Patching: $name, for $patch..." patch -p0 < "../$patch.patch" done popd touch .patched fi ) depend() { local name=$1 echo echo "Checking dependency: $name..." [[ -e "lib/include/$name" ]] && return pushd "lib/$name" fetchSource pushd "src" echo echo "Configuring dependency: $name..." if [[ -e configure.ac ]]; then if [[ ! -e configure ]]; then # create configure using autotools. if ! hash aclocal || ! hash automake; then echo >&2 "Need autotools to build $name. Please install automake and autoconf." exit 1 fi aclocal autoheader autoconf mkdir -p config.aux automake --add-missing fi fi if [[ -e configure ]]; then ./configure fi echo echo "Building dependency: $name..." if [[ -e Makefile ]]; then if ! hash make; then echo >&2 "Need make to build $name. Please install GNU make." exit 1 fi make install -d "../../include/$name/" find . -name '*.h' -exec install -m 444 {} "../../include/$name/" \; else echo >&2 "error: Don't know how to build: $name" exit 1 fi popd popd } depend_scrypt() { if (( mpw_sodium )) && haslib sodium; then if [[ $CFLAGS != *HAS_SODIUM=1* ]]; then CFLAGS+=" -DHAS_SODIUM=1" LDFLAGS+=" -lsodium" fi return fi depend scrypt if [[ $CFLAGS != *HAS_CPERCIVA=1* ]]; then local objects=( "lib/scrypt/src/libcperciva/"*/*.o "lib/scrypt/src/lib/crypto/"*.o ) CFLAGS+=" -DHAS_CPERCIVA=1" LDFLAGS+=" -Llib/scrypt/src ${objects[*]}" fi } ### MPW mpw() { depend_scrypt echo echo "Building target: $target..." local CFLAGS=( $CFLAGS # library paths -I"lib/include" # mpw paths -I"core" -I"cli" ) local LDFLAGS=( $LDFLAGS # link libraries -l"crypto" ) # optional features (( mpw_color )) && CFLAGS+=( -DCOLOR ) LDFLAGS+=( -l"curses" ) cc "${CFLAGS[@]}" "$@" -c core/mpw-algorithm.c -o core/mpw-algorithm.o cc "${CFLAGS[@]}" "$@" -c core/mpw-types.c -o core/mpw-types.o cc "${CFLAGS[@]}" "$@" -c core/mpw-util.c -o core/mpw-util.o cc "${CFLAGS[@]}" "$@" "core/mpw-algorithm.o" "core/mpw-types.o" "core/mpw-util.o" \ "${LDFLAGS[@]}" "cli/mpw-cli.c" -o "mpw" echo "done! Now run ./install or use ./mpw" } ### MPW-BENCH mpw-bench() { depend_scrypt depend bcrypt echo echo "Building target: $target..." local CFLAGS=( $CFLAGS # library paths -I"lib/include" # mpw paths -I"core" -I"cli" ) local LDFLAGS=( $LDFLAGS # bcrypt "lib/bcrypt/src/crypt_blowfish.o" "lib/bcrypt/src/crypt_gensalt.o" "lib/bcrypt/src/wrapper.o" "lib/bcrypt/src/x86.o" # library paths -L"lib/bcrypt/src" # link libraries -l"crypto" ) cc "${CFLAGS[@]}" "$@" -c core/mpw-algorithm.c -o core/mpw-algorithm.o cc "${CFLAGS[@]}" "$@" -c core/mpw-types.c -o core/mpw-types.o cc "${CFLAGS[@]}" "$@" -c core/mpw-util.c -o core/mpw-util.o cc "${CFLAGS[@]}" "$@" "core/mpw-algorithm.o" "core/mpw-types.o" "core/mpw-util.o" \ "${LDFLAGS[@]}" "cli/mpw-bench.c" -o "mpw-bench" echo "done! Now use ./mpw-bench" } ### MPW-TESTS mpw-tests() { depend_scrypt echo echo "Building target: $target..." local CFLAGS=( $CFLAGS # library paths -I"lib/include" -I"/usr/include/libxml2" -I"/usr/local/include/libxml2" # mpw paths -I"core" -I"cli" ) local LDFLAGS=( $LDFLAGS # link libraries -l"crypto" -l"xml2" ) cc "${CFLAGS[@]}" "$@" -c core/mpw-algorithm.c -o core/mpw-algorithm.o cc "${CFLAGS[@]}" "$@" -c core/mpw-types.c -o core/mpw-types.o cc "${CFLAGS[@]}" "$@" -c core/mpw-util.c -o core/mpw-util.o cc "${CFLAGS[@]}" "$@" -c cli/mpw-tests-util.c -o cli/mpw-tests-util.o cc "${CFLAGS[@]}" "$@" "core/mpw-algorithm.o" "core/mpw-types.o" "core/mpw-util.o" \ "${LDFLAGS[@]}" "cli/mpw-tests-util.o" "cli/mpw-tests.c" -o "mpw-tests" echo "done! Now use ./mpw-tests" } ### TARGETS haslib() { cc -l"$1" -x c -o /dev/null - <<< 'int main() { return 0; }' } cc() { if hash llvm-gcc 2>/dev/null; then llvm-gcc "$@" elif hash gcc 2>/dev/null; then gcc -std=gnu99 "$@" elif hash clang 2>/dev/null; then clang "$@" else echo >&2 "Need a compiler. Please install GCC or LLVM." exit 1 fi } echo "Will build targets: ${targets[*]}..." for target in "${targets[@]}"; do "$target" "$@" done