Open Source Training Seminar FreePBX Paid Support

Ticket #2814 (new Patches)

Opened 4 months 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.

Donate



Support
Download
Develop
Forums
News
Documentation
Paid Support
About

Paid Ads