def start(self, username, password, resource): log_debug(3, username, password, resource) # XXX find a better name for this function self.auth(username, password, resource) self.username = username self.resource = resource self.jid = "%s@%s/%s" % (self.username, self._host, self.resource) # Retrieve roster self.retrieve_roster()
def unstick_contacts(self, jids): """If we are waiting for 'subscribed' presence stanzas for too long, ask again""" if time.time() - self._stuck_subscription_timestamp > 60: for jid in jids: stripped_jid = self._strip_resource(jid) if self.needs_unsticking(stripped_jid): presence_node = jabber_lib.JabberPresenceNode(to=stripped_jid, type="subscribe") presence_node.setID("presence-%s" % self.get_unique_id()) log_debug(4, "Re-sending presence subscription request", presence_node) self.send(presence_node) self._stuck_subscription_timestamp = time.time()
def _message_callback(self, client, stanza): log_debug(4) assert stanza.getName() == 'message' # Actions we know how to react to actions = [ jabber_lib.NS_RHN_MESSAGE_REQUEST_CHECKIN, jabber_lib.NS_RHN_MESSAGE_REQUEST_PING, ] sig = self._check_signature_from_message(stanza, actions) if not sig: return action = sig.getAttr('action') if action == jabber_lib.NS_RHN_MESSAGE_REQUEST_PING: log_debug(1, 'Ping request') self.send_message(stanza.getFrom(), jabber_lib.NS_RHN_MESSAGE_RESPONSE_PING) return # Send confirmation self.send_message(stanza.getFrom(), jabber_lib.NS_RHN_MESSAGE_RESPONSE_CHECKIN) # Checkin run_check = self._config.get('run_rhn_check') log_debug(3, "run_rhn_check:", run_check) if not self._config.get('run_rhn_check'): log_debug(0, "Pretend that command just ran") else: self.run_rhn_check_async()
def run_rhn_check_async(self): """Runs rhn_check and keeps a handle that it is monitored during the event loop """ command = self._config.get('rhn_check_command') # rhn_check now checks for multiple instances, # lets use that directly if command is None: args = [self.RHN_CHECK_CMD] else: # XXX should find a better way to get the list of args args = command.split() # if rhn_check process already exists if self._rhn_check_process is not None: retcode = self._rhn_check_process.poll() if retcode is None: log_debug(3, "rhn_check is still running, not running again...") return if self._rhn_check_fail_count > 0: log_debug(3, "rhn_check failed last time (fail count %d)" % self._rhn_check_fail_count) log_debug(3, "About to execute:", args) oldumask = os.umask(int("0077", 8)) os.umask(oldumask | int("0022", 8)) self._rhn_check_process = Popen(args) os.umask(oldumask) log_debug(0, "executed %s with pid %d" % (args[0], self._rhn_check_process.pid))
def run_rhn_check_async(self): """Runs rhn_check and keeps a handle that it is monitored during the event loop """ command = self._config.get('rhn_check_command') # rhn_check now checks for multiple instances, # lets use that directly if command is None: args = [self.RHN_CHECK_CMD] else: # XXX should find a better way to get the list of args args = command.split() # if rhn_check process already exists if self._rhn_check_process is not None: retcode = self._rhn_check_process.poll() if retcode is None: log_debug(3, "rhn_check is still running, not running again...") return if self._rhn_check_fail_count > 0: log_debug(3, "rhn_check failed last time (fail count %d)" % self._rhn_check_fail_count) log_debug(3, "About to execute:", args) oldumask = os.umask(int("0077", 8)) os.umask(oldumask | int("0022", 8)) Client.rhncheckPID = self._rhn_check_process = Popen(args) os.umask(oldumask) log_debug(0, "executed %s with pid %d" % (args[0], self._rhn_check_process.pid))
def setup_config(self, config, force=0): # We don't want to slam the server with lots of XMLRPC requests at the # same time, especially if jabberd goes down - in that case all # clients are slamming the server at the same time try: if (self._config_setup_counter % self._config_setup_interval == 0) or \ force: # This will catch the first pass too self._setup_config(config, force) else: log_debug(4, "Skipping config setup; counter=%s; interval=%s" % (self._config_setup_counter, self._config_setup_interval)) except: self._config_setup_counter = 0 raise # Update the counter for the next time self._config_setup_counter = self._config_setup_counter + 1
def _create_signature(self, jid, action): log_debug(4, jid, action) attrs = { 'client-id' : self.client_id, 'timestamp' : int(time.time()), 'serial' : self.get_unique_id(), 'action' : action, 'jid' : self.jid, } signing_comps = ['client-id', 'timestamp', 'serial', 'action', 'jid'] args = [self.shared_key, jid] for sc in signing_comps: args.append(attrs[sc]) log_debug(4, "Signature args", args) attrs['signature'] = jabber_lib.sign(*args) x = jabber_lib.jabber.xmlstream.Node('x') x.setNamespace(jabber_lib.NS_RHN_SIGNED) for k, v in attrs.items(): x.putAttr(k, v) return x
def _create_signature(self, jid, action): log_debug(4, jid, action) attrs = { 'client-id': self.client_id, 'timestamp': int(time.time()), 'serial': self.get_unique_id(), 'action': action, 'jid': self.jid, } signing_comps = ['client-id', 'timestamp', 'serial', 'action', 'jid'] args = [self.shared_key, jid] for sc in signing_comps: args.append(attrs[sc]) log_debug(4, "Signature args", args) attrs['signature'] = jabber_lib.sign(*args) x = jabber_lib.jabber.xmlstream.Node('x') x.setNamespace(jabber_lib.NS_RHN_SIGNED) for k, v in attrs.items(): x.putAttr(k, v) return x
def process_once(self, client): # Re-read the systemid file. If it's changed from the # previous version re-setup the config. This will create a new # key on the satellite server tied to this new system id. # This change prevents having to restart osad after a system # re-registration. systemid = open(self._systemid_file).read() if systemid != self._systemid: log_debug(4, "System re-registration detected. systemid file has changed.") config = self.read_config() raise jabber_lib.NeedRestart # make sure that dispatchers are not stuck in state [none + ask] or [from + ask] # for too long. This can happen, for example, if a "subscribe" presence stanza # gets lost - in that case re-send it client.unstick_contacts(self._dispatchers) # if rhn_check is running or the last one failed, check more often if (client._rhn_check_process is None) and (client._rhn_check_fail_count < 1): client.process(timeout=180) else: client.process(timeout=5)
def process_loop_hook(self): # if rhn_check process exists, check it last # status if self._rhn_check_process is not None: retcode = self._rhn_check_process.poll() if retcode is not None: log_debug(3, "rhn_check exited with status %d" % retcode) if retcode != 0: self._rhn_check_fail_count += 1 else: self._rhn_check_fail_count = 0 self._rhn_check_process = None else: log_debug(3, "rhn_check is still running...") else: # rhn_check is not running but last one failed # we force a check even if the server does not # contact us. The idea is to exhaust the number of # times we can pick up the action until the server fails # it. if self._rhn_check_fail_count > 0: log_debug(3, "rhn_check failed last time, " \ "force retry (fail count %d)" % self._rhn_check_fail_count) self.run_rhn_check_async()
def _setup_config(self, config, force=0): logfile = self.options.logfile if logfile is None or logfile == '': logfile = config['logfile'] debug_level = self.options.verbose if debug_level is None: dl = config['debug_level'] if dl is not None: debug_level = int(dl) else: dl = 0 set_logfile(logfile) self.debug_level = debug_level set_debug_level(debug_level) self._tcp_keepalive_timeout = config['tcp_keepalive_timeout'] self._tcp_keepalive_count = config['tcp_keepalive_count'] log_debug(3, "Updating configuration") client_ssl_cert = config['ssl_ca_cert'] osa_ssl_cert = config['osa_ssl_cert'] or client_ssl_cert if osa_ssl_cert is None: die("No SSL cert supplied") self.ssl_cert = osa_ssl_cert auth_info = self.read_auth_info(force) self._username = auth_info['username'] self._password = auth_info['password'] self._resource = auth_info['resource'] server_url = config.get('server_url') self._jabber_servers = [] if self.options.jabber_server: self._jabber_servers.append(self.options.jabber_server) if type(server_url) == type([]): for su in server_url: a_su = self._parse_url(su)[1] self._jabber_servers.append(a_su) else: upstream_jabber_server = self._parse_url(server_url)[1] if upstream_jabber_server not in self._jabber_servers: self._jabber_servers.append(upstream_jabber_server) if 'enable_failover' not in config or config['enable_failover'] != '1': self._jabber_servers = [self._jabber_servers[0]] # Load the config self._config_options.clear() self._config_options.update(config) # No reason to expose these at the Client level - but if we have to, # uncommment some of the values below self._config_options.update({ # 'jabber-servers' : self._jabber_servers, # 'dispatchers' : self._dispatchers, # 'client_name' : self._client_name, # 'shared_key' : self._shared_key, })
def read_config(self): ret = {} # Read from the global config first config_file = self.options.cfg self._config = osad_config.init('osad', config_file=config_file) config_keys = [ 'debug_level', 'osa_ssl_cert', 'logfile', 'run_rhn_check', 'rhn_check_command', 'enable_failover' ] for key in config_keys: ret[key] = osad_config.get(key) try: server_url = osad_config.get('server_url') except osad_config.InterpolationError: e = sys.exc_info()[1] server_url = config.getServerlURL() else: if not server_url: server_url = config.getServerlURL() else: def convert_url(s): s = s.strip() if hasattr(config, 'convert_url_to_puny'): s = config.convert_url_to_puny(s) elif hasattr(config, 'convert_url_to_pune'): s = config.convert_url_to_pune(s) return s server_url = [convert_url(i) for i in server_url.split(';')] # Remove empty URLs for url in server_url: if not url: server_url.remove(url) # Real unusual case if there is no server URL both in up2date and osad config files if not server_url: die("Missing server URL in config file") ret['server_url'] = server_url #8/23/05 wregglej 165775 added the run_rhn_check option. run_rhn_check = osad_config.get('run_rhn_check') if run_rhn_check is None: log_debug(3, "Forcing run_rhn_check") run_rhn_check = 1 ret['run_rhn_check'] = int(run_rhn_check) ret['tcp_keepalive_timeout'] = int( osad_config.get('tcp_keepalive_timeout', defval=1800)) ret['tcp_keepalive_count'] = int( osad_config.get('tcp_keepalive_count', defval=3)) systemid = osad_config.get('systemid') if systemid is None: systemid = self.get_up2date_config()['systemIdPath'] ret['systemid'] = systemid enable_proxy = self._config.get_option('enableProxy') if enable_proxy is None: enable_proxy = self.get_up2date_config()['enableProxy'] if enable_proxy: ret['enable_proxy'] = 1 ret['proxy_url'] = self._config.get_option('httpProxy') if ret['proxy_url'] is None: ret['proxy_url'] = str(config.getProxySetting()) ret['enable_proxy_auth'] = 0 enable_proxy_auth = self._config.get_option('enableProxyAuth') if enable_proxy_auth is None: enable_proxy_auth = self.get_up2date_config( )['enableProxyAuth'] if enable_proxy_auth: ret['enable_proxy_auth'] = 1 proxy_user = self._config.get_option('proxyUser') if proxy_user is None: proxy_user = self.get_up2date_config()['proxyUser'] ret['proxy_user'] = proxy_user proxy_password = self._config.get_option('proxyPassword') if proxy_password is None: proxy_password = self.get_up2date_config()['proxyPassword'] ret['proxy_password'] = proxy_password if not server_url: die("Unable to retrieve server URL") # SSL cert for Jabber's TLS, it can potentially be different than the # client's osa_ssl_cert = self._config.get_option('osa_ssl_cert') # The up2date ssl cert - we get it from up2daate's config file client_ca_cert = self.get_up2date_config()['sslCACert'] if isinstance(client_ca_cert, ListType): if client_ca_cert: client_ca_cert = client_ca_cert[0] else: client_ca_cert = None if osa_ssl_cert is None: # No setting, use up2date's osa_ssl_cert = client_ca_cert if client_ca_cert is not None: ret['ssl_ca_cert'] = client_ca_cert if osa_ssl_cert is not None: ret['osa_ssl_cert'] = osa_ssl_cert return ret
def fix_connection(self, c): "After setting up the connection, do whatever else is necessary" # Setup XMLRPC server xmlrpc_params = self.build_rpclib_params(self._config_options) # Looking for a server we connected to jabberd on server_urls = self._config_options['server_url'] for url in server_urls: if self._connected_jabber_server in url: xmlrpc_params['uri'] = url break server = rpclib.Server(**xmlrpc_params) self._xmlrpc_server = server client_ssl_cert = self._config_options['ssl_ca_cert'] osa_ssl_cert = self._config_options['osa_ssl_cert'] or client_ssl_cert if osa_ssl_cert: server.add_trusted_cert(osa_ssl_cert) server.registration.welcome_message() server_capabilities = get_server_capability(server) if 'registration.register_osad' not in server_capabilities: raise Exception("Server does not support OSAD registration") self._systemid_file = self._config_options['systemid'] self._systemid = open(self._systemid_file).read() current_timestamp = int(time.time()) ret = server.registration.register_osad( self._systemid, {'client-timestamp': current_timestamp}) #Bugzilla: 142067 #If the server doesn't have push support. 'ret' won't have anything in it. if len(ret.keys()) < 1: raise jabber_lib.JabberConnectionError js = ret.get('jabber-server') if js not in self._jabber_servers: self._jabber_servers.append(js) server_timestamp = ret.get('server-timestamp') # Compute the time drift between the client and the server self._time_drift = server_timestamp - current_timestamp log_debug(2, "Time drift", self._time_drift) self._dispatchers = ret.get('dispatchers') self._client_name = ret.get('client-name') self._shared_key = ret.get('shared-key') log_debug(2, "Client name", self._client_name) log_debug(2, "Shared key", self._shared_key) c.set_config_options(self._config_options) c.client_id = self._client_name c.shared_key = self._shared_key c.time_drift = self._time_drift c._sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) c._sock.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, self._tcp_keepalive_timeout) c._sock.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT, self._tcp_keepalive_count) # Update the jabber ID systemid = open(self._systemid_file).read() args = { 'jabber-id': str(c.jid), } ret = self._xmlrpc_server.registration.register_osad_jid( systemid, args) c.set_dispatchers(self._dispatchers) c.subscribe_to_presence(self._dispatchers) # Signal presence to the jabber server c.send_presence() return c
def handle(self, signal, frame): if osad_client.Client.rhncheckPID: log_debug(4, "Waiting for process " + str(osad_client.Client.rhncheckPID .pid) + " to finish.") osad_client.Client.rhncheckPID.wait() sys.exit(0)
def _check_signature(self, stanza, actions=None): # Do we have this client in the table? jid = stanza.getFrom() if jid is None: log_debug(3, 'no from') return None # Look for a <x> child that has our namespace xes = stanza.getTags('x') for x in xes: if x.getNamespace() != jabber_lib.NS_RHN_SIGNED: continue break else: #for log_debug(1, "No signature node found in stanza") return None timestamp = x.getAttr('timestamp') try: timestamp = int(timestamp) except ValueError: log_debug(1, "Invalid message timestamp", timestamp) return None now = time.time() current_drift = timestamp - now # Allow for a 120 seconds drift max_drift = 120 abs_drift = abs(current_drift - self.time_drift) if abs_drift > max_drift: log_debug(1, "Dropping message, drift is too big", abs_drift) action = x.getAttr('action') if actions and action not in actions: log_debug(1, "action %s not allowed" % action) return None # We need the fully qualified JID here too full_jid = x.getAttr('jid') if not full_jid: log_debug(3, "Full JID not found in signature stanza") return None attrs = { 'timestamp': x.getAttr('timestamp'), 'serial': x.getAttr('serial'), 'action': x.getAttr('action'), 'jid': full_jid, } signing_comps = ['timestamp', 'serial', 'action', 'jid'] args = [self.shared_key, self.jid] for sc in signing_comps: args.append(attrs[sc]) log_debug(4, "Signature args", args) signature = jabber_lib.sign(*args) x_signature = x.getAttr('signature') if signature != x_signature: log_debug(1, "Signatures do not match", signature, x_signature) return None # Happy joy return x
def fix_connection(self, c): "After setting up the connection, do whatever else is necessary" # Setup XMLRPC server xmlrpc_params = self.build_rpclib_params(self._config_options) # Looking for a server we connected to jabberd on server_urls = self._config_options['server_url'] for url in server_urls: if self._connected_jabber_server in url: xmlrpc_params['uri'] = url break server = rpclib.Server(**xmlrpc_params) self._xmlrpc_server = server client_ssl_cert = self._config_options['ssl_ca_cert'] osa_ssl_cert = self._config_options['osa_ssl_cert'] or client_ssl_cert if osa_ssl_cert: server.add_trusted_cert(osa_ssl_cert) server.registration.welcome_message() server_capabilities = get_server_capability(server) if 'registration.register_osad' not in server_capabilities: raise Exception("Server does not support OSAD registration") self._systemid_file = self._config_options['systemid'] self._systemid = open(self._systemid_file).read() current_timestamp = int(time.time()) ret = server.registration.register_osad(self._systemid, {'client-timestamp': current_timestamp}) #Bugzilla: 142067 #If the server doesn't have push support. 'ret' won't have anything in it. if len(ret.keys()) < 1: raise jabber_lib.JabberConnectionError js = ret.get('jabber-server') if js not in self._jabber_servers: self._jabber_servers.append(js) server_timestamp = ret.get('server-timestamp') # Compute the time drift between the client and the server self._time_drift = server_timestamp - current_timestamp log_debug(2, "Time drift", self._time_drift) self._dispatchers = ret.get('dispatchers') self._client_name = ret.get('client-name') self._shared_key = ret.get('shared-key') log_debug(2, "Client name", self._client_name) log_debug(2, "Shared key", self._shared_key) c.set_config_options(self._config_options) c.client_id = self._client_name c.shared_key = self._shared_key c.time_drift = self._time_drift c._sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) c._sock.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, self._tcp_keepalive_timeout) c._sock.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT, self._tcp_keepalive_count) # Update the jabber ID systemid = open(self._systemid_file).read() args = { 'jabber-id' : str(c.jid), } ret = self._xmlrpc_server.registration.register_osad_jid(systemid, args) c.set_dispatchers(self._dispatchers) c.subscribe_to_presence(self._dispatchers) # Signal presence to the jabber server c.send_presence() return c
def read_config(self): ret = {} # Read from the global config first config_file = self.options.cfg self._config = osad_config.init('osad', config_file=config_file) config_keys = ['debug_level', 'osa_ssl_cert', 'logfile', 'run_rhn_check', 'rhn_check_command', 'enable_failover'] for key in config_keys: ret[key] = osad_config.get(key) try: server_url = osad_config.get('server_url') except osad_config.InterpolationError: e = sys.exc_info()[1] server_url = config.getServerlURL() else: if not server_url: server_url = config.getServerlURL() else: def convert_url(s): s = s.strip() if hasattr(config, 'convert_url_to_puny'): s = config.convert_url_to_puny(s) elif hasattr(config, 'convert_url_to_pune'): s = config.convert_url_to_pune(s) return s server_url = [convert_url(i) for i in server_url.split(';')] # Remove empty URLs for url in server_url: if not url: server_url.remove(url) # Real unusual case if there is no server URL both in up2date and osad config files if not server_url: die("Missing server URL in config file") ret['server_url'] = server_url #8/23/05 wregglej 165775 added the run_rhn_check option. run_rhn_check = osad_config.get('run_rhn_check') if run_rhn_check is None: log_debug(3, "Forcing run_rhn_check") run_rhn_check = 1 ret['run_rhn_check'] = int(run_rhn_check) ret['tcp_keepalive_timeout'] = int(osad_config.get('tcp_keepalive_timeout', defval=1800)) ret['tcp_keepalive_count'] = int(osad_config.get('tcp_keepalive_count', defval=3)) systemid = osad_config.get('systemid') if systemid is None: systemid = self.get_up2date_config()['systemIdPath'] ret['systemid'] = systemid enable_proxy = self._config.get_option('enableProxy') if enable_proxy is None: enable_proxy = self.get_up2date_config()['enableProxy'] if enable_proxy: ret['enable_proxy'] = 1 ret['proxy_url'] = self._config.get_option('httpProxy') if ret['proxy_url'] is None: ret['proxy_url'] = str(config.getProxySetting()) ret['enable_proxy_auth'] = 0 enable_proxy_auth = self._config.get_option('enableProxyAuth') if enable_proxy_auth is None: enable_proxy_auth = self.get_up2date_config()['enableProxyAuth'] if enable_proxy_auth: ret['enable_proxy_auth'] = 1 proxy_user = self._config.get_option('proxyUser') if proxy_user is None: proxy_user = self.get_up2date_config()['proxyUser'] ret['proxy_user'] = proxy_user proxy_password = self._config.get_option('proxyPassword') if proxy_password is None: proxy_password = self.get_up2date_config()['proxyPassword'] ret['proxy_password'] = proxy_password if not server_url: die("Unable to retrieve server URL") # SSL cert for Jabber's TLS, it can potentially be different than the # client's osa_ssl_cert = self._config.get_option('osa_ssl_cert') # The up2date ssl cert - we get it from up2daate's config file client_ca_cert = self.get_up2date_config()['sslCACert'] if isinstance(client_ca_cert, ListType): if client_ca_cert: client_ca_cert = client_ca_cert[0] else: client_ca_cert = None if osa_ssl_cert is None: # No setting, use up2date's osa_ssl_cert = client_ca_cert if client_ca_cert is not None: ret['ssl_ca_cert'] = client_ca_cert if osa_ssl_cert is not None: ret['osa_ssl_cert'] = osa_ssl_cert return ret
def _check_signature(self, stanza, actions=None): # Do we have this client in the table? jid = stanza.getFrom() if jid is None: log_debug(3, 'no from') return None # Look for a <x> child that has our namespace xes = stanza.getTags('x') for x in xes: if x.getNamespace() != jabber_lib.NS_RHN_SIGNED: continue break else: #for log_debug(1, "No signature node found in stanza") return None timestamp = x.getAttr('timestamp') try: timestamp = int(timestamp) except ValueError: log_debug(1, "Invalid message timestamp", timestamp) return None now = time.time() current_drift = timestamp - now # Allow for a 120 seconds drift max_drift = 120 abs_drift = abs(current_drift - self.time_drift) if abs_drift > max_drift: log_debug(1, "Dropping message, drift is too big", abs_drift) action = x.getAttr('action') if actions and action not in actions: log_debug(1, "action %s not allowed" % action) return None # We need the fully qualified JID here too full_jid = x.getAttr('jid') if not full_jid: log_debug(3, "Full JID not found in signature stanza") return None attrs = { 'timestamp' : x.getAttr('timestamp'), 'serial' : x.getAttr('serial'), 'action' : x.getAttr('action'), 'jid' : full_jid, } signing_comps = ['timestamp', 'serial', 'action', 'jid'] args = [self.shared_key, self.jid] for sc in signing_comps: args.append(attrs[sc]) log_debug(4, "Signature args", args) signature = jabber_lib.sign(*args) x_signature = x.getAttr('signature') if signature != x_signature: log_debug(1, "Signatures do not match", signature, x_signature) return None # Happy joy return x