changed 'user' to 'username'.
[sip-router] / scripts / sc
1 #!/bin/sh 
2 #
3 # $Id$
4 #
5 # sc: ser control; tool for maintaining ser's databases
6 #
7 # History:
8 # --------
9 # 2003-02-23 Thomas's start|stop commands checked in
10
11 # configuration for starting/stopping ser
12 PID_FILE=/var/run/ser.pid
13 SYSLOG=1 # 0=output to console, 1=output to syslog
14 STARTOPTIONS= # for example -dddd
15
16 # ser's FIFO server
17 if [ -z "$SER_FIFO" ]; then
18         SER_FIFO=/tmp/ser_fifo
19 fi
20 # period in which stats are reprinted
21 if [ -z "$WATCH_PERIOD" ] ; then
22         WATCH_PERIOD=2
23 fi
24
25 # SQL config
26 if [ -z "$SQL_DB" ] ; then
27         SQL_DB=ser
28 fi
29 if [ -z "$SQL_HOST" ] ; then
30         SQL_HOST=localhost
31 fi
32 if [ -z "$SQL_USER" ] ; then
33         SQL_USER=ser
34 fi
35
36 # the read-only user for whom password may be stored here
37 if [ -z "$RO_USER" ] ; then
38         RO_USER=serro
39 fi
40 if [ -z "$RO_PW" ] ; then
41         RO_PW=47serro11
42 fi
43
44 # binaries
45 GENHA1='gen_ha1'
46 MYSQL='mysql'
47 SER='sr'
48 LAST_LINE='tail -1'
49
50 # ACL name verification
51 VERIFY_ACL=1
52 ACL_GROUPS="local ld int voicemail free-pstn"
53
54 # expiration time for alias table
55 FOREVER='2020-05-28 21:32:15'
56 FOREVER_REL=1073741823
57
58 VERSION='$Revision$'
59 #### SQL names
60
61 # Usr Loc Table
62 USRLOC=location
63 USER_COLUMN=username
64 CALLID_COLUMN=callid
65
66 # subscriber table
67 TABLE=subscriber
68 REALM_COLUMN=domain
69 HA1_COLUMN=HA1
70 HA1B_COLUMN=HA1B
71 PASSWORD_COLUMN=password
72 SUBSCRIBER_COLUMN='username'
73 EMAIL_COLUMN=email_address
74 SUB_CREATED_COLUMN=datetime_created
75 SUB_MODIFIED_COLUMN=datetime_modified
76 PHP_LIB_COLUMN=phplib_id
77
78 # acl table
79 ACL_TABLE=grp
80 ACL_USER_COLUMN=user
81 ACL_GROUP_COLUMN=grp
82 ACL_MODIFIED_COLUMN=last_modified
83
84 # aliases table
85 A_TABLE=aliases
86 A_USER_COLUMN=user
87 A_CONTACT_COLUMN=contact
88 A_EXPIRES_COLUMN=expires
89 A_Q_COLUMN=q
90 A_CALLID_COLUMN=callid
91 A_CSEQ_COLUMN=cseq
92 A_LAST_MODIFIED_COLUMN=last_modified
93
94 FIFO_DBG=0
95 #===================================================================
96
97
98 usage() {
99 CMD=`basename $0`
100 if [ "0$VERIFY_ACL" -eq 1 ] ; then
101         EXTRA_TEXT="ACL privileges are: $ACL_GROUPS"
102 fi
103 cat <<EOF
104 $0 $VERSION
105 usage: 
106            * subscribers *
107  $CMD add <username> <password> <email> .. add a new subscriber (*)
108  $CMD passwd <username> <passwd> ......... change user's password (*)
109  $CMD rm <username> ...................... delete a user (*)
110  $CMD mail <username> .................... send an email to a user
111  $CMD alias show [<alias>] ............... show aliases
112  $CMD alias rm <alias> ................... remove an alias
113  $CMD alias add <alias> <uri> ............ add an aliases 
114
115            * access control lists *
116  $CMD acl show [<username>] .............. show user membership
117  $CMD acl grant <username> <group> ....... grant user membership (*)
118  $CMD acl revoke <username> [<group>] .... grant user membership(s) (*)
119
120            * usrloc *
121  $CMD ul show [<username>]................ show in-RAM online users
122  $CMD ul rm <username> ................... delete user's UsrLoc entries
123  $CMD ul add <username> <uri> ............ introduce a permanent UrLoc entry
124  $CMD showdb [<username>] ................ show online users flushed in DB
125
126            * server health *
127  $CMD monitor ............................ show internal status
128  $CMD ps ................................. show runnig processes 
129  $CMD fifo ............................... send raw commands to FIFO
130
131            * server control *
132  $CMD start .............................. start ser
133  $CMD stop ............................... stop ser
134  $CMD restart ............................ restart ser
135
136
137    Commands labeled with (*) will prompt for a MySQL password.
138    If the variable PW is set, the password will not be prompted.
139
140      $EXTRA_TEXT
141
142 EOF
143 }
144
145 # check the parameter if it is a valid SIP URI
146 # quite simplified now -- it captures just very basic
147 # errors
148 check_uri() {
149         echo "$1" | grep -E "^sip:([a-zA-Z0-9_]+@)?.*\..*" 
150 }
151
152
153 #params: none
154 # output: PW
155 prompt_pw() {
156         if [ -z "$PW" ] ; then
157                 savetty=`stty -g`
158                 printf "MySql password: "
159                 stty -echo
160         read PW
161                 stty $savetty
162         echo
163         fi
164 }
165
166 # process output from FIFO server; if everything is ok
167 # skip the first "ok" line and proceed to returned 
168 # parameters
169 filter_fl()
170 {
171 #       tail +2
172         
173         awk 'BEGIN {line=0;IGNORECASE=1;}
174                 {line++}
175                 line==1 && /^200 ok/ { next }
176                 { print }'
177 }
178
179
180 fifo_cmd()
181 {
182         if [ "0${FIFO_DBG}" -eq 1 ] ; then
183                 echo "entering fifo_cmd $*"
184         fi
185         if [ "$#" -lt 1 ]; then
186                 echo "ERROR: fifo_cmd must take at least command name as parameter"
187                 exit
188         fi
189         name=ser_receiver_$$
190         path=/tmp/$name
191         if [ ! -w $SER_FIFO ]; then
192                 echo "Error opening ser's FIFO $SER_FIFO"
193                 echo "Make sure you have line fifo=$SER_FIFO in your config"
194                 exit 1
195         fi
196         mkfifo $path
197         if [ $? -ne 0 ] ; then
198                 echo "error opening read fifo $path"
199                 exit 1
200         fi
201         chmod a+w $path
202
203         # construct the command now
204         CMD=":$1:$name\n";
205         shift
206         while [ -n "$1" ] ; do
207                 CMD="${CMD}${1}\n"
208                 shift
209         done
210         CMD="${CMD}\n"
211
212         trap "rm -f $path; exit 1" 2
213
214         # start reader now so that it is ready for replies
215         # immediately after a request was sent out
216         cat < $path | filter_fl &
217
218         # issue FIFO request (printf taken to deal with \n)
219         printf "$CMD" > $SER_FIFO
220
221         # wait for the reader to complete
222         wait
223         rm $path
224
225         if [ "0${FIFO_DBG}" -eq 1 ] ; then
226                 printf "FIFO command was:\n$CMD"
227         fi
228 }
229
230
231 # $1 = name $2=path $3=attempt
232 print_stats() {
233
234 echo "[cycle #: $3; if constant make sure server lives and fifo is on]"
235
236 cat < $2 | filter_fl &
237 cat > $SER_FIFO <<EOF
238 :version:$1
239
240 EOF
241 wait
242
243 cat < $2 | filter_fl &
244 cat > $SER_FIFO << EOF
245 :uptime:$1
246
247 EOF
248 wait
249 echo
250
251 echo Transaction Statistics
252 cat < $2 | filter_fl &
253 cat > $SER_FIFO <<EOF
254 :t_stats:$1
255
256 EOF
257 wait
258 echo
259
260 echo Stateless Server Statistics
261 cat < $2 | filter_fl &
262 cat > $SER_FIFO <<EOF
263 :sl_stats:$1
264
265 EOF
266 wait
267 echo
268
269 echo UsrLoc Stats
270 cat < $2 | filter_fl &
271 cat > $SER_FIFO <<EOF
272 :ul_stats:$1
273
274 EOF
275 wait
276 }
277
278
279 # input: sql query, optional mysql command-line params
280 sql_query() {
281         # if password not yet queried, query it now
282         if [ -z "$PW" ] ; then
283                 savetty=`stty -g`
284                 printf "MySql password: "
285                 stty -echo
286         read PW >&2
287                 stty $savetty
288         echo >&2
289         fi
290         $MYSQL $2 -h $SQL_HOST -u $SQL_USER "-p$PW" -e "$1 ;" $SQL_DB
291 }
292
293 # input: sql query, optional mysql command-line params
294 sql_ro_query() {
295         $MYSQL $2 -h $SQL_HOST -u $RO_USER "-p$RO_PW" \
296                 -e "$1 ;" $SQL_DB
297 }
298
299
300 usrloc() {
301         if [ "$#" -lt 2 ] ; then
302                 echo "usrloc: too few parameters"
303                 exit 1
304         fi
305         if [ "$1" = "alias" ] ; then
306                 TABLE="$A_TABLE"
307         elif [ "$1" = "ul" ] ; then
308                 TABLE="$USRLOC"
309         else
310                 echo "usrloc: unknown table name"
311                 exit 1
312         fi
313         shift
314
315         case $1 in 
316                 show)
317                         if [ $# -eq 2 ] ; then
318                                 fifo_cmd ul_show_contact $TABLE $2
319                         elif [ $# -eq 1 ] ; then
320                                 fifo_cmd ul_dump
321                         else
322                                 echo "wrong number of params for usrloc show"
323                                 usage
324                                 exit 1
325                         fi
326                         exit $?
327                         ;;
328                 add)
329                         if [ $# -ne 3 ] ; then
330                                 usage
331                                 exit 1
332                         fi
333                         shift
334                         check_uri "$2"
335                         if [ "$?" -ne "0" ] ; then
336                                 echo "$2 is not a valid URI"
337                                 exit 1
338                         fi
339
340                         fifo_cmd ul_add "$TABLE" "$1" "$2" "$FOREVER_REL" "1.00" "0"
341                         exit $?
342                         ;;
343                 rm)
344             if [ $# -ne 2 ] ; then
345                 usage
346                 exit 1
347             fi
348                         shift
349                         fifo_cmd ul_rm $TABLE $1
350
351             ;;
352
353                 *)
354                         usage
355                         exit 1
356                         ;;
357         esac
358 }
359
360 acl() {
361         case $1 in
362                 show)
363                         if [ $# -eq 2 ] ; then
364                                 is_user $2
365                                 if [ $? -ne 0 ] ; then
366                                         echo non-existent user
367                                         exit 1;
368                                 fi
369                                 CLAUSE=" WHERE $ACL_USER_COLUMN='$2' "
370                         elif [ $# -ne 1 ] ; then
371                                 usage
372                                 exit 1
373                         fi
374                         QUERY="select * FROM $ACL_TABLE $CLAUSE ; "
375                         sql_ro_query "$QUERY"
376
377                         ;;
378
379                 grant)
380                         if [ $# -lt 3 ] ; then
381                                 usage
382                                 exit 1
383                         fi
384                         prompt_pw
385                         is_user $2
386                         if [ $? -ne 0 ] ; then
387                                 echo non-existent user
388                                 exit 1
389                         fi
390                         SIP_USER="$2"
391                         shift 2
392                         while [ $# -gt 0 ] ; do
393
394                                 if [ $VERIFY_ACL -eq 1 ] ; then
395                                         found=0
396                                         for i in $ACL_GROUPS ; do
397                                                 if [ "$1" = "$i" ] ; then
398                                                         found=1
399                                                         break
400                                                 fi
401                                         done    
402                                         if [ $found -eq 0 ] ; then
403                                                 echo "Invalid privilege: $1 ignored"
404                                                 shift
405                                                 continue
406                                         fi
407                                 fi
408
409                         QUERY="insert into $ACL_TABLE \
410                         ($ACL_USER_COLUMN,$ACL_GROUP_COLUMN,$ACL_MODIFIED_COLUMN) \
411                         values ('$SIP_USER','$1', now());"
412                                 sql_query "$QUERY"
413                                 if [ $? -ne 0 ] ; then
414                                         echo "SQL Error"
415                                         exit 1
416                                 fi
417                                 shift
418                         done
419
420                         $0 acl show $SIP_USER
421
422                         ;;
423
424                 revoke)
425                         if [ $# -eq 3 ] ; then
426                                 CLAUSE=" and $ACL_GROUP_COLUMN='$3' "
427                         elif [ $# -ne 2 ] ; then
428                                 usage
429                                 exit 1
430                         fi      
431
432                         QUERY="delete from $ACL_TABLE where \
433                                 $ACL_TABLE.$ACL_USER_COLUMN='$2' $CLAUSE"
434                         sql_query "$QUERY"
435
436                         $0 acl show $2
437
438                         ;;
439
440                 *)
441                         usage
442                         exit 1
443                         ;;
444         esac
445 }
446
447 # params: user
448 # output: false if exists, true otherwise
449 is_user() {
450         QUERY="select count(*) from $TABLE \
451                 where $SUBSCRIBER_COLUMN='$1' and $REALM_COLUMN='$SIP_DOMAIN';"
452         CNT=`sql_ro_query "$QUERY" | grep -v ERROR | $LAST_LINE`
453         if [ "0$CNT" -eq 0 ] ; then
454                 false
455         else
456                 true
457         fi
458
459 }
460
461
462 # params: user, password
463 # output: HA1, HA1B
464 credentials()
465 {
466         HA1=`$GENHA1 $1 $SIP_DOMAIN $2`
467         if [ $? -ne 0 ] ; then
468                 echo "HA1 calculation failed"
469                 exit 1
470         fi
471         HA1B=`$GENHA1 "$1@$SIP_DOMAIN" $SIP_DOMAIN $2`
472         if [ $? -ne 0 ] ; then
473                 echo "HA1B calculation failed"
474                 exit 1
475         fi
476 }
477
478 #================================================================
479
480 if [ -z "$SIP_DOMAIN" ] ; then
481         echo
482         echo "You need to set environment variable SIP_DOMAIN (e.g. to 'foobar.com') first"
483         echo
484 #       This confuses new users cause its easy to miss the information above
485 #       usage
486         exit 1
487 fi
488
489 # if the script calls itself ...
490 export PW
491
492 case $1 in
493
494         start)
495                 DIR=`dirname $0`
496                 echo
497                 echo -n "Starting SER : "
498                 if [ -r $PID_FILE ] ; then
499                         echo "PID file exists! ($PID_FILE) already running?"
500                         exit 1
501                 else
502                         if [ $SYSLOG = 1 ] ; then
503                                 $DIR/ser -P $PID_FILE $STARTOPTIONS 1>/dev/null 2>/dev/null
504                         else
505                                 $DIR/ser -P $PID_FILE -E $STARTOPTIONS
506                         fi
507                         sleep 1
508                         echo "started pid(`cat $PID_FILE`)"
509                 fi
510                 exit 0
511         ;;
512
513         stop)
514                 echo -n "Stopping SER : "
515                 if [ -r $PID_FILE ] ; then
516                         kill `cat $PID_FILE`
517                         echo "stopped"
518                 else
519                         echo No PID file found!
520                         exit 1
521                 fi
522                 exit 0
523         ;;
524
525         restart)
526                 DIR=`dirname $0`
527                 echo -n "Stopping SER : "
528                 if [ -r $PID_FILE ] ; then
529                         kill `cat $PID_FILE`
530                         echo "stopped"
531                 else
532                         echo No PID file found! SER problably not running
533                         exit 1
534                 fi
535                 sleep 2
536                 echo -n "Starting SER : "
537                 if [ -r $PID_FILE ] ; then
538                         echo "PID file exists! ($PID_FILE) already running?"
539                         exit 1
540                 else
541                         if [ $SYSLOG = 1 ] ; then
542                                 $DIR/ser -P $PID_FILE $STARTOPTIONS 1>/dev/null 2>/dev/null
543                         else
544                                 $DIR/ser -P $PID_FILE -E $STARTOPTIONS
545                         fi
546                         sleep 1
547                         echo "started pid(`cat $PID_FILE`)"
548                 fi
549                 exit 0
550         ;;
551
552         passwd)
553                 if [ $# -ne 3 ] ; then
554                         usage
555                         exit 1
556                 fi
557                 shift
558                 credentials $1 $2
559                 prompt_pw
560
561                 is_user $1
562                 if [ $? -ne 0 ] ; then
563                         echo non-existent user
564                         exit 1
565                 fi
566                 QUERY="update $TABLE \
567                         set $HA1_COLUMN='$HA1', $HA1B_COLUMN='$HA1B', $PASSWORD_COLUMN='$2' \
568                         , $SUB_MODIFIED_COLUMN=now() \
569                         WHERE $SUBSCRIBER_COLUMN='$1' and $REALM_COLUMN='$SIP_DOMAIN';"
570                 sql_query "$QUERY"
571                 if [ $? -ne 0 ] ; then
572                         echo "password change failed"
573                 else
574                         echo "password change succeeded"
575                 fi
576
577                 ;;              
578                         
579                 
580
581         add)
582                 if [ $# -ne 4 ] ; then
583                         usage
584                         exit 1
585                 fi
586                 shift
587                 credentials $1 $2
588                 prompt_pw
589         is_user $1
590         if [ $? -eq 0 ] ; then
591             echo user already exists
592             exit 1
593         fi
594
595                 QUERY="insert into $TABLE \
596                                 ($SUBSCRIBER_COLUMN,$REALM_COLUMN,$HA1_COLUMN,\
597                                 $HA1B_COLUMN,$PASSWORD_COLUMN,$EMAIL_COLUMN, $SUB_CREATED_COLUMN,  \
598                                 $PHP_LIB_COLUMN ) \
599                                 values ('$1','$SIP_DOMAIN','$HA1','$HA1B','$2', '$3', now(), '$HA1' );";
600                 sql_query "$QUERY"
601                 if [ $? -ne 0 ] ; then
602                         echo "introducing a new user to the database failed"
603                 else
604                         echo "new user added"
605                 fi
606
607                 ;;
608
609         monitor|console|moni|con)
610                 name=ser_receiver_$$
611                 path=/tmp/$name
612                 if [ ! -w $SER_FIFO ]; then
613                         echo "Error opening ser's FIFO $SER_FIFO"
614                         echo "Make sure you have line fifo=$SER_FIFO in your config"
615                         exit 1
616                 fi
617                 mkfifo $path
618                 if [ $? -ne 0 ] ; then
619                         echo "error opening read fifo $path"
620                         exit 1
621                 fi
622                 trap "rm $path;  clear; echo sc monitor ^C-ed; exit 1" 2
623                 attempt=0
624                 clear
625                 while [ 1 -eq 1 ]; do
626                         attempt=`expr $attempt + 1`
627                         #clear
628                         tput cup 0 0
629                         print_stats $name $path $attempt
630                         sleep $WATCH_PERIOD
631                 done
632                 rm $path
633                 exit 0
634                 ;;
635
636         mail)
637                 if [ $# -ne 2 ] ; then
638                         usage
639                         exit 1
640                 fi
641                 shift
642                 QUERY="select $TABLE.$EMAIL_COLUMN from $TABLE where  \
643                         $TABLE.$SUBSCRIBER_COLUMN='$1'"
644                 EA=`sql_ro_query "$QUERY" "-B" | grep -v ERROR | $LAST_LINE`
645                 if [ $? -ne 0 ] ; then
646                         echo "MySql query failed"
647                         exit 1
648                 fi
649                 echo "Write email to $1: $EA now ..."
650                 mail -s "Message from $SIP_DOMAIN SIP admin" $EA
651                 if [ $? -eq 0 ] ; then
652                         echo message sent
653                 else
654                         echo sending message failed
655                 fi
656
657                 ;;
658
659         alias|ul)
660                 usrloc "$@"
661                 ;;
662
663         online)
664                 fifo_cmd ul_dump |grep aor| awk '{print $3}' | sort | sort -mu
665                 exit $?
666                 ;;
667
668
669         showdb|userdb)
670                 if [ $# -eq 2 ] ; then
671                         is_user $2
672                         if [ $? -ne 0 ] ; then
673                                 echo non-existent user
674                                 exit 1;
675                         fi
676                 elif [ $# -ne 1  ] ; then
677                         usage
678                         exit 1
679                 fi
680
681                 shift
682
683                 QUERY1="select $TABLE.$EMAIL_COLUMN from $TABLE where  \
684                         $TABLE.$SUBSCRIBER_COLUMN='$1'"
685                 QUERY2="select $USRLOC.* from $USRLOC where \
686                         $USRLOC.$USER_COLUMN='$1' order by expires desc"
687                 QUERY3="select $USRLOC.$USER_COLUMN, $TABLE.$EMAIL_COLUMN, $USRLOC.$CALLID_COLUMN \
688                         from $TABLE, $USRLOC where  \
689                         $TABLE.$SUBSCRIBER_COLUMN=$USRLOC.$USER_COLUMN  order by $USRLOC.$USER_COLUMN" 
690
691                 if [ $# -eq 1 ] ; then
692                         sql_ro_query "$QUERY1"
693                         sql_ro_query "$QUERY2"
694                 else
695                         sql_ro_query "$QUERY3"
696                 fi
697                 echo -n "Note: Due to usage of cache, server's list "
698                 echo "may differ from DB list."
699
700                 ;;
701
702         rm)
703         if [ $# -ne 2 ] ; then
704             usage
705             exit 1
706         fi
707                 shift 
708                 prompt_pw 
709
710         is_user $1
711         if [ $? -ne 0 ] ; then
712             echo non-existent user
713             exit 1
714         fi
715
716         QUERY="delete from $TABLE where $TABLE.$SUBSCRIBER_COLUMN='$1'"
717                 sql_query "$QUERY"
718
719                 $0 acl revoke $1 > /dev/null 2>&1
720                 $0 dul $1   > /dev/null 2>&1
721         ;;
722                         
723         ps)
724                 fifo_cmd ps
725                 ;;
726
727         acl)
728                 shift
729                 acl "$@"
730                 ;;
731
732         fifo)
733                 shift
734                 fifo_cmd "$@"
735                 ;;
736
737         version)
738                 echo  "$0 $VERSION"
739                 ;;
740                 
741         *)
742                 usage
743                 exit 1
744                 ;;
745
746 esac
747