def remove_active_host(self, task, access_path): self.acl(task) try: del self.server_dispatcher.active_count_dict[access_path] except KeyError: log.warn('access_path "%s" not found in active_count_dict' % access_path) return True
def joined(self, channel): if channel != self.ircchannel: log.warn("Odd, I shouldn't be joining " + channel) return self.run_cronjobs() log.msg("Joined channel")
def validate_team_name(name): if len(name) > 9: log.warn( "Team name's length exceeds 9 character limit. More info: https://git.io/fN2cI" ) # TODO: Once issue #345 is sorted out, we can do a proper validation # for now we just warn # return False return True
def fetch_feed(self, url): feed_type = self.feeds[url].type err = None try: data = yield self.client.request(url) except HTTPClientError as err: log.warn('Failed to fetch feed ({}): {}'.format(url, err)) data = None finally: self.schedule_fetch(url, fast=bool(err)) # do faster re-fetch on errors if data is None: defer.returnValue(None) # cache hit, not modified, error data, headers = data if feed_type == 'feed': import feedparser parser = feedparser.parse(data, response_headers=headers) feed, posts = parser.feed, parser.entries elif feed_type == 'reddit-json': from lya import AttrDict # mandatory dep anyway data = json.loads(data)['data'] posts = list(AttrDict(post['data']) for post in data.pop('children')) feed = AttrDict(data) else: raise ValueError('Unrecognized feed type: {!r}'.format(self.feeds[url].type)) count = 0 for post in reversed(posts): if feed_type == 'reddit-json': # Some reddit-api-specific encoding hacks try: title = unescape(post['title']) except KeyError: pass else: post.title = title post_obj = FeedEntryInfo(feed, post, self.conf) post_id = list( force_bytes(post_obj.get_by_path(attr)) for attr in self.feeds[url].deduplication ) if not self.filter_db.add(url, post_id): continue first_err = None for template in self.feeds[url].template: try: event = template.format(**post_obj._asdict()) except (KeyError, IndexError, AttributeError) as err: if not first_err: first_err = ValueError( 'Failed to format template {!r} (data: {}): {}'\ .format(template, post_obj, err) ) continue event = RelayedEvent(event) event.data = post_obj # for any further tricky filtering reactor.callLater(0, self.interface.dispatch, event, source=self) break else: raise first_err # all templates failed count += 1 if self.feeds[url].process_max and count >= self.feeds[url].process_max: break
def extReceived(self, dataType, data): """ Called when we receive extended data (usually standard error) @param dataType: data type code @type dataType: integer """ message = "The command %s returned stderr data (%d) from the device: %s" % (self.command, dataType, data) log.warn("%s channel %s %s", self.targetIp, self.conn.localChannelID, message) self.stderr += data
def retry(self, request, server): # servers don't start up *quite* right away, so we give it a # moment to be ready to accept connections sleep = self.config.get("sleep") wait_up_to = self.config.get("wait_up_to") for i in range(int(wait_up_to / sleep)): try: yield self.get_page(request, server) return except Exception, e: log.warn(e) yield wait_for(sleep)
def handle_change(self, stuff, path, mask): mask_str = inotify.humanReadableMask(mask) log.noise('Event: {} ({})'.format(path, mask_str)) ## Filtering path_real = path.realpath() if not path_real.isfile(): log.debug( 'Ignoring event for' ' non-regular file: {} (realpath: {})'.format(path, path_real) ) return dir_key = path_real.parent().realpath() if dir_key not in self.paths_watch: log.warn( 'Ignoring event for file outside of watched' ' set of paths: {} (realpath: {})'.format(path, path_real) ) return for pat in self.paths_watch[dir_key]: if fnmatch(bytes(path.basename()), pat): break else: log.noise( 'Non-matched path in one of' ' the watched dirs: {} (realpath: {})'.format(path, path_real) ) return ## Get last position if self.paths_pos.get(path_real) is not None: pos, size, data = self.paths_pos[path_real] if self.file_end_check(path_real, pos, size=size, data=data): log.debug(( 'Event (mask: {}) for unchanged' ' path, ignoring: {}' ).format(mask_str, path)) return if path_real.getsize() < pos: log.debug( 'Detected truncation' ' of a path, rewinding: {}'.format(path) ) pos = None else: pos = None ## Actual processing line = self.paths_buff.setdefault(path_real, '') with path_real.open('rb') as src: if pos: src.seek(pos) pos = None while True: buff = src.readline() if not buff: # eof self.paths_pos[path_real] = self.file_end_mark(path_real, data=line) line += buff if line.endswith('\n'): log.noise('New line (source: {}): {!r}'.format(path, line)) reactor.callLater(0, self.handle_line, line) line = self.paths_buff[path_real] = '' else: line, self.paths_buff[path_real] = None, line break
def update_world(self): last_time = self.last_time current_time = reactor.seconds() if last_time is not None: dt = current_time - last_time if dt > 1.0: log.warn('high CPU usage detected - %s' % dt) self.last_time = current_time ServerProtocol.update_world(self) time_taken = reactor.seconds() - current_time if time_taken > 1.0: log.warn('World update iteration took %s, objects: %s' % (time_taken, self.world.objects))
def name_from_patch_link( self, link, _re_path=re.compile(r'\bpackages/[\w\-]+/(?P<name>[\w\-]+)/') ): names = set() try: page = yield getPage(force_bytes(link), timeout=120) except Exception as err: log.warn('Failed to download patch: {}'.format(err)) defer.returnValue(None) page = it.imap(op.methodcaller('strip'), page.splitlines()) for line in page: if re.search(r'^\s*(\S+\s+\|\s+\d+\s+[\-+]*\s*$|rename |diff --git |[\-+]{3} )', line): line = _re_path.search(line) if line: names.add(line.group('name')) defer.returnValue(names)
def get_available_hosts(self, task): self.acl(task) records = {} for host_id, data in self.server_dispatcher.available_host_dict.items( ): records[data['access_path']] = (host_id, data) for access_path, data in self.server_dispatcher.active_count_dict.items( ): try: records[access_path][1]['count'] = data['count'] except KeyError: log.warn('access_path ignored', access_path) return list(records.values())
def login_failed(request): request.setResponseCode(403) user.did_login_failure() if user.authentication_failure_count < self.max_failure: # diffrent message to hind the failure point (developing) log.warn('login failured from ' + client_ip) request.write(b'Login failure, try again') request.finish() else: log.warn('login failures over ' + str(self.max_failure) + ' times from ' + client_ip) request.write(b'Too many failure, good bye') request.finish()
def receiveError( self, reasonCode, description ): """ Called when a disconnect error message was received from the device. @param reasonCode: error code from SSH connection failure @type reasonCode: integer @param description: human-readable version of the error code @type description: string """ message= 'SSH error from remote device (code %d): %s\n' % \ ( reasonCode, str( description ) ) log.warn( message ) transport.SSHClientTransport.receiveError(self, reasonCode, description )
def remove_username(self, username): db = self.presentation_root_folder.db p_ids_to_remove = [] try: p_ids = db.user_presentation_dict[username] except KeyError: pass else: p_ids_to_remove.extend(p_ids) # remove from sbs_name_dict try: del db.sbs_name_dict[username] except KeyError: pass # remove from binding_dict try: binding = db.binding_dict[username] except KeyError: pass else: if isinstance(binding, str): # username is binding to another username try: all_bindings = db.binding_dict[binding] except KeyError: pass else: if username in all_bindings: all_bindings.remove(username) if len(all_bindings) == 0: # remove this item del db.binding_dict[binding] else: # update this item db.binding_dict[binding] = all_bindings else: #username is been binded by other usernames del db.binding_dict[binding] for binder in binding: try: binded = db.binding_dict[binder] except KeyError: log.warn('binding db inconsistent type #1') else: if binded == username: del db.binding_dict[binder] else: log.warn('binding db inconsistent type #2') return p_ids_to_remove
def process_ack(self, uid_conversation, ack=1): if uid_conversation in self.factory.waiting_acks: log.debug('Processing ack for conversation %s' % (uid_conversation, )) data = {'ack': ack, 'uid_conversation': uid_conversation} channel = self.factory.waiting_acks[uid_conversation]["channel"] channel.sendLine(self.serializer.dumps(data)) del self.factory.waiting_acks[uid_conversation] if uid_conversation in self.factory.conversation_callbacks: self.factory.conversation_callbacks[uid_conversation].cancel() del self.factory.conversation_callbacks[uid_conversation] else: log.warn('Tried to process an ack that is not present %s' % (uid_conversation, ))
def announce(room_id): room_id_wo_R = room_id[1:] try: count = len(MessageBus.ws_listeners[room_id]) except KeyError: log.warn('announce to unexisted room: %s' % room_id) else: self.broadcast_by_internal_node( room_id_wo_R, { 'topic': '_ANNOUNCE_', 'data': { 'type': 'JOIN', 'members_count': count } })
def _getKey(self): keyPath = os.path.expanduser(self.factory.keyPath) log.msg("Expanded SSH key path from KeyPath {0} to {1}".format(self.factory.keyPath, keyPath)) key = None if os.path.exists(keyPath): try: key = Key.fromFile(keyPath) except IOError, ex: message = "Unable to read the SSH key file because %s" % (str(ex)) log.warn(message) device = "localhost" # Fallback try: device = socket.getfqdn() except: pass
def check_scripts(scripts): ''' Checks if scripts were included multiple times. ''' seen = set() dups = [] for script in scripts: if script in seen: dups.append(script) else: seen.add(script) if dups: log.warn("Scripts included multiple times: {}".format(dups)) return False return True
def openFailed(self, reason): """ Called when the open fails. """ from twisted.conch.error import ConchError if isinstance(reason, ConchError): args = (reason.data, reason.value) else: args = (reason.code, reason.desc) message = 'CommandChannel Open of %s failed (error code %d): %s' % ( (self.command,) + args) log.warn("%s %s", self.targetIp, message) channel.SSHChannel.openFailed(self, reason) if self.conn is not None: self.conn.factory.clientFinished()
def data_received(self, peer: Peer, packet: Packet) -> None: ip = peer.address.host current_time = reactor.seconds() try: ServerProtocol.data_received(self, peer, packet) except (NoDataLeft, ValueError): import traceback traceback.print_exc() log.info( 'IP %s was hardbanned for invalid data or possibly DDoS.' % ip) self.hard_bans.add(ip) return dt = reactor.seconds() - current_time if dt > 1.0: log.warn('processing {!r} from {} took {}'.format( packet.data, ip, dt))
def handle_line(self, line, repo_lock=defer.DeferredLock()): try: line = line.decode('utf-8', 'ignore').strip() match = re.search(r'(^|\s+)!pq\s+(?P<link>\S+)(\s+::\S+|$)', line) if not match: log.noise('Non-patchbot line, ignoring: {}'.format(line.encode('utf-8', 'ignore'))) defer.returnValue(None) link = match.group('link').encode('ascii') if not re.search('https?://', link, re.IGNORECASE): log.warn('Incorrect non-http link, skipping: {}'.format(link)) defer.returnValue(None) except UnicodeError as err: log.warn('Failed to recode line ({!r}): {}'.format(line, err)) defer.returnValue(None) ## Grab the patch dst_base = '{}.patch'.format(sha1(link).hexdigest()) dst_path = self.dst_path.child(dst_base) if dst_path.exists(): log.debug( 'Patch already exists' ' (file: {}, link: {}), skipping'.format(dst_path, link) ) defer.returnValue(None) # Not via tmpfile to prevent multiple downloads of the same paste try: yield downloadPage(link, dst_path.open('wb'), timeout=120) except: if dst_path.exists(): dst_path.remove() raise ## Commit into repo and push yield repo_lock.acquire() try: for cmd, check in [ (['add', dst_base], True), (['commit', '-m', 'New patch: {}'.format(link)], False), (['push'], True) ]: out, err, code = yield getProcessOutputAndValue( '/usr/bin/git', cmd, path=self.dst_path.path ) if check and code: log.error('\n'.join([ 'Failed to commit/push new patch into repo', 'Command: {}'.format(cmd), 'Exit code: {}'.format(code), 'Stdout:\n {}'.format('\n '.join(out.splitlines())), 'Stderr:\n {}'.format('\n '.join(err.splitlines())) ])) break else: log.debug('Successfully pushed paste: {}'.format(link)) finally: repo_lock.release()
def remove_p_id(self, p_id): db = self.presentation_root_folder.db try: del db.presentation_atime_dict[p_id] except KeyError: pass try: p_state = db.presentation_states_dict[p_id] except KeyError: pass else: acl_token = p_state['acl_token'] for token in acl_token.values(): #if (token is None) or (token == ''): continue if not token: continue log.debug('removing token %s' % token) try: # 此數值 db.token_presentation_dict[token] 應該是p_id # 此處暫時不做一致性檢查 del db.token_presentation_dict[token] except KeyError: # 應該存在才合理 log.warn('token_presentation_dict db inconsistent type #1') try: db.delegate_host_dict[token] except KeyError: pass username = p_state['owner'] try: p_ids = db.user_presentation_dict[username] except KeyError: pass else: if p_id in p_ids: p_ids.remove(p_id) # 雖然 p_ids 可能是空的,但還是留著此紀錄,以保留 username之間的binding關係 db.user_presentation_dict[username] = p_ids else: log.warn('user_presentation_dict db inconsistent type #2') del db.presentation_states_dict[p_id]
def send(self, message, delay=False): '''Attempt to send a message with optional delay''' if not self.active: log.warn("Attempted to send a message to inactive %s: %s", self.TYPE, self.uid) return if message is None or message == "": log.warn("Attempted to send an empty messsage") return if type(message) == type(u""): message = message.encode('utf-8') time = 0.2 if delay: time = 2.5 log.msg("Sending <{0}>: {1}".format(self.uid, message)) reactor.callLater(time, self._send, unicode(message, 'utf-8'))
def get_external_ip(self, ip_getter: str) -> Iterator[Deferred]: log.info( 'Retrieving external IP from {!r} to generate server identifier.'. format(ip_getter)) try: ip = yield self.getPage(ip_getter) ip = IPv4Address(ip.strip()) except AddressValueError as e: log.warn('External IP getter service returned invalid data.\n' 'Please check the "ip_getter" setting in your config.') return except Exception as e: log.warn("Getting external IP failed: {reason}", reason=e) return self.ip = ip self.identifier = make_server_identifier(ip, self.port) log.info('Server public ip address: {}:{}'.format(ip, self.port)) log.info('Public aos identifier: {}'.format(self.identifier))
def _getKey(self): keyPath = os.path.expanduser(self.factory.keyPath) log.msg('Expanded SSH key path from zKeyPath %s to %s' % ( self.factory.keyPath, keyPath)) key = None if os.path.exists(keyPath): try: data = ''.join(open(keyPath).readlines()).strip() key = Key.fromString(data) #key = Key.fromString(data, # passphrase=self.factory.password) except IOError, ex: message = "Unable to read the SSH key file because %s" % ( str(ex)) log.warn(message) device = 'localhost' # Fallback try: device = socket.getfqdn() except: pass
def send(self, message, delay=False): '''Attempt to send a message with optional delay''' if not self.active: log.warn("Attempted to send a message to inactive %s: %s", self.TYPE, self.uid) return if message is None or message == "": log.warn("Attempted to send an empty messsage") return if type(message) == type(u""): message = message.encode('utf-8') time = 0.2 if type(delay) is int: time = delay elif delay is True: time = 1.5 + random.random() * 2 log.msg("Sending <{0}>: {1}".format(self.uid, message)) reactor.callLater(time, self._send, unicode(message, 'utf-8'))
def update_sid_db( self, _ref_line=re.compile( r'^\s*config\s+reference:' r'\s+(?P<ref_type>\w+)\s+(?P<ref_url>\S+)\s*$' ) ): log.debug('Updating sid-msg.map hash: {}'.format(self.conf.paths.sid_db)) # Process ref types config (ref_type:url mapping) ref_map = dict() if self.conf.paths.refs: with open(self.conf.paths.refs) as src: for line in src: match = _ref_line.search(line) if not match: continue ref_map[match.group('ref_type').lower()] = match.group('ref_url') # (Re)build sid:urls db try: os.unlink(self.conf.paths.sid_db) except OSError: pass with open(self.conf.paths.sid_src) as src,\ closing(anydbm.open(self.conf.paths.sid_db, 'c')) as dst: for line in src: line = line.strip() if not line or line[0] == '#': continue try: sid, msg, refs = op.itemgetter(0, 1, slice(2, None))\ (map(op.methodcaller('strip'), line.split(' || '))) except IndexError: log.warn('Unrecognized sid-msg.map line format, ignoring: {!r}'.format(line)) if not sid.isdigit(): log.warn('Detected non-numeric sid: {!r} (line: {!r})'.format(sid, line)) ref_urls = list() for ref in refs: if ref_map: try: ref_type, ref = it.imap(op.methodcaller('strip'), ref.split(',', 1)) ref = ''.join([ref_map[ref_type.lower()], ref]) except ValueError: log.warn('Unrecognized ref format, ignoring: {!r} (line: {!r})'.format(ref, line)) continue except KeyError: log.warn( 'Unrecognized ref type:' ' {!r} (ref: {!r}, line: {!r})'.format(ref_type, ref, line) ) ref = ','.join([ref_type, ref]) ref_urls.append(ref) if ref_urls: dst[sid] = ' '.join(sorted(set(dst.get(sid, '').split()).union(ref_urls)))
def no_ack_timeout(cls, factory, channel, uid_conversation, uid_to): if uid_conversation in factory.waiting_acks: log.warn('No ack for %s to %s' % (uid_conversation, uid_to)) data = {'ack': 0, 'error': 'time out, unable to contact'} channel.sendLine(factory.serializer.dumps(data)) clients = factory.waiting_acks[uid_conversation]["clients"] for client in clients: log.warn('UIDS for this client: %s' % client.uids) if len(client.uids) == 1: try: log.warn( 'Aborting connection because the only uid it had is not responding %s' % (uid_conversation, )) client.transport.abortConnection() except Exception, e: log.failure("{message!r}", message=e.message) client.uids.remove(uid_to) del factory.clients[uid_to]
clients = factory.waiting_acks[uid_conversation]["clients"] for client in clients: log.warn('UIDS for this client: %s' % client.uids) if len(client.uids) == 1: try: log.warn( 'Aborting connection because the only uid it had is not responding %s' % (uid_conversation, )) client.transport.abortConnection() except Exception, e: log.failure("{message!r}", message=e.message) client.uids.remove(uid_to) del factory.clients[uid_to] else: log.warn( 'Callback called but should have not been for conversation %s' % (uid_conversation, )) def process_ack(self, uid_conversation, ack=1): if uid_conversation in self.factory.waiting_acks: log.debug('Processing ack for conversation %s' % (uid_conversation, )) data = {'ack': ack, 'uid_conversation': uid_conversation} channel = self.factory.waiting_acks[uid_conversation]["channel"] channel.sendLine(self.serializer.dumps(data)) del self.factory.waiting_acks[uid_conversation] if uid_conversation in self.factory.conversation_callbacks: self.factory.conversation_callbacks[uid_conversation].cancel() del self.factory.conversation_callbacks[uid_conversation] else: log.warn('Tried to process an ack that is not present %s' %
def __init__(self, interface: bytes, config_dict: Dict[str, Any]) -> None: # logfile path relative to config dir if not abs path log_filename = logfile.get() if log_filename.strip(): # catches empty filename if not os.path.isabs(log_filename): log_filename = os.path.join(config.config_dir, log_filename) ensure_dir_exists(log_filename) if logging_rotate_daily.get(): logging_file = DailyLogFile(log_filename, '.') else: logging_file = open(log_filename, 'a') globalLogPublisher.addObserver(textFileLogObserver(logging_file)) globalLogPublisher.addObserver(textFileLogObserver(sys.stderr)) log.info('piqueserver started on %s' % time.strftime('%c')) self.config = config_dict if random_rotation: self.map_rotator_type = random_choice_cycle else: self.map_rotator_type = itertools.cycle # pylint: disable=redefined-variable-type self.default_time_limit = default_time_limit.get() self.default_cap_limit = cap_limit.get() self.advance_on_win = int(advance_on_win.get()) self.win_count = itertools.count(1) self.bans = NetworkDict() # attempt to load a saved bans list try: with open(os.path.join(config.config_dir, bans_file.get()), 'r') as f: self.bans.read_list(json.load(f)) log.debug("loaded {count} bans", count=len(self.bans)) except FileNotFoundError: log.debug("skip loading bans: file unavailable", count=len(self.bans)) except IOError as e: log.error('Could not read bans.txt: {}'.format(e)) except ValueError as e: log.error('Could not parse bans.txt: {}'.format(e)) self.hard_bans = set() # possible DDoS'ers are added here self.player_memory = deque(maxlen=100) if len(self.name) > MAX_SERVER_NAME_SIZE: log.warn('(server name too long; it will be truncated to "%s")' % (self.name[:MAX_SERVER_NAME_SIZE])) self.respawn_time = respawn_time_option.get() self.respawn_waves = respawn_waves.get() if game_mode.get() == 'ctf': self.game_mode = CTF_MODE elif game_mode.get() == 'tc': self.game_mode = TC_MODE elif self.game_mode is None: raise NotImplementedError('invalid game mode: %s' % game_mode) self.game_mode_name = game_mode.get().split('.')[-1] self.team1_name = team1_name.get() self.team2_name = team2_name.get() self.team1_color = tuple(team1_color.get()) self.team2_color = tuple(team2_color.get()) self.friendly_fire = friendly_fire.get() self.friendly_fire_on_grief = friendly_fire_on_grief.get() self.friendly_fire_time = grief_friendly_fire_time.get() self.spade_teamkills_on_grief = spade_teamkills_on_grief.get() self.fall_damage = fall_damage.get() self.teamswitch_interval = teamswitch_interval.get() self.teamswitch_allowed = teamswitch_allowed.get() self.max_players = max_players.get() self.melee_damage = melee_damage.get() self.max_connections_per_ip = max_connections_per_ip.get() self.passwords = passwords.get() self.server_prefix = server_prefix.get() self.time_announcements = time_announcements.get() self.balanced_teams = balanced_teams.get() self.login_retries = login_retries.get() # voting configuration self.default_ban_time = default_ban_duration.get() self.speedhack_detect = speedhack_detect.get() if user_blocks_only.get(): self.user_blocks = set() self.set_god_build = set_god_build.get() self.debug_log = debug_log_enabled.get() if self.debug_log: # TODO: make this configurable pyspades.debug.open_debug_log( os.path.join(config.config_dir, 'debug.log')) if ssh_enabled.get(): from piqueserver.ssh import RemoteConsole self.remote_console = RemoteConsole(self) irc = irc_options.get() if irc.get('enabled', False): from piqueserver.irc import IRCRelay self.irc_relay = IRCRelay(self, irc) if status_server_enabled.get(): from piqueserver.statusserver import StatusServerFactory self.status_server = StatusServerFactory(self) if ban_publish.get(): from piqueserver.banpublish import PublishServer self.ban_publish = PublishServer(self, ban_publish_port.get()) if bans_urls.get(): from piqueserver import bansubscribe self.ban_manager = bansubscribe.BanManager(self) self.start_time = reactor.seconds() self.end_calls = [] # TODO: why is this here? create_console(self) for user_type, func_names in rights.get().items(): for func_name in func_names: commands.add_rights(user_type, func_name) port = self.port = port_option.get() ServerProtocol.__init__(self, port, interface) self.host.intercept = self.receive_callback try: self.set_map_rotation(self.config['rotation']) except MapNotFound as e: log.critical('Invalid map in map rotation (%s), exiting.' % e.map) raise SystemExit self.update_format() self.tip_frequency = tip_frequency.get() if self.tips is not None and self.tip_frequency > 0: reactor.callLater(self.tip_frequency * 60, self.send_tip) self.master = register_master_option.get() self.set_master() self.http_agent = web_client.Agent(reactor) ip_getter = ip_getter_option.get() if ip_getter: self.get_external_ip(ip_getter)
def connection_lost(self): log.warn("Connection lost") self.subscriber = None reactor.callLater(self.secs_to_wait, self.suscribe)
def connectionLost(self, reason): log.warn( 'Detected inotify' ' connectionLost event, reason: {}'.format(reason) ) self.errback(reason)
def handle_change(self, stuff, path, mask): mask_str = inotify.humanReadableMask(mask) log.noise('Event: {} ({})'.format(path, mask_str)) ## Filtering path_real = path.realpath() if not path_real.isfile(): log.debug( 'Ignoring event for' ' non-regular file: {} (realpath: {})'.format(path, path_real) ) return dir_key = path_real.parent().realpath() if dir_key not in self.paths_watch: log.warn( 'Ignoring event for file outside of watched' ' set of paths: {} (realpath: {})'.format(path, path_real) ) return for pat in self.paths_watch[dir_key]: if fnmatch(bytes(path.basename()), pat): break else: log.noise( 'Non-matched path in one of' ' the watched dirs: {} (realpath: {})'.format(path, path_real) ) return for pat in self.exclude: if pat.search(path.path): log.noise( 'Matched path by exclude-pattern' ' ({}): {} (realpath: {})'.format(pat, path, path_real) ) return ## Get last position pos = self.paths_pos.get(path_real) if not pos: # try restoring it from xattr try: pos = pickle.loads(xattr(path_real.path)[self.conf.xattr_name]) except KeyError: log.debug('Failed to restore last log position from xattr for path: {}'.format(path)) else: log.noise( 'Restored pos from xattr ({}) for path {}: {!r}'\ .format(self.conf.xattr_name, path_real, pos) ) if pos: pos, size, data_hash = pos if self.file_end_check(path_real, pos, size=size, data_hash=data_hash): log.noise(( 'Event (mask: {}) for unchanged' ' path, ignoring: {}' ).format(mask_str, path)) return if path_real.getsize() < pos: log.debug( 'Detected truncation' ' of a path, rewinding: {}'.format(path) ) pos = None ## Actual processing buff_agg = self.paths_buff.setdefault(path_real, '') with path_real.open() as src: if pos: src.seek(pos) pos = None while True: pos = src.tell() try: buff, pos = self.read(src), src.tell() except StopIteration: buff_agg = '' src.seek(pos) # revert back to starting position buff, pos = self.read(src), src.tell() if not buff: # eof, try to mark the position if not buff_agg: # clean eof at the end of the chunk - mark it pos = self.file_end_mark(path_real, pos=pos, data=buff_agg) self.paths_pos[path_real] = pos xattr(path_real.path)[self.conf.xattr_name] = pickle.dumps(pos) log.noise( 'Updated xattr ({}) for path {} to: {!r}'\ .format(self.conf.xattr_name, path_real, pos) ) break buff_agg = self.paths_buff[path_real] = self.process(buff_agg + buff, path)
def run() -> None: """ runs the server """ # apply scripts protocol_class = FeatureProtocol connection_class = FeatureConnection script_objects = [] script_names = scripts_option.get() script_dir = os.path.join(config.config_dir, 'scripts/') for script in script_names[:]: try: # this finds and loads scripts directly from the script dir # no need for messing with sys.path f, filename, desc = imp.find_module(script, [script_dir]) module = imp.load_module('piqueserver_script_namespace_' + script, f, filename, desc) script_objects.append(module) except ImportError as e: # warning: this also catches import errors from inside the script # module it tried to load try: module = importlib.import_module(script) script_objects.append(module) except ImportError as e: log.error("(script '{}' not found: {!r})".format(script, e)) script_names.remove(script) for script in script_objects: protocol_class, connection_class = script.apply_script( protocol_class, connection_class, config.get_dict()) # apply the game_mode script if game_mode.get() not in ('ctf', 'tc'): # must be a script with this game mode module = None try: game_mode_dir = os.path.join(config.config_dir, 'game_modes/') f, filename, desc = imp.find_module(game_mode.get(), [game_mode_dir]) module = imp.load_module( 'piqueserver_gamemode_namespace_' + game_mode.get(), f, filename, desc) except ImportError as e: try: module = importlib.import_module(game_mode.get()) except ImportError as e: log.error("(game_mode '%s' not found: %r)" % (game_mode.get(), e)) if module: protocol_class, connection_class = module.apply_script( protocol_class, connection_class, config.get_dict()) protocol_class.connection_class = connection_class interface = network_interface.get().encode('utf-8') # instantiate the protocol class once. It will set timers and hooks to keep # itself running once we start the reactor protocol_class(interface, config.get_dict()) log.debug('Checking for unregistered config items...') unused = config.check_unused() if unused: log.warn('The following config items are not used:') pprint(unused) log.info('Started server...') profile = logging_profile_option.get() if profile: import cProfile cProfile.runctx('reactor.run()', None, globals()) else: reactor.run()
def dispatch(self, msg, source, user=None, direct=False): if not isinstance(msg, list): msg = [msg] channels = dict() if direct and user: # Direct reply log.noise('Dispatching msg from {!r} directly to user: {!r}'.format(source, user)) channels[user] = msg else: try: route = self.routes[self.relays.get(source) or source] except KeyError: log.noise('No routes to dispatch message to, dropping: {!r}'.format(msg)) return # Pull msg through all the pipelines and build dst channels / msgs buffer for dst, pipe in route: msg_copy = list(msg) for name in pipe: relay = self.relays[name] results = yield defer.DeferredList(list( defer.maybeDeferred(relay.dispatch, part) for part in msg_copy )) msg_copy = set() for chk, result in results: if not chk: log.error( 'Detected pipeline failure (src: {}, dst: {}, pipe: {}, relay: {}, msg: {}): {}'\ .format(source, dst, pipe, name, msg_copy, result) ) elif isinstance(result, list): msg_copy.update(result) else: msg_copy.add(result) msg_copy = msg_copy.difference({None}) if not msg_copy: break else: if dst in self.relays: extra_kwz = dict() if isinstance(dst, types.StringTypes): dst = self.relays[dst] if user and 'source' in inspect.getargspec(dst.dispatch).args: extra_kwz['source'] = user log.noise('Delivering msgs to dst relay: {}, extra_kwz: {}'.format(dst, extra_kwz)) yield defer.DeferredList(list( defer.maybeDeferred(dst.dispatch, msg_copy, **extra_kwz) for msg_copy in msg_copy )) else: channels.setdefault(self.channels[dst].name, set()).update(msg_copy) # Check whether anything can be delivered to channels at all if not self.proto: log.warn( 'Failed to deliver message(s)' ' ({!r}) to the following channels: {}'.format(msg, channels) ) defer.returnValue(None) # Encode and deliver for channel, msg in channels.viewitems(): for msg in msg: if not isinstance(msg, types.StringTypes): log.warn('Dropping non-string message: {!r}'.format(msg)) continue if isinstance(msg, unicode): try: msg = msg.encode(self.irc_enc) except UnicodeEncodeError as err: log.warn('Failed to encode ({}) unicode msg ({!r}): {}'.format(self.irc_enc, msg, err)) msg = msg.encode(self.irc_enc, 'replace') max_len = min( self.max_line_length, self.proto._safeMaximumLineLength('PRIVMSG {} :'.format(channel)) - 2 ) first_line = True for line in irc.split(msg, length=max_len): if not first_line: line = ' {}'.format(line) if not self.dry_run: self.proto.msg(channel, line) else: log.info('IRC line (channel: {}): {}'.format(channel, line)) first_line = False
def sent_err(failure): self.transport.lock.release() log.warn('send file error:%s' % failure.getErrorMessage())
def render_GET(self, request): """ handle requests like /login/username<space>password /login/username/password /login?username=&password= /logout /logout?next=URL """ paths = unquote(request.path.decode('utf-8')).split('/') command = paths[1] # only /login, /logout allowed assert command in ('login', 'logout') user = self.get_user(request) client_ip = request.transport.getPeer().host if self.allow_cross_origin: request.setHeader('Access-Control-Allow-Origin', '*') request.setHeader('Access-Control-Allow-Credentials', '*') #print 'command = ',command,'user.authenticated',user.authenticated __main__.statetree.emit('UserRequestLogin', user.username) session = request.getSession() if command == 'login' and user.authenticated: session.touch() log.info('User ' + user.username + ' login from ' + client_ip) return self.make_response({ 'retcode': 0, 'stdout': self.success_login_metadata(user) }) elif command == 'logout': if user.authenticated: log.debug('user ' + user.username + ' logout from ' + client_ip) user.logout() next_url = request.args.get(b'next', [None])[0] if next_url: #http://127.0.0.1:2880/logo?next=http://127.0.0.1:2880/app/whiteboard.html assert not next_url.startswith(b'/logout') request.setResponseCode(302) request.setHeader('Location', next_url.decode()) return b'bye' else: return self.make_response({'retcode': 0, 'stdout': 'Good-bye'}) def login_failed(request): request.setResponseCode(403) user.did_login_failure() if user.authentication_failure_count < self.max_failure: # diffrent message to hind the failure point (developing) log.warn('login failured from ' + client_ip) request.write(b'Login failure, try again') request.finish() else: log.warn('login failures over ' + str(self.max_failure) + ' times from ' + client_ip) request.write(b'Too many failure, good bye') request.finish() # do login starts login_type = request.args.get(b'type', [None])[0] if login_type: # A customized mechanism to do login # 1. Register a type-handler in server side try: ok = self.type_handler[login_type.decode()](user, request) except Exception as e: log.warn('login failure, type=%s, e=%s' % (login_type, e)) login_failed(request) return NOT_DONE_YET else: # re-compose command line, accepts following formats # /login/username<space>password # /login/username/password # /login?username=&password= message = '' username = '' password = '' if len(paths[2:]): line = 'login ' + (' '.join(paths[2:])) commands = ObjshCommand.decodeChunks([line]) # only 1 command supported per request command = commands[0] #log.msg('line = '+line+'; args=',command.args) username = str( command.args[0]) if len(command.args) > 0 else '' password = str( command.args[1]) if len(command.args) > 1 else '' elif request.args.get(b'username'): username = request.args[b'username'][0].decode('utf-8').strip() password = request.args.get(b'password', [b''])[0].decode('utf-8').strip() else: message = 'access denied!' message = 'unauthorized %s' % time.time() if not (username and password): login_failed(request) return NOT_DONE_YET # user.login is an inline callback, so the following line is blocking code try: log.debug('login with', [username, password]) ok = user.login(username, password) except: traceback.print_exc() if isinstance(ok, defer.Deferred): def next(ret, request): if user.authenticated: # succeed to login log.info('A user ' + user.username + ' login from ' + client_ip) # enforce to su to another user #if os.environ['USER']=='root': raise NotImplementedError() self.send_object( request, { 'retcode': 0, 'stdout': self.success_login_metadata(user) }) request.finish() else: login_failed(request) def err(failure, request): errmsg = failure.getErrorMessage() if errmsg: log.msg('auth error:%s' % errmsg) login_failed(request) ok.addCallback(next, request) ok.addErrback(err, request) return NOT_DONE_YET elif user.authenticated: log.info('USER ' + user.username + ' login from ' + client_ip) return self.make_response({ 'retcode': 0, 'stdout': self.success_login_metadata(user) }) else: login_failed(request) return NOT_DONE_YET
def dispatch(self, msg): if not msg.strip(): return ## Event lines are cached until EOE msg is encountered match = self._re_base.search(msg) if not match: log.warn('Failed to match audit event spec: {!r}'.format(msg)) return node, ev_id, ev_type, msg = (match.group(k) for k in ['node', 'ev_id', 'type', 'msg']) ev_key = node, ev_id if ev_key not in self._ev_cache: self._ev_cache[ev_key] = defaultdict(list) self._ev_cache[ev_key].update(ts=time.time(), node=node, ev_id=ev_id) self._ev_cache_gc() ev = self._ev_cache[ev_key] if ev_type != 'EOE': # cache event data ev[ev_type].append(msg) return del self._ev_cache[ev_key] ## Get "key" value for event, if present ev_key = None try: syscall, = ev['SYSCALL'] # currently handled events always have it except ValueError: pass else: try: ev_key = self.get_msg_val(syscall, 'key', ur'"(?P<val>[^"]+)"') except KeyError as err: log.noise('Failed to get ev_key from syscall: {}'.format(err)) if not ev_key: log.noise('Unhandled event: {!r}'.format(ev)) return ## Processing if ev_key in self.conf.events.watches.ev_keys: # Extract all necessary attributes ev_vals = dict(node=ev['node'], ev_id=ev['ev_id'], key=ev_key) for k in it.imap(''.join, it.product(['', 'e', 's', 'fs'], ['uid', 'gid'])): ev_vals[k] = self.get_msg_val(syscall, k) for k in 'comm', 'exe': ev_vals[k] = self.get_msg_val(syscall, k, ur'"(?P<val>[^"]+)"') ev_vals['tty'] = self.get_msg_val(syscall, 'tty', '(?P<val>\S+)') paths = ev_vals['paths'] = list() for msg in ev['PATH']: path = self.get_msg_val(msg, 'name', ur'(?P<val>"[^"]+"|\(null\)|[0-9A-F]+)') paths.append(dict( path=path, inode=self.get_msg_val(msg, 'inode', fallback='nil'), dev=self.get_msg_val(msg, 'dev', '(?P<val>[a-f\d]{2}:[a-f\d]{2})', fallback='nil') )) # Formatting err, tpl = None, force_unicode(self.conf.events.watches.template_path) ev_vals['paths'] = list() for val in paths: try: ev_vals['paths'].append(tpl.format(**val)) except self._lookup_error as err: break if not err: ev_vals['paths'] = ', '.join(ev_vals['paths']) tpl, val = force_unicode(self.conf.events.watches.template), ev_vals try: event = tpl.format(**val) except self._lookup_error as err: pass event = RelayedEvent(event) event.data = ev_vals return event raise ValueError( 'Failed to format template {!r} (data: {}): {}'.format(tpl, val, err))