Ticket #2814 (new Patches)

Opened 2 years ago

Last modified 2 years ago

Call Pickup **+EXT Security

Reported by: joshpatten Assigned to: p_lindheimer
Priority: minor Milestone: Cut Line
Component: Core Version: 2.4-branch
Keywords: Cc:
Confirmation: Unreviewed SVN Revision (if applicable):
Backend Engine: All Backend Engine Version:

Description

I spent about 8 hours a few days ago hacking through FreePBX code to implement what was a show stopper for me. It seems the way FreePBX handles call pickup with **+EXT is to let anyone pick up any ringing extension. This is OK for very small organizations, but not for larger organizations with multiple departments.

What I did was to utilize the callgroup and pickupgroup parameters to determine whether the extension attempting to pickup someone else's call is eligible to do so.

I doubt this is complete, but it worked for me and will give a starting point for everyone to build on.

Here is what I modified: /var/www/html/admin/modules/core/functions.inc.php starting at line 675 of the original version 2.4.0.1 file:

This is the original code:

// Call pickup using app_pickup - Note that '**xtn' is hard-coded into the GXPs and SNOMs as a number to dial
// when a user pushes a flashing BLF. 
if ($fc_pickup != '') {
	$ext->addInclude('from-internal-additional', 'app-pickup');
	$fclen = strlen($fc_pickup);
	$ext->add('app-pickup', "_$fc_pickup.", '', new ext_NoOp('Attempt to Pickup ${EXTEN:'.$fclen.'} by ${CALLERID(num)}'));
	if (strstr($version, 'BRI')) 
		$ext->add('app-pickup', "_$fc_pickup.", '', new ext_dpickup('${EXTEN:'.$fclen.'}'));
	else
		$ext->add('app-pickup', "_$fc_pickup.", '', new ext_pickup('${EXTEN:'.$fclen.'}'));
}

This is the modified code:

// Call pickup using app_pickup - Note that '**xtn' is hard-coded into the GXPs and SNOMs as a number to dial
// when a user pushes a flashing BLF. 
if ($fc_pickup != '') {
	$ext->addInclude('from-internal-additional', 'app-pickup');
	$fclen = strlen($fc_pickup);
	$ext->add('app-pickup', "_$fc_pickup.", '', new ext_NoOp('Attempt to Pickup ${EXTEN:'.$fclen.'} by ${CALLERID(num)}'));
	//new code to do permission checking
	$ext->add('app-pickup', "_$fc_pickup.", '', new ext_setvar('CALLG','${DB(AMPUSER/${EXTEN:'.$fclen.'}/callgroup)}'));
	$ext->add('app-pickup', "_$fc_pickup.", '', new ext_setvar('PICKUPG','${DB(AMPUSER/${CALLERID(number)}/pickupgroup)}'));
	$ext->add('app-pickup', "_$fc_pickup.", '', new ext_system('${ASTAGIDIR}/parse.py ${CALLG} ${PICKUPG}'));
	$ext->add('app-pickup', "_$fc_pickup.", '', new ext_gotoif('$[${SYSTEMSTATUS} = APPERROR]','permden','permok'));
	$ext->add('app-pickup', "_$fc_pickup.", 'permden', new ext_playback('sorry-cant-let-you-do-that2'));
        $ext->add('app-pickup', "_$fc_pickup.", '', new ext_hangup(''));
//end new code
	if (strstr($version, 'BRI')) {
		//added from-did-direct and from-internal
		$ext->add('app-pickup', "_$fc_pickup.", 'permok', new ext_dpickup('${EXTEN:'.$fclen.'}'));
		$ext->add('app-pickup', "_$fc_pickup.", '', new ext_dpickup('${EXTEN:'.$fclen.'}@from-did-direct'));
		$ext->add('app-pickup', "_$fc_pickup.", '', new ext_dpickup('${EXTEN:'.$fclen.'}@from-internal'));
	}
	else {
		//added from-did-direct and from-internal
		$ext->add('app-pickup', "_$fc_pickup.", 'permok', new ext_pickup('${EXTEN:'.$fclen.'}'));
		$ext->add('app-pickup', "_$fc_pickup.", '', new ext_pickup('${EXTEN:'.$fclen.'}@from-did-direct'));
		$ext->add('app-pickup', "_$fc_pickup.", '', new ext_pickup('${EXTEN:'.$fclen.'}@from-internal'));
    }
                
}

also, at line 2439 of the original version 2.4.0.1 version of the file:

Original:

//write to astdb
if ($astman) {
	$cid_masquerade = (isset($cid_masquerade) && trim($cid_masquerade) != "")?trim($cid_masquerade):$extension;
	$astman->database_put("AMPUSER",$extension."/password",isset($password)?$password:'');
	$astman->database_put("AMPUSER",$extension."/ringtimer",isset($ringtimer)?$ringtimer:'');
	$astman->database_put("AMPUSER",$extension."/noanswer",isset($noanswer)?$noanswer:'');
	$astman->database_put("AMPUSER",$extension."/recording",isset($recording)?$recording:'');
	$astman->database_put("AMPUSER",$extension."/outboundcid",isset($outboundcid)?"\"".$outboundcid."\"":'');
	$astman->database_put("AMPUSER",$extension."/cidname",isset($name)?"\"".$name."\"":'');
	$astman->database_put("AMPUSER",$extension."/cidnum",$cid_masquerade);
	$astman->database_put("AMPUSER",$extension."/voicemail","\"".isset($voicemail)?$voicemail:''."\"");

Modified:

//write to astdb
if ($astman) {
	$cid_masquerade = (isset($cid_masquerade) && trim($cid_masquerade) != "")?trim($cid_masquerade):$extension;
	$astman->database_put("AMPUSER",$extension."/password",isset($password)?$password:'');
	$astman->database_put("AMPUSER",$extension."/ringtimer",isset($ringtimer)?$ringtimer:'');
	$astman->database_put("AMPUSER",$extension."/noanswer",isset($noanswer)?$noanswer:'');
	$astman->database_put("AMPUSER",$extension."/recording",isset($recording)?$recording:'');
	$astman->database_put("AMPUSER",$extension."/outboundcid",isset($outboundcid)?"\"".$outboundcid."\"":'');
	$astman->database_put("AMPUSER",$extension."/cidname",isset($name)?"\"".$name."\"":'');
	$astman->database_put("AMPUSER",$extension."/cidnum",$cid_masquerade);
	$astman->database_put("AMPUSER",$extension."/voicemail","\"".isset($voicemail)?$voicemail:''."\"");
	//added code to insert callgroup and pickupgroup info to the built in DB
	if (isset($devinfo_callgroup)) {
        $astman->database_put("AMPUSER",$extension."/callgroup",$devinfo_callgroup);
    }
    else {
        $astman->database_put("AMPUSER",$extension."/callgroup",'');
    }
    if (isset($devinfo_pickupgroup)) {
        $astman->database_put("AMPUSER",$extension."/pickupgroup",$devinfo_pickupgroup);
    }
    else {
        $astman->database_put("AMPUSER",$extension."/pickupgroup",'');
    }
    //end added code

I also had to write a helper script parse.py and place it in /var/lib/asterisk/agi-bin to sort out and match the callgroup and pickupgroup parameters. Since I don't know PHP too well I wrote it in python. I'm sure someone could probably easily convert this, as it's a pretty simple script.

parse.py:

#!/usr/bin/python

import string
import sys

# Get the values from asterisk
callgroup = sys.argv[1]
pickupgroup = sys.argv[2]

group_array = []

# split the string by commas
pgsplit = pickupgroup.split(',')

#hacky
j=0
i=0
while j < len(pgsplit):
  #If the value has a dash in it, the first statement will reject it sending it to the except: statement.
  try:
    group_array.append(int(pgsplit[j]))
  except:
    split_range = pgsplit[j].split('-')
    split_range[1] = int(split_range[1]) + 1
    range_count = range(int(split_range[0]), split_range[1])
    for num in range_count:
      group_array.append(num)
  j = j + 1


while i < len(group_array):
  if int(callgroup) == group_array[i]:
    sys.exit(0)
  i = i + 1

sys.exit(1)

All this results in 2 more attributes being written per extension to the internal asterisk database and the [app-pickup] dialplan will look like this:

[app-pickup]
include => app-pickup-custom
exten => _**.,1,Noop(Attempt to Pickup ${EXTEN:2} by ${CALLERID(num)})
exten => _**.,n,Set(CALLG=${DB(AMPUSER/${EXTEN:2}/callgroup)})
exten => _**.,n,Set(PICKUPG=${DB(AMPUSER/${CALLERID(number)}/pickupgroup)})
exten => _**.,n,System(${ASTAGIDIR}/parse.py ${CALLG} ${PICKUPG})
exten => _**.,n,GotoIf($[${SYSTEMSTATUS} = APPERROR]?permden:permok)
exten => _**.,n(permden),Playback(sorry-cant-let-you-do-that2)
exten => _**.,n,Hangup
exten => _**.,n(permok),Pickup(${EXTEN:2})
exten => _**.,n,Pickup(${EXTEN:2}@from-did-direct)
exten => _**.,n,Pickup(${EXTEN:2}@from-internal)

; end of [app-pickup]

I realize this is a bit hacky, and some pieces are probably missing, but it worked for me, for now. Perhaps the community can improve upon it and implement it soon.

Change History

01/15/09 19:28:12 changed by joshpatten

Oh well, guess no one cares about this.