*/ class ParTCP_Access { public $dataDir; public $options; public $lastError; public function __construct( $dataDir, $options = [] ){ $this->dataDir = $dataDir; $this->options = array_replace_recursive( [ 'user_prefix' => 'ptcp_', 'sbin_dir' => '/usr/sbin' ], $options ); } public function check_environment(){ $queueDir = "{$this->dataDir}/access/queue"; if ( ! file_exists( $queueDir ) && ! mkdir( $queueDir, 0755, TRUE ) ){ $this->lastError = _('Queue directory does not exist'); return FALSE; } $perms = decoct( fileperms( $queueDir ) ); if ( substr( $perms, -2, 1 ) > 5 || substr( $perms, -1, 1 ) > 5 ){ $this->lastError = _('Queue directory must only be writable by owner'); return FALSE; } return TRUE; } public function request_exists( $ptcpId ){ $file = "{$this->dataDir}/access/queue/{$ptcpId}"; return file_exists( $file ); } public function enqueue_request( $ptcpId ){ $file = "{$this->dataDir}/access/queue/{$ptcpId}"; if ( file_exists( $file ) ){ return [ 'error' => -1 ]; } $result['user'] = "{$this->options['user_prefix']}{$ptcpId}"; $result['password'] = ''; $charset = '23456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'; $charsetLength = strlen( $charset ); for ( $i = 0; $i < 8; $i++ ){ $result['password'] .= $charset[ rand( 0, $charsetLength - 1 ) ]; } if ( ! file_put_contents( "{$file}", $result['password'] ) ){ return [ 'error' => -2 ]; } chmod( "{$file}", 0600 ); $result['notice'] = $this->options['user_notice'] ?? ''; return $result; } public function user_exists( $ptcpId ){ exec( "id {$this->options['user_prefix']}{$ptcpId} 2> /dev/null", $output, $returnVar ); return $returnVar === 0; } public function process_queue(){ $owner = fileowner( "{$this->dataDir}/access/queue" ); $expDate = date( 'Y-m-d', strtotime('tomorrow') ); $bin = $this->options['sbin_dir']; $errors = []; $listing = glob( "{$this->dataDir}/access/queue/*" ); foreach ( $listing as $file ){ if ( fileowner( $file ) != $owner ){ $errors[] = "Owner mismatch for file {$file}\n"; continue; } $perms = decoct( fileperms( $file ) ); if ( substr( $perms, -2, 1 ) > 4 || substr( $perms, -1, 1 ) > 4 ){ $errors[] = "Invalid permissions for file {$file}\n"; continue; } $passwd = trim( file_get_contents( $file ) ); if ( ! $passwd ){ $errors[] = "Empty or unreadable file {$file}\n"; continue; } $userName = $this->options['user_prefix'] . basename( $file ); if ( $this->user_exists( $userName ) ){ $errors[] = "User {$userName} already exists\n"; continue; } $cmd = "{$bin}/useradd -d / -N -e {$expDate} -s /bin/bash {$userName}"; exec( $cmd, $output, $returnVar ); if ( $returnVar != 0 ){ $errors[] = "Could not create user account {$userName} (error {$returnVar})\n"; continue; } $cmd = "echo {$userName}:{$passwd} | {$bin}/chpasswd"; exec( $cmd, $output, $returnVar ); if ( $returnVar != 0 ){ $errors[] = "Could not set password for {$userName} (error {$returnVar})\n"; continue; } unlink( $file ); } return $errors; } public function delete_old_users(){ $prefix = $this->options['user_prefix']; $bin = $this->options['sbin_dir']; $errors = []; $epochDate = floor( time() / 86400 ); $shadow = file('/etc/shadow'); foreach ( $shadow as $line ){ if ( substr( $line, 0, strlen( $prefix ) ) != $prefix ){ continue; } $record = explode( ':', $line ); if ( $record[7] <= $epochDate ){ exec( "{$bin}/deluser -f {$record[0]}", $output, $returnVar ); if ( $returnVar !== 0 ){ $errors[] = "Error on deleting user {$recorde[0]} (exit code {$returnVar})"; } } } return $errors; } } // end of file models/access.class.php