From 0dc2987b84e12640bb793b188aae2b42d3e0724b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 28 Apr 2016 16:32:50 -0400 Subject: [PATCH 1/4] add some error checking, but fix the call to bind which really should have a +1 in it. --- src/zm_stream.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/zm_stream.cpp b/src/zm_stream.cpp index 77c94e68c..eb15fe02c 100644 --- a/src/zm_stream.cpp +++ b/src/zm_stream.cpp @@ -291,7 +291,11 @@ void StreamBase::openComms() if ( connkey > 0 ) { - snprintf( sock_path_lock, sizeof(sock_path_lock), "%s/zms-%06d.lock", config.path_socks, connkey); + unsigned int length = snprintf( sock_path_lock, sizeof(sock_path_lock), "%s/zms-%06d.lock", config.path_socks, connkey); + if ( length >= sizeof(sock_path_lock) ) { + Warning("Socket lock path was truncated."); + length = sizeof(sock_path_lock)-1; + } lock_fd = open(sock_path_lock, O_CREAT|O_WRONLY, S_IRUSR | S_IWUSR); if ( lock_fd <= 0 ) @@ -318,12 +322,19 @@ void StreamBase::openComms() Fatal( "Can't create socket: %s", strerror(errno) ); } - snprintf( loc_sock_path, sizeof(loc_sock_path), "%s/zms-%06ds.sock", config.path_socks, connkey ); + length = snprintf( loc_sock_path, sizeof(loc_sock_path), "%s/zms-%06ds.sock", config.path_socks, connkey ); + if ( length >= sizeof(loc_sock_path) ) { + Warning("Socket path was truncated."); + length = sizeof(loc_sock_path)-1; + } unlink( loc_sock_path ); + if ( sizeof(loc_addr.sun_path) < length ) { + Error("Not enough space %d in loc_addr.sun_path for socket file %s", sizeof(loc_addr.sun_path), loc_sock_path ); + } strncpy( loc_addr.sun_path, loc_sock_path, sizeof(loc_addr.sun_path) ); loc_addr.sun_family = AF_UNIX; - if ( bind( sd, (struct sockaddr *)&loc_addr, strlen(loc_addr.sun_path)+sizeof(loc_addr.sun_family)) < 0 ) + if ( bind( sd, (struct sockaddr *)&loc_addr, strlen(loc_addr.sun_path)+sizeof(loc_addr.sun_family))+1 < 0 ) { Fatal( "Can't bind: %s", strerror(errno) ); } From 75f9fde9202a1f644e0ab3de9474a603a16d7a59 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 2 May 2016 10:37:19 -0400 Subject: [PATCH 2/4] rough in Server object support --- web/api/app/Controller/ServersController.php | 155 +++++++++++++++++++ web/api/app/Model/Server.php | 74 +++++++++ web/api/app/View/Servers/json/edit.ctp | 2 + web/api/app/View/Servers/json/index.ctp | 1 + web/api/app/View/Servers/json/view.ctp | 1 + web/api/app/View/Servers/xml/edit.ctp | 2 + web/api/app/View/Servers/xml/index.ctp | 2 + web/api/app/View/Servers/xml/view.ctp | 2 + 8 files changed, 239 insertions(+) create mode 100644 web/api/app/Controller/ServersController.php create mode 100644 web/api/app/Model/Server.php create mode 100644 web/api/app/View/Servers/json/edit.ctp create mode 100644 web/api/app/View/Servers/json/index.ctp create mode 100644 web/api/app/View/Servers/json/view.ctp create mode 100644 web/api/app/View/Servers/xml/edit.ctp create mode 100644 web/api/app/View/Servers/xml/index.ctp create mode 100644 web/api/app/View/Servers/xml/view.ctp diff --git a/web/api/app/Controller/ServersController.php b/web/api/app/Controller/ServersController.php new file mode 100644 index 000000000..b9afe0033 --- /dev/null +++ b/web/api/app/Controller/ServersController.php @@ -0,0 +1,155 @@ +Session->Read('systemPermission'); + if ($canView =='None') { + throw new UnauthorizedException(__('Insufficient Privileges')); + return; + } + +} + + +/** + * index method + * + * @return void + */ + public function index() { + $this->Server->recursive = 0; + + $options=''; + $servers = $this->Server->find('all',$options); + $this->set(array( + 'servers' => $servers, + '_serialize' => array('servers') + )); + } + +/** + * view method + * + * @throws NotFoundException + * @param string $id + * @return void + */ + public function view($id = null) { + $this->Server->recursive = 0; + if (!$this->Server->exists($id)) { + throw new NotFoundException(__('Invalid server')); + } + $restricted = ''; + + $options = array('conditions' => array( + array('Server.' . $this->Server->primaryKey => $id), + $restricted + ) + ); + $server = $this->Server->find('first', $options); + $this->set(array( + 'server' => $server, + '_serialize' => array('server') + )); + } + +/** + * add method + * + * @return void + */ + public function add() { + if ($this->request->is('post')) { + + if ($this->Session->Read('systemPermission') != 'Edit') + { + throw new UnauthorizedException(__('Insufficient privileges')); + return; + } + + $this->Server->create(); + if ($this->Server->save($this->request->data)) { + # Might be nice to send it a start request + #$this->daemonControl($this->Server->id, 'start', $this->request->data); + return $this->flash(__('The server has been saved.'), array('action' => 'index')); + } + } + } + +/** + * edit method + * + * @throws NotFoundException + * @param string $id + * @return void + */ + public function edit($id = null) { + $this->Server->id = $id; + + if (!$this->Server->exists($id)) { + throw new NotFoundException(__('Invalid server')); + } + if ($this->Session->Read('systemPermission') != 'Edit') + { + throw new UnauthorizedException(__('Insufficient privileges')); + return; + } + if ($this->Server->save($this->request->data)) { + $message = 'Saved'; + } else { + $message = 'Error'; + } + + $this->set(array( + 'message' => $message, + '_serialize' => array('message') + )); + // - restart this server after change + #$this->daemonControl($this->Server->id, 'restart', $this->request->data); + } + +/** + * delete method + * + * @throws NotFoundException + * @param string $id + * @return void + */ + public function delete($id = null) { + $this->Server->id = $id; + if (!$this->Server->exists()) { + throw new NotFoundException(__('Invalid server')); + } + if ($this->Session->Read('systemPermission') != 'Edit') + { + throw new UnauthorizedException(__('Insufficient privileges')); + return; + } + $this->request->allowMethod('post', 'delete'); + + #$this->daemonControl($this->Server->id, 'stop'); + + if ($this->Server->delete()) { + return $this->flash(__('The server has been deleted.'), array('action' => 'index')); + } else { + return $this->flash(__('The server could not be deleted. Please, try again.'), array('action' => 'index')); + } + } +} diff --git a/web/api/app/Model/Server.php b/web/api/app/Model/Server.php new file mode 100644 index 000000000..b58450db5 --- /dev/null +++ b/web/api/app/Model/Server.php @@ -0,0 +1,74 @@ + array( + 'numeric' => array( + 'rule' => array('numeric'), + //'message' => 'Your custom message here', + //'allowEmpty' => false, + //'required' => false, + //'last' => false, // Stop validation after this rule + //'on' => 'create', // Limit validation to 'create' or 'update' operations + ), + ), + ); + + //The Associations below have been created with all possible keys, those that are not needed can be removed + +/** + * hasMany associations + * + * @var array + */ + public $hasMany = array( + 'Monitor' => array( + 'className' => 'Monitor', + 'foreignKey' => 'ServerId', + 'dependent' => false, + 'conditions' => '', + 'fields' => '', + 'order' => '', + 'limit' => '', + 'offset' => '', + 'exclusive' => '', + 'finderQuery' => '', + 'counterQuery' => '' + ) + ); +} diff --git a/web/api/app/View/Servers/json/edit.ctp b/web/api/app/View/Servers/json/edit.ctp new file mode 100644 index 000000000..0be859571 --- /dev/null +++ b/web/api/app/View/Servers/json/edit.ctp @@ -0,0 +1,2 @@ +echo json_encode($message); +echo json_encode($server); diff --git a/web/api/app/View/Servers/json/index.ctp b/web/api/app/View/Servers/json/index.ctp new file mode 100644 index 000000000..6e5cbd26d --- /dev/null +++ b/web/api/app/View/Servers/json/index.ctp @@ -0,0 +1 @@ +echo json_encode($servers); diff --git a/web/api/app/View/Servers/json/view.ctp b/web/api/app/View/Servers/json/view.ctp new file mode 100644 index 000000000..c3d0226ab --- /dev/null +++ b/web/api/app/View/Servers/json/view.ctp @@ -0,0 +1 @@ +echo json_encode($server); diff --git a/web/api/app/View/Servers/xml/edit.ctp b/web/api/app/View/Servers/xml/edit.ctp new file mode 100644 index 000000000..09fb8979a --- /dev/null +++ b/web/api/app/View/Servers/xml/edit.ctp @@ -0,0 +1,2 @@ +$xml = Xml::fromArray(array('response' => $message)); +echo $xml->asXML(); diff --git a/web/api/app/View/Servers/xml/index.ctp b/web/api/app/View/Servers/xml/index.ctp new file mode 100644 index 000000000..37afc918b --- /dev/null +++ b/web/api/app/View/Servers/xml/index.ctp @@ -0,0 +1,2 @@ +$xml = Xml::fromArray(array('response' => $monitors)); +echo $xml->asXML(); diff --git a/web/api/app/View/Servers/xml/view.ctp b/web/api/app/View/Servers/xml/view.ctp new file mode 100644 index 000000000..b33c6e79a --- /dev/null +++ b/web/api/app/View/Servers/xml/view.ctp @@ -0,0 +1,2 @@ +$xml = Xml::fromArray(array('response' => $monitor)); +echo $xml->asXML(); From 01aa2c931940794a75348e5d3213dee015ec737d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 2 May 2016 19:48:24 -0400 Subject: [PATCH 3/4] change permissions to stream permissions for view --- web/api/app/Controller/ServersController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/api/app/Controller/ServersController.php b/web/api/app/Controller/ServersController.php index b9afe0033..88a5bec90 100644 --- a/web/api/app/Controller/ServersController.php +++ b/web/api/app/Controller/ServersController.php @@ -19,7 +19,7 @@ class ServersController extends AppController { public function beforeFilter() { parent::beforeFilter(); - $canView = $this->Session->Read('systemPermission'); + $canView = $this->Session->Read('streamPermission'); if ($canView =='None') { throw new UnauthorizedException(__('Insufficient Privileges')); return; From c0509691412fa8312968ed31fb773d050a7922d1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 5 May 2016 15:33:28 -0400 Subject: [PATCH 4/4] Merge object model classes from storageareas --- web/includes/Event.php | 152 +++++++++++++++++++++++++++++++++++++++ web/includes/Frame.php | 103 ++++++++++++++++++++++++++ web/includes/Server.php | 79 +++++++++++++------- web/includes/Storage.php | 51 +++++++++++++ 4 files changed, 359 insertions(+), 26 deletions(-) create mode 100644 web/includes/Event.php create mode 100644 web/includes/Frame.php create mode 100644 web/includes/Storage.php diff --git a/web/includes/Event.php b/web/includes/Event.php new file mode 100644 index 000000000..5ad1c4031 --- /dev/null +++ b/web/includes/Event.php @@ -0,0 +1,152 @@ + $v) { + $this->{$k} = $v; + } + } else { + Error("No row for Event " . $IdOrRow ); + } + } // end function __construct + public function Storage() { + return new Storage( $this->{'StorageId'} ); + } + public function __call( $fn, array $args){ + if(isset($this->{$fn})){ + return $this->{$fn}; +#array_unshift($args, $this); +#call_user_func_array( $this->{$fn}, $args); + } + } + + public function Time() { + if ( ! isset( $this->{'Time'} ) ) { + $this->{'Time'} = strtotime($this->{'StartTime'}); + } + return $this->{'Time'}; + } + + public function Path() { + $Storage = $this->Storage(); + return $Storage->Path().'/'.$this->Relative_Path(); + } + public function Relative_Path() { + $event_path = ""; + + if ( ZM_USE_DEEP_STORAGE ) + { + $event_path = + $this->{'MonitorId'} + .'/'.strftime( "%y/%m/%d/%H/%M/%S", + $this->Time() + ) + ; + } + else + { + $event_path = + $this->{'MonitorId'} + .'/'.$this->{'Id'} + ; + } + + return( $event_path ); + + } + + public function LinkPath() { + if ( ZM_USE_DEEP_STORAGE ) { + return $this->{'MonitorId'} .'/'.strftime( "%y/%m/%d/.", $this->Time()).$this->{'Id'}; + } + Error("Calling Link_Path when not using deep storage"); + return ''; + } + + public function delete() { + dbQuery( 'DELETE FROM Events WHERE Id = ?', array($this->{'Id'}) ); + if ( !ZM_OPT_FAST_DELETE ) { + dbQuery( 'DELETE FROM Stats WHERE EventId = ?', array($this->{'Id'}) ); + dbQuery( 'DELETE FROM Frames WHERE EventId = ?', array($this->{'Id'}) ); + if ( ZM_USE_DEEP_STORAGE ) { + +# Assumption: All events haev a start time + $start_date = date_parse( $this->{'StartTime'} ); + $start_date['year'] = $start_date['year'] % 100; + + $Storage = $this->Storage(); +# So this is because ZM creates a link under teh day pointing to the time that the event happened. + $eventlink_path = $Storage->Path().'/'.$this->Link_Path(); + + if ( $id_files = glob( $eventlink_path ) ) { +# I know we are using arrays here, but really there can only ever be 1 in the array + $eventPath = preg_replace( '/\.'.$event['Id'].'$/', readlink($id_files[0]), $id_files[0] ); + deletePath( $eventPath ); + deletePath( $id_files[0] ); + $pathParts = explode( '/', $eventPath ); + for ( $i = count($pathParts)-1; $i >= 2; $i-- ) { + $deletePath = join( '/', array_slice( $pathParts, 0, $i ) ); + if ( !glob( $deletePath."/*" ) ) { + deletePath( $deletePath ); + } + } + } else { + Warning( "Found no event files under $eventlink_path" ); + } # end if found files + } else { + $eventPath = $this->Path(); + deletePath( $eventPath ); + } # USE_DEEP_STORAGE OR NOT + } # ! ZM_OPT_FAST_DELETE + } # end Event->delete + +public function getStreamSrc( $args, $querySep='&' ) { + return ZM_BASE_URL.'/index.php?view=view_video&eid='.$this->{'Id'}; + + $streamSrc = ZM_BASE_URL.ZM_PATH_ZMS; + + $args[] = "source=event&event=".$this->{'Id'}; + + if ( ZM_OPT_USE_AUTH ) { + if ( ZM_AUTH_RELAY == "hashed" ) { + $args[] = "auth=".generateAuthHash( ZM_AUTH_HASH_IPS ); + } elseif ( ZM_AUTH_RELAY == "plain" ) { + $args[] = "user=".$_SESSION['username']; + $args[] = "pass=".$_SESSION['password']; + } elseif ( ZM_AUTH_RELAY == "none" ) { + $args[] = "user=".$_SESSION['username']; + } + } + if ( !in_array( "mode=single", $args ) && !empty($GLOBALS['connkey']) ) { + $args[] = "connkey=".$GLOBALS['connkey']; + } + if ( ZM_RAND_STREAM ) { + $args[] = "rand=".time(); + } + + if ( count($args) ) { + $streamSrc .= "?".join( $querySep, $args ); + } + + return( $streamSrc ); + } // end function getStreamSrc +} # end class +?> diff --git a/web/includes/Frame.php b/web/includes/Frame.php new file mode 100644 index 000000000..5973cd1bf --- /dev/null +++ b/web/includes/Frame.php @@ -0,0 +1,103 @@ + $v) { + $this->{$k} = $v; + } + } else { + Error("No row for Frame " . $IdOrRow ); + } + } // end function __construct + public function Storage() { + return $this->Event()->Storage(); + } + public function Event() { + return new Event( $this->{'EventId'} ); + } + public function __call( $fn, array $args){ + if(isset($this->{$fn})){ + return $this->{$fn}; +#array_unshift($args, $this); +#call_user_func_array( $this->{$fn}, $args); + } + } + + public function Path() { + $Storage = $this->Storage(); + return $Storage->Path().'/'.$this->Relative_Path(); + } + public function Relative_Path() { + $event_path = ""; + + if ( ZM_USE_DEEP_STORAGE ) + { + $event_path = + $this->{'MonitorId'} + .'/'.strftime( "%y/%m/%d/%H/%M/%S", + $this->Time() + ) + ; + } + else + { + $event_path = + $this->{'MonitorId'} + .'/'.$this->{'Id'} + ; + } + + return( $event_path ); + + } + + public function getImageSrc( ) { + return ZM_BASE_URL.'/index.php?view=image&fid='.$this->{'Id'}; + } // end function getImageSrc + + public static function find( $parameters = array(), $limit = NULL ) { + $sql = 'SELECT * FROM Frames'; + $values = array(); + if ( sizeof($parameters) ) { + $sql .= ' WHERE ' . implode( ' AND ', array_map( + function($v){ return $v.'=?'; }, + array_keys( $parameters ) + ) ); + $values = array_values( $parameters ); + } + if ( $limit ) { + $sql .= ' LIMIT ' . $limit; + } + $results = dbFetchAll( $sql, NULL, $values ); + if ( $results ) { + return array_map( function($id){ return new Frame($id); }, $results ); + } + } + + public static function find_one( $parameters = array() ) { + $results = Frame::find( $parameters, 1 ); + if ( ! sizeof( $results ) ) { + return; + } + return $results[0]; + } +} # end class +?> diff --git a/web/includes/Server.php b/web/includes/Server.php index e8402809c..dfce67eb8 100644 --- a/web/includes/Server.php +++ b/web/includes/Server.php @@ -1,28 +1,28 @@ $v) { - $this->{$k} = $v; - } - } else { - $this->{'Name'} = ''; - $this->{'Hostname'} = ''; - } +class Server { + public function __construct( $IdOrRow = NULL ) { + $row = NULL; + if ( $IdOrRow ) { + if ( is_integer( $IdOrRow ) or is_numeric( $IdOrRow ) ) { + $row = dbFetchOne( 'SELECT * FROM Servers WHERE Id=?', NULL, array( $IdOrRow ) ); + if ( ! $row ) { + Error("Unable to load Server record for Id=" . $IdOrRow ); + } + } elseif ( is_array( $IdOrRow ) ) { + $row = $IdOrRow; + } + } # end if isset($IdOrRow) + if ( $row ) { + foreach ($row as $k => $v) { + $this->{$k} = $v; + } + } else { + $this->{'Name'} = ''; + $this->{'Hostname'} = ''; } + } public static function find_all() { $servers = array(); $result = dbQuery( 'SELECT * FROM Servers ORDER BY Name'); @@ -47,11 +47,38 @@ class Server { return $this->{'Name'}; } public function __call( $fn, array $args= NULL){ - if(isset($this->{$fn})){ - return $this->{$fn}; - #array_unshift($args, $this); - #call_user_func_array( $this->{$fn}, $args); - } + if(isset($this->{$fn})){ + return $this->{$fn}; +#array_unshift($args, $this); +#call_user_func_array( $this->{$fn}, $args); } + } + public static function find( $parameters = array(), $limit = NULL ) { + $sql = 'SELECT * FROM Servers'; + $values = array(); + if ( sizeof($parameters) ) { + $sql .= ' WHERE ' . implode( ' AND ', array_map( + function($v){ return $v.'=?'; }, + array_keys( $parameters ) + ) ); + $values = array_values( $parameters ); + } + if ( $limit ) { + $sql .= ' LIMIT ' . $limit; + } + $results = dbFetchAll( $sql, NULL, $values ); + if ( $results ) { + return array_map( function($id){ return new Server($id); }, $results ); + } + } + + public static function find_one( $parameters = array() ) { + $results = Server::find( $parameters, 1 ); + if ( ! sizeof( $results ) ) { + return; + } + return $results[0]; + } + } ?> diff --git a/web/includes/Storage.php b/web/includes/Storage.php new file mode 100644 index 000000000..546cb9cbe --- /dev/null +++ b/web/includes/Storage.php @@ -0,0 +1,51 @@ + $v) { + $this->{$k} = $v; + } + } else { + $this->{'Name'} = ''; + $this->{'Path'} = ''; + } + } + + public function Path() { + if ( isset( $this->{'Path'} ) and ( $this->{'Path'} != '' ) ) { + return $this->{'Path'}; + } else if ( ! isset($this->{'Id'}) ) { + return ZM_DIR_EVENTS; + } + return $this->{'Name'}; + } + public function __call( $fn, array $args= NULL){ + if(isset($this->{$fn})){ + return $this->{$fn}; + #array_unshift($args, $this); + #call_user_func_array( $this->{$fn}, $args); + } + } + public static function find_all() { + $storage_areas = array(); + $result = dbQuery( 'SELECT * FROM Storage ORDER BY Name'); + $results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Storage' ); + foreach ( $results as $row => $obj ) { + $storage_areas[] = $obj; + } + return $storage_areas; + } +} +?>