password protected folder for a tiny web server

I have a tiny web server “lighttpd” at a NAS (Network Attached Storage). It gets more popular than the conventional appache in last years (in particular for light web server markets). Lighttpd is very nice, as it’s  light weight, easy to configure and most of all, easy to password-protect folders. There are 3 password formats:

plain A file which contains username and the clear text password  separated by a colon. Each entry is terminated by a single newline. e.g.

agent007:secret

htpasswd A file which contains username and the crypt()’ed password seperated by a colon. Each entry is terminated by a single newline.

e.g.: agent007:XWY5JwrAVBXsQ

You can use htpasswd from the apache distribution to manage those files.

$ htpasswd file4lighttpd.user.htpasswd agent007

htdigest A file which contains a line per user identification. Each line contains the username, realm and a MD5 value separated by colons. eg

agent007:download area:8364d0044ef57b3defcfa141e8f77b65

The MD5 value is the checksum of a string concatenating the username, realm and password, separated by colons.

There are many ways to create htdigest file. I prefer the 2nd approach, as it is easy and need non additional installation. The important thing is to restrict access to your password file. You don't want it has rwxrwxrwx access. I keep my as

-rw-r--r-- 1 root root 140 Jun 19  2008 /etc/lighttpd/lighttpd.htdigest.user

1. You can use htdigest from the apache distribution to manage that kind of files.

$ htdigest lighttpd.user.htdigest 'download area' agent007

2. Using md5sum can also generate the password-hash:

#!/bin/sh
user=$1
realm=$2
pass=$3

hash=`echo -n "$user:$realm:$pass" | md5sum | cut -b -32`

echo "$user:$realm:$hash"

To use it (spaces between arguments!):

$ htdigest.sh 'agent007' 'download area' 'secret'
agent007:download area:8364d0044ef57b3defcfa141e8f77b65

3. The pro way, this script can be used for service:

#!/bin/sh

export PATH="/bin:/usr/bin:/usr/sbin:$PATH" 

# when input ctrl-c, remove lockfile and exit
trap '[ $lockstart -eq 1 ] && unlock $pfile && exit 0 || exit 0' INT

pfile="/etc/lighttpd/conf.d/lighttpd.user"
lockstart=0
remove=0

errmsg() {
    echo "$1" > /dev/stderr
}

user_check() {
    check_user=$1
    grep "^${check_user}:" ${pfile} >& /dev/null
    return $?
}

lock() {
    lockfile="$1"
    lockfile="${lockfile}.lock" 

    [ -f "${lockfile}" ] && {
        errmsg "WARNING: lock file ${lockfile} is already exists"
        errmsg "         Wait minites for end of previous working ..."
    }

    while [ -f "${lockfile}" ]; do echo >& /dev/null ; done
    touch ${lockfile}
    lockstart=1
}

unlock() {
    lockfile="$1"
    lockfile="${lockfile}.lock" 

    [ -f "${lockfile}" ] && rm -f ${lockfile} && lockstart=0
}

usage() {
    errmsg
    errmsg "lightdigest: lighttpd htdigest password generation program"
    errmsg "Scripted by JoungKyun.Kim <http://oops.org>"
    errmsg
    errmsg "Usage: $0 -[hd] -u user -p pass -r realm [-f password_file]"
    errmsg "Options:"
    errmsg "    -h          print this help messages"
    errmsg "    -u user     username"
    errmsg "    -p pass     password"
    errmsg "    -r realm    realm name"
    errmsg "    -f filename password file [default: /etc/lighttpd/conf.d/lighttpd.user"
    errmsg "    -d          remove user"
    errmsg

    [ $lockstart -eq 1 ] && rm -f ${pfile}.lock

    exit 1
}   

opts=$(getopt df:hp:r:u: $*)
[ $? != 0 ] && usage

set -- ${opts}
for i
do
    case "$i" in
        -d) remove=1; shift;;
        -f) pfile="$2"; shift; shift;;
        -p) pass="$2"; shift; shift;;
        -r) realm="$2"; shift; shift;;
        -u) user="$2"; shift; shift;;
        --) shift; break;
    esac
done

#echo $user
#echo $realm
#echo $pass
#echo $pfile
#echo $remove

[ -z "$user" ] && errmsg "ERROR: User is none!!" && usage
[ ${remove} -eq 0 -a -z "${realm}" ] && errmsg "ERROR: Realm is none!!" && usage

if [ -z "${pass}" -a ${remove} -eq 0 ]; then
    echo -n "Input new password : "
    read newpass
    echo -n "Reinput password for confirm : "
    read renewpass

    if [ "${newpass}" != "${renewpass}" ]; then
        errmsg "ERROR: Password is not match"
        exit 1
    fi

    pass=${newpass}
fi

lock ${pfile}

if [ ${remove} -eq 0 ]; then
    # User Add Mode
    hash=$(echo -n "${user}:${realm}:${pass}" | md5sum | cut -b -32)
    user_check ${user}
    already=$?

    [ -f "${pfile}" ] && cp -af ${pfile} ${pfile}.bak
    if [ ${already} -eq 0 ]; then
        # already exists
        perl -pi -e "s/^${user}:.*$/${user}:${realm}:${hash}/g" ${pfile}
    else
        # add new user
        echo "${user}:${realm}:${hash}" >> ${pfile}
    fi
else
    # User Remove Mode
    tmp_htdigest="/tmp/lighttpd-htdiges.tmp.$$"
    cp -af ${pfile} ${pfile}.bak
    grep -v "^${user}:" ${pfile} > ${tmp_htdigest}
    mv -f ${tmp_htdigest} ${pfile}
fi

unlock ${pfile}

exit 0

To use it (don't use realm value! getopt of some bash version has bug.) :

  # if you add or change
  $ lightdigest -u USERNAME -r REALM_NAME -f PASSWORD_FILE_PATH
  # if you want to remove use
  $ lightdigest -d -u USERNAME
About these ads

One response to “password protected folder for a tiny web server

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s