#!/bin/sh # # $Id$ # # sc: ser control; tool for maintaining ser's databases # # History: # -------- # 2003-04-06 this is a hack, from serctl, to make work with postgres # 2003-02-23 Thomas's start|stop commands checked in # # To-DO: # ----- # - generalization for other than mysql databases # - front-end to updating administrative mysql password would # be a convenient thing to have # # I copy this over the top of the existing serctl program. # # configuration for starting/stopping ser PID_FILE=/var/run/ser.pid SYSLOG=1 # 0=output to console, 1=output to syslog STARTOPTIONS= # for example -dddd # ser's FIFO server if [ -z "$SER_FIFO" ]; then SER_FIFO=/tmp/ser_fifo fi # period in which stats are reprinted if [ -z "$WATCH_PERIOD" ] ; then WATCH_PERIOD=2 fi PW="test" # SQL config if [ -z "$SQL_DB" ] ; then SQL_DB=ser fi if [ -z "$SQL_HOST" ] ; then SQL_HOST=localhost fi if [ -z "$SQL_PORT" ] ; then SQL_PORT=5432 fi if [ -z "$SQL_USER" ] ; then SQL_USER=ser fi # the read-only user for whom password may be stored here if [ -z "$RO_USER" ] ; then RO_USER=serro fi if [ -z "$RO_PW" ] ; then RO_PW=47serro11 fi # binaries GENHA1='gen_ha1' PGSQL='psql' SER='sr' LAST_LINE='tail -1' # ACL name verification VERIFY_ACL=1 ACL_GROUPS="local ld int voicemail free-pstn" # expiration time for alias table FOREVER='2020-05-28 21:32:15' FOREVER_REL=1073741823 VERSION='$Revision$' #### SQL names # Usr Loc Table USRLOC=location USER_COLUMN=username CALLID_COLUMN=callid # subscriber table TABLE=subscriber REALM_COLUMN=domain HA1_COLUMN=HA1 HA1B_COLUMN=HA1B PASSWORD_COLUMN=password SUBSCRIBER_COLUMN='username' EMAIL_COLUMN=email_address SUB_CREATED_COLUMN=datetime_created SUB_MODIFIED_COLUMN=datetime_modified PHP_LIB_COLUMN=phplib_id # acl table ACL_TABLE=grp ACL_USER_COLUMN=user ACL_GROUP_COLUMN=grp ACL_MODIFIED_COLUMN=last_modified # aliases table A_TABLE=aliases A_USER_COLUMN=user A_CONTACT_COLUMN=contact A_EXPIRES_COLUMN=expires A_Q_COLUMN=q A_CALLID_COLUMN=callid A_CSEQ_COLUMN=cseq A_LAST_MODIFIED_COLUMN=last_modified FIFO_DBG=0 #=================================================================== usage() { CMD=`basename $0` if [ "0$VERIFY_ACL" -eq 1 ] ; then EXTRA_TEXT="ACL privileges are: $ACL_GROUPS" fi cat < .. add a new subscriber (*) $CMD passwd ......... change user's password (*) $CMD rm ...................... delete a user (*) $CMD mail .................... send an email to a user $CMD alias show [] ............... show aliases $CMD alias rm ................... remove an alias $CMD alias add ............ add an aliases * access control lists * $CMD acl show [] .............. show user membership $CMD acl grant ....... grant user membership (*) $CMD acl revoke [] .... grant user membership(s) (*) * usrloc * $CMD ul show []................ show in-RAM online users $CMD ul rm ................... delete user's UsrLoc entries $CMD ul add ............ introduce a permanent UrLoc entry $CMD showdb [] ................ show online users flushed in DB * server health * $CMD monitor ............................ show internal status $CMD ps ................................. show runnig processes $CMD fifo ............................... send raw commands to FIFO * server control * $CMD start .............................. start ser $CMD stop ............................... stop ser $CMD restart ............................ restart ser Commands labeled with (*) will prompt for a MySQL password. If the variable PW is set, the password will not be prompted. $EXTRA_TEXT EOF } # check the parameter if it is a valid SIP URI # quite simplified now -- it captures just very basic # errors check_uri() { echo "$1" | grep -E "^sip:([a-zA-Z0-9_]+@)?.*\..*" } #params: none # output: PW prompt_pw() { if [ -z "$PW" ] ; then savetty=`stty -g` printf "Postgres password: " stty -echo read PW stty $savetty echo fi } # process output from FIFO server; if everything is ok # skip the first "ok" line and proceed to returned # parameters filter_fl() { # tail +2 awk 'BEGIN {line=0;IGNORECASE=1;} {line++} line==1 && /^200 ok/ { next } { print }' } fifo_cmd() { if [ "0${FIFO_DBG}" -eq 1 ] ; then echo "entering fifo_cmd $*" fi if [ "$#" -lt 1 ]; then echo "ERROR: fifo_cmd must take at least command name as parameter" exit fi name=ser_receiver_$$ path=/tmp/$name if [ ! -w $SER_FIFO ]; then echo "Error opening ser's FIFO $SER_FIFO" echo "Make sure you have line fifo=$SER_FIFO in your config" exit 1 fi mkfifo $path if [ $? -ne 0 ] ; then echo "error opening read fifo $path" exit 1 fi chmod a+w $path # construct the command now CMD=":$1:$name\n"; shift while [ -n "$1" ] ; do CMD="${CMD}${1}\n" shift done CMD="${CMD}\n" trap "rm -f $path; exit 1" 2 # start reader now so that it is ready for replies # immediately after a request was sent out cat < $path | filter_fl & # issue FIFO request (printf taken to deal with \n) printf "$CMD" > $SER_FIFO # wait for the reader to complete wait rm $path if [ "0${FIFO_DBG}" -eq 1 ] ; then printf "FIFO command was:\n$CMD" fi } # $1 = name $2=path $3=attempt print_stats() { echo "[cycle #: $3; if constant make sure server lives and fifo is on]" cat < $2 | filter_fl & cat > $SER_FIFO < $SER_FIFO << EOF :uptime:$1 EOF wait echo echo Transaction Statistics cat < $2 | filter_fl & cat > $SER_FIFO < $SER_FIFO < $SER_FIFO <&2 stty $savetty echo >&2 fi $PGSQL $2\ -A -q -t \ -P fieldsep=" " \ -h $SQL_HOST \ -U $SQL_USER \ $SQL_DB \ -c "$1" } # input: sql query, optional mysql command-line params sql_ro_query() { $PGSQL $2\ -h $SQL_HOST \ -U $SQL_USER \ $SQL_DB \ -c "$1" } # input: sql query, optional mysql command-line params sql_ro_raw_query() { $PGSQL $2\ -A -q -t \ -P fieldsep=" " \ -h $SQL_HOST \ -U $SQL_USER \ $SQL_DB \ -c "$1" } usrloc() { if [ "$#" -lt 2 ] ; then echo "usrloc: too few parameters" exit 1 fi if [ "$1" = "alias" ] ; then TABLE="$A_TABLE" elif [ "$1" = "ul" ] ; then TABLE="$USRLOC" else echo "usrloc: unknown table name" exit 1 fi shift case $1 in show) if [ $# -eq 2 ] ; then fifo_cmd ul_show_contact $TABLE $2 elif [ $# -eq 1 ] ; then fifo_cmd ul_dump else echo "wrong number of params for usrloc show" usage exit 1 fi exit $? ;; add) if [ $# -ne 3 ] ; then usage exit 1 fi shift check_uri "$2" if [ "$?" -ne "0" ] ; then echo "$2 is not a valid URI" exit 1 fi fifo_cmd ul_add "$TABLE" "$1" "$2" "$FOREVER_REL" "1.00" "0" exit $? ;; rm) if [ $# -ne 2 ] ; then usage exit 1 fi shift fifo_cmd ul_rm $TABLE $1 ;; *) usage exit 1 ;; esac } acl() { case $1 in show) if [ $# -eq 2 ] ; then is_user $2 if [ $? -ne 0 ] ; then echo non-existent user exit 1; fi CLAUSE=" WHERE $ACL_USER_COLUMN='$2' " elif [ $# -ne 1 ] ; then usage exit 1 fi QUERY="select * FROM $ACL_TABLE $CLAUSE ; " sql_ro_query "$QUERY" ;; grant) if [ $# -lt 3 ] ; then usage exit 1 fi prompt_pw is_user $2 if [ $? -ne 0 ] ; then echo non-existent user exit 1 fi SIP_USER="$2" shift 2 while [ $# -gt 0 ] ; do if [ $VERIFY_ACL -eq 1 ] ; then found=0 for i in $ACL_GROUPS ; do if [ "$1" = "$i" ] ; then found=1 break fi done if [ $found -eq 0 ] ; then echo "Invalid privilege: $1 ignored" shift continue fi fi QUERY="insert into $ACL_TABLE \ ($ACL_USER_COLUMN,$ACL_GROUP_COLUMN,$ACL_MODIFIED_COLUMN) \ values ('$SIP_USER','$1', now());" sql_query "$QUERY" if [ $? -ne 0 ] ; then echo "SQL Error" exit 1 fi shift done $0 acl show $SIP_USER ;; revoke) if [ $# -eq 3 ] ; then CLAUSE=" and $ACL_GROUP_COLUMN='$3' " elif [ $# -ne 2 ] ; then usage exit 1 fi QUERY="delete from $ACL_TABLE where \ $ACL_TABLE.$ACL_USER_COLUMN='$2' $CLAUSE" sql_query "$QUERY" $0 acl show $2 ;; *) usage exit 1 ;; esac } # params: user # output: false if exists, true otherwise is_user() { QUERY="select count(*) from $TABLE \ where $SUBSCRIBER_COLUMN='$1' and $REALM_COLUMN='$SIP_DOMAIN';" CNT=`sql_ro_raw_query "$QUERY" | grep -v ERROR | $LAST_LINE` if [ "0$CNT" -eq 0 ] ; then false else true fi } # params: user, password # output: HA1, HA1B credentials() { HA1=`$GENHA1 $1 $SIP_DOMAIN $2` if [ $? -ne 0 ] ; then echo "HA1 calculation failed" exit 1 fi HA1B=`$GENHA1 "$1@$SIP_DOMAIN" $SIP_DOMAIN $2` if [ $? -ne 0 ] ; then echo "HA1B calculation failed" exit 1 fi } #================================================================ if [ -z "$SIP_DOMAIN" ] ; then echo echo "You need to set environment variable SIP_DOMAIN (e.g. to 'foobar.com') first" echo # This confuses new users cause its easy to miss the information above # usage exit 1 fi # if the script calls itself ... export PW case $1 in start) DIR=`dirname $0` echo printf "Starting SER : " if [ -r $PID_FILE ] ; then echo "PID file exists! ($PID_FILE) already running?" exit 1 else if [ $SYSLOG = 1 ] ; then $DIR/ser -P $PID_FILE $STARTOPTIONS 1>/dev/null 2>/dev/null else $DIR/ser -P $PID_FILE -E $STARTOPTIONS fi sleep 1 echo "started pid(`cat $PID_FILE`)" fi exit 0 ;; stop) printf "Stopping SER : " if [ -r $PID_FILE ] ; then kill `cat $PID_FILE` echo "stopped" else echo No PID file found! exit 1 fi exit 0 ;; restart) DIR=`dirname $0` printf "Stopping SER : " if [ -r $PID_FILE ] ; then kill `cat $PID_FILE` echo "stopped" else echo No PID file found! SER problably not running exit 1 fi sleep 2 printf "Starting SER : " if [ -r $PID_FILE ] ; then echo "PID file exists! ($PID_FILE) already running?" exit 1 else if [ $SYSLOG = 1 ] ; then $DIR/ser -P $PID_FILE $STARTOPTIONS 1>/dev/null 2>/dev/null else $DIR/ser -P $PID_FILE -E $STARTOPTIONS fi sleep 1 echo "started pid(`cat $PID_FILE`)" fi exit 0 ;; passwd) if [ $# -ne 3 ] ; then usage exit 1 fi shift credentials $1 $2 prompt_pw is_user $1 if [ $? -ne 0 ] ; then echo non-existent user exit 1 fi QUERY="update $TABLE \ set $HA1_COLUMN='$HA1', $HA1B_COLUMN='$HA1B', $PASSWORD_COLUMN='$2' \ , $SUB_MODIFIED_COLUMN=now() \ WHERE $SUBSCRIBER_COLUMN='$1' and $REALM_COLUMN='$SIP_DOMAIN';" sql_query "$QUERY" if [ $? -ne 0 ] ; then echo "password change failed" else echo "password change succeeded" fi ;; add) if [ $# -ne 4 ] ; then usage exit 1 fi shift credentials $1 $2 prompt_pw is_user $1 if [ $? -eq 0 ] ; then echo user already exists exit 1 fi QUERY="insert into $TABLE \ ($SUBSCRIBER_COLUMN,$REALM_COLUMN,$HA1_COLUMN,\ $HA1B_COLUMN,$PASSWORD_COLUMN,$EMAIL_COLUMN, $SUB_CREATED_COLUMN, \ $PHP_LIB_COLUMN,datetime_modified ) \ values ('$1','$SIP_DOMAIN','$HA1','$HA1B','$2', '$3', now(), '$HA1', now() );"; sql_query "$QUERY" if [ $? -ne 0 ] ; then echo "introducing a new user to the database failed" else echo "new user added" fi ;; monitor|console|moni|con) name=ser_receiver_$$ path=/tmp/$name if [ ! -w $SER_FIFO ]; then echo "Error opening ser's FIFO $SER_FIFO" echo "Make sure you have line fifo=$SER_FIFO in your config" exit 1 fi mkfifo $path if [ $? -ne 0 ] ; then echo "error opening read fifo $path" exit 1 fi trap "rm $path; clear; echo sc monitor ^C-ed; exit 1" 2 attempt=0 clear while [ 1 -eq 1 ]; do attempt=`expr $attempt + 1` #clear tput cup 0 0 print_stats $name $path $attempt sleep $WATCH_PERIOD done rm $path exit 0 ;; mail) if [ $# -ne 2 ] ; then usage exit 1 fi shift QUERY="select $TABLE.$EMAIL_COLUMN from $TABLE where \ $TABLE.$SUBSCRIBER_COLUMN='$1'" EA=`sql_ro_raw_query "$QUERY" "-B" | grep -v ERROR | $LAST_LINE` if [ $? -ne 0 ] ; then echo "MySql query failed" exit 1 fi echo "Write email to $1: $EA now ..." mail -s "Message from $SIP_DOMAIN SIP admin" $EA if [ $? -eq 0 ] ; then echo message sent else echo sending message failed fi ;; alias|ul) usrloc "$@" ;; online) fifo_cmd ul_dump |grep aor| awk '{print $3}' | sort | sort -mu exit $? ;; showdb|userdb) if [ $# -eq 2 ] ; then is_user $2 if [ $? -ne 0 ] ; then echo non-existent user exit 1; fi elif [ $# -ne 1 ] ; then usage exit 1 fi shift QUERY1="select $TABLE.$EMAIL_COLUMN from $TABLE where \ $TABLE.$SUBSCRIBER_COLUMN='$1'" QUERY2="select $USRLOC.* from $USRLOC where \ $USRLOC.$USER_COLUMN='$1' order by expires desc" QUERY3="select $USRLOC.$USER_COLUMN, $TABLE.$EMAIL_COLUMN, $USRLOC.$CALLID_COLUMN \ from $TABLE, $USRLOC where \ $TABLE.$SUBSCRIBER_COLUMN=$USRLOC.$USER_COLUMN order by $USRLOC.$USER_COLUMN" if [ $# -eq 1 ] ; then sql_ro_query "$QUERY1" sql_ro_query "$QUERY2" else sql_ro_query "$QUERY3" fi echo "Note: Due to usage of cache, server's list " \ "may differ from DB list." ;; rm) if [ $# -ne 2 ] ; then usage exit 1 fi shift prompt_pw is_user $1 if [ $? -ne 0 ] ; then echo non-existent user exit 1 fi QUERY="delete from $TABLE where $TABLE.$SUBSCRIBER_COLUMN='$1'" sql_query "$QUERY" $0 acl revoke $1 > /dev/null 2>&1 $0 dul $1 > /dev/null 2>&1 ;; ps) fifo_cmd ps ;; acl) shift acl "$@" ;; fifo) shift fifo_cmd "$@" ;; version) echo "$0 $VERSION" ;; *) usage exit 1 ;; esac