def _verifyProxyAuthToken(auth_token): """ verifies the validity of a proxy auth token NOTE: X-RHN-Proxy-Auth described in proxy/broker/rhnProxyAuth.py """ log_debug(4, auth_token) token, hostname = splitProxyAuthToken(auth_token) hostname = hostname.strip() ipv4_regex = '^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])$' # This ipv6 regex was develeoped by Stephen Ryan at Dataware. # (http://forums.intermapper.com/viewtopic.php?t=452) It is licenced # under a Creative Commons Attribution-ShareAlike 3.0 Unported # License, so we are free to use it as long as we attribute it to him. ipv6_regex = '^((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?$' hostname_is_ip_address = re.match(ipv4_regex, hostname) or re.match(ipv6_regex, hostname) headers = rhnFlags.get('outputTransportOptions') if len(token) < 5: # Bad auth information; decline any action log_debug(4, "incomplete proxy authentication token: %s" % auth_token) headers['X-RHN-Proxy-Auth-Error'] = '%s:%s' % ( 1003, _("incomplete proxy authentication token: %s") % auth_token) if not hostname_is_ip_address: headers['X-RHN-Proxy-Auth-Origin'] = hostname raise rhnFault(1003) # Invalid session key log_debug(5, "proxy auth token: %s, hostname: %s" % (repr(token), hostname or 'n/a')) proxyId, proxyUser, rhnServerTime, expireOffset, signature = token[:5] computed = computeSignature(CFG.SECRET_KEY, proxyId, proxyUser, rhnServerTime, expireOffset) if computed != signature: log_error("Proxy signature failed: proxy id='%s', proxy user='******'" % (proxyId, proxyUser)) log_debug(4, "Sent proxy signature %s does not match ours %s." % ( signature, computed)) headers['X-RHN-Proxy-Auth-Error'] = '%s:%s' % ( 1003, _("Sent proxy signature %s does not match ours %s.") % ( signature, computed)) if not hostname_is_ip_address: headers['X-RHN-Proxy-Auth-Origin'] = hostname raise rhnFault(1003) # Invalid session key # Convert the expiration/time to floats: rhnServerTime = float(rhnServerTime) expireOffset = float(expireOffset) if rhnServerTime + expireOffset < time.time(): log_debug(4, "Expired proxy authentication token") headers['X-RHN-Proxy-Auth-Error'] = '%s:%s' % (1004, "Expired") if not hostname_is_ip_address: headers['X-RHN-Proxy-Auth-Origin'] = hostname raise rhnFault(1004) # Expired client authentication token log_debug(4, "Proxy auth OK: sigs match; not an expired token") return 1
def getAnyChecksum(self, info, username=None, password=None, session=None, is_source=0): """ returns checksum info of available packages also does an existance check on the filesystem. """ log_debug(3) pkg_infos = info.get('packages') channels = info.get('channels', []) force = info.get('force', 0) orgid = info.get('org_id') if orgid == 'null': null_org = 1 else: null_org = None if not session: org_id, force = rhnPackageUpload.authenticate(username, password, channels=channels, null_org=null_org, force=force) else: try: org_id, force = rhnPackageUpload.authenticate_session( session, channels=channels, null_org=null_org, force=force) except rhnSession.InvalidSessionError: raise_with_tb(rhnFault(33), sys.exc_info()[2]) except rhnSession.ExpiredSessionError: raise_with_tb(rhnFault(34), sys.exc_info()[2]) if is_source: ret = self._getSourcePackageChecksum(org_id, pkg_infos) else: ret = self._getPackageChecksum(org_id, pkg_infos) return ret
def __init__(self, dict=None): log_debug(4, dict) self.ifaces = {} self.db_ifaces = [] # parameters which are not allowed to be empty and set to NULL self._autonull = ('hw_addr', 'module') if not dict: return for name, info in dict.items(): if name == 'class': # Ignore it continue if not isinstance(info, type({})): raise rhnFault(53, "Unexpected format for interface %s" % name) vdict = {} for key, mapping in self.key_mapping.items(): # Look at the mapping first; if not found, look for the key if info.has_key(mapping): k = mapping else: k = key if not info.has_key(k): raise rhnFault(53, "Unable to find required field %s" % key) val = info[k] vdict[mapping] = val if 'ipaddr' in info and info['ipaddr']: vdict['ipv4'] = NetIfaceAddress4( [{'ipaddr': info['ipaddr'], 'broadcast': info['broadcast'], 'netmask': info['netmask']}]) if 'ipv6' in info and info['ipv6']: vdict['ipv6'] = NetIfaceAddress6(info["ipv6"]) self.ifaces[name] = vdict
def new_user(self, username, password, email = None, org_id = None, org_password = None): """ Finish off creating the user. The user has to exist (must be already reserved), the password must match and we set the e-mail address if one is given Return true if success """ log_debug(1, username, email) # email has to be a string or nothing if not checkValue(email, None, "", type("")): raise rhnFault(30, _faultValueString(email, "email")) # be somewhat drastic about the org values if org_id and org_password: org_password = str(org_password) try: org_id = int(str(org_id)) except ValueError: raise rhnFault(30, _faultValueString(org_id, "org_id")), None, sys.exc_info()[2] else: org_id = org_password = None username, password = rhnUser.check_user_password(username, password) email = rhnUser.check_email(email) # now create this user ret = rhnUser.new_user(username, password, email, org_id, org_password) # rhnUser.new_user will raise it's own faults. return ret
def update_crash_count(self, system_id, crash, crash_count): self.auth_system(system_id) log_debug(1, self.server_id, "Updating crash count for %s to %s" % (crash, crash_count)) server_org_id = self.server.server['org_id'] server_crash_dir = get_crash_path(str(server_org_id), str(self.server_id), crash) if not server_crash_dir: log_debug(1, self.server_id, "Error composing crash directory path") raise rhnFault(5002) h = rhnSQL.prepare(_query_update_crash_count) r = h.execute( crash_count=crash_count, server_id=self.server_id, crash=crash) rhnSQL.commit() if r == 0: log_debug(1, self.server_id, "No record for crash: %s" % crash) raise rhnFault(5005, "Invalid crash name: %s" % crash) absolute_dir = os.path.join(CFG.MOUNT_POINT, server_crash_dir) absolute_file = os.path.join(absolute_dir, 'count') log_debug(1, self.server_id, "Updating crash count file: %s" % absolute_file) f = open(absolute_file, 'w+') f.write(crash_count) f.close() return 1
def auth_client(self, token): """ Authenticate a system based on the same authentication tokens the client is sending for GET requests """ log_debug(3) # Build a UserDictCase out of the token dict = UserDictCase(token) # Set rhnFlags so that we can piggyback on apacheAuth's auth_client rhnFlags.set('AUTH_SESSION_TOKEN', dict) # XXX To clean up apacheAuth.auth_client's logging, this is not about # GET requests result = apacheAuth.auth_client() if not result: raise rhnFault(33, _("Invalid session key")) log_debug(4, "Client auth OK") # We checked it already, so we're sure it's there client_id = dict['X-RHN-Server-Id'] server = rhnServer.search(client_id) if not server: raise rhnFault(8, _("This server ID no longer exists")) # XXX: should we check if the username still has access to it? # probably not, because there is no known good way we can # update the server system_id on the client side when # permissions change... Damn it. --gafton self.server = server self.server_id = client_id self.user = dict['X-RHN-Auth-User-Id'] return server
def check_user_password(username, password): """ Do some minimal checks on the data thrown our way. """ # username is required if not username: raise rhnFault(11) # password is required if not password: raise rhnFault(12) if len(username) < CFG.MIN_USER_LEN: raise rhnFault(13, _("username should be at least %d characters") % CFG.MIN_USER_LEN) if len(username) > CFG.MAX_USER_LEN: raise rhnFault(700, _("username should be less than %d characters") % CFG.MAX_USER_LEN) username = username[:CFG.MAX_USER_LEN] # Invalid characters # ***NOTE*** Must coordinate with web and installer folks about any # changes to this set of characters!!!! invalid_re = re.compile(".*[\s&+%'`\"=#]", re.I) tmp = invalid_re.match(username) if tmp is not None: pos = tmp.regs[0] raise rhnFault(15, _("username = `%s', invalid character `%s'") % ( username, username[pos[1] - 1])) # use new password validation method validate_new_password(password) return username, password
def valid(self): log_debug(4) # check for anonymous if self.attrs.get('machine_id'): entitlements = check_entitlement_by_machine_id(self.attrs.get('machine_id')) log_debug(4, "found entitlements for machine_id", self.attrs.get('machine_id'), entitlements) if 'salt_entitled' in entitlements: raise rhnFault(48, """ This system is already registered as a Salt Minion. If you want to register it as a traditional client please delete it first via the web UI or API and then register it using the traditional tools. """) if 'type' in self.attrs and self.attrs['type'] \ and string.upper(self.attrs['type']) == "ANONYMOUS": raise rhnFault(28, """ You need to re-register your system with SUSE Manager. Previously you have chosen to skip the creation of a system profile with SUSE Manager and this trial feature is no longer available now. """) # we don't support anonymous anymore # now we have a real server. Get its secret sid = self.attrs["system_id"] secret = getServerSecret(sid) if secret is None: # no secret, can't validate log_debug(1, "Server id %s not found in database" % sid) return 0 return self.__validate_checksum(secret)
def authzOrg(self, info): # This function is a lot more complicated than it should be; the # corner case is pushes without a channel; we have to deny regular # users the ability to push to their org. # If the org id is not specified, default to the user's org id if not info.has_key("orgId"): info["orgId"] = self.org_id log_debug(4, "info[orgId]", info["orgId"], "org id", self.org_id) org_id = info["orgId"] if org_id == "": # Satellites are not allowwd to push in the null org raise rhnFault(4, _("You are not authorized to manage packages in the null org")) if org_id and self.org_id != org_id: # Not so fast... raise rhnFault(32, _("You are not allowed to manage packages in the %s org") % org_id) # Org admins and channel admins have full privileges; we could use # user_manages_channes, except for the case where there are no chanels if self.isOrgAdmin() or self.isChannelAdmin(): log_debug(4, "Org authorized (org_admin or channel_admin)") return # regular user at this point... check if the user manages any channels if user_manages_channels(self.user_id): log_debug(4, "Org authorized (user manages a channel)") return # ok, you're a regular user who doesn't manage any channels. # take a hike. raise rhnFault(32, _("You are not allowed to perform administrative tasks"))
def management_remove_channel(self, dict): log_debug(1) self._get_and_validate_session(dict) config_channel = dict.get('config_channel') # XXX Validate the namespace row = rhnSQL.fetchone_dict(self._query_config_channel_by_label, org_id=self.org_id, label=config_channel) if not row: raise rhnFault(4009, "Channel not found") delete_call = rhnSQL.Procedure('rhn_config.delete_channel') try: delete_call(row['id']) except rhnSQL.SQLError: e = sys.exc_info()[1] errno = e.args[0] if errno == 2292: raise_with_tb(rhnFault(4005, "Cannot remove non-empty channel %s" % config_channel, explain=0), sys.exc_info()[2]) raise log_debug(5, "Removed:", config_channel) rhnSQL.commit() return ""
def get_package_path(server_id, pkg_spec, channel): log_debug(3, server_id, pkg_spec, channel) if isinstance(pkg_spec, ListType): pkg = pkg_spec[:4] #Insert EPOCH pkg.insert(1, None) else: pkg = parseRPMFilename(pkg_spec) if pkg is None: log_debug(4, "Error", "Requested weird package", pkg_spec) raise rhnFault(17, _("Invalid RPM package %s requested") % pkg_spec) statement = """ select p.id, p.path path, pe.epoch epoch from rhnPackageArch pa, rhnChannelPackage cp, rhnPackage p, rhnPackageEVR pe, rhnServerChannel sc, rhnPackageName pn, rhnChannel c where 1=1 and c.label = :channel and pn.name = :name and sc.server_id = :server_id and pe.version = :ver and pe.release = :rel and c.id = sc.channel_id and c.id = cp.channel_id and pa.label = :arch and pn.id = p.name_id and p.id = cp.package_id and p.evr_id = pe.id and sc.channel_id = cp.channel_id and p.package_arch_id = pa.id """ h = rhnSQL.prepare(statement) pkg = map(str, pkg) h.execute(name = pkg[0], ver = pkg[2], rel = pkg[3], arch = pkg[4], channel = channel, server_id = server_id) rs = h.fetchall_dict() if not rs: log_debug(4, "Error", "Non-existant package requested", server_id, pkg_spec, channel) raise rhnFault(17, _("Invalid RPM package %s requested") % pkg_spec) # It is unlikely for this query to return more than one row, # but it is possible # (having two packages with the same n, v, r, a and different epoch in # the same channel is prohibited by the RPM naming scheme; but extra # care won't hurt) max_row = rs[0] for each in rs[1:]: # Compare the epoch as string if _none2emptyString(each['epoch']) > _none2emptyString(max_row['epoch']): max_row = each # Set the flag for the proxy download accelerator rhnFlags.set("Download-Accelerator-Path", max_row['path']) return check_package_file(max_row['path'], max_row['id'], pkg_spec), max_row['id']
def __init__(self, list_ifaces=None): log_debug(4, list_ifaces) self.ifaces = {} self.db_ifaces = [] # parameters which are not allowed to be empty and set to NULL self._autonull = ('address', 'netmask') self.sequence = "rhn_srv_net_iface_id_seq" if not list_ifaces: return for info in list_ifaces: if not isinstance(info, type({})): raise rhnFault(53, "Unexpected format for interface %s" % info) vdict = {} for key, mapping in self.key_mapping.items(): # Look at the mapping first; if not found, look for the key if info.has_key(mapping): k = mapping else: k = key if not info.has_key(k): raise rhnFault(53, "Unable to find required field %s" % (key)) val = info[k] if mapping in ['ip_addr', 'netmask', 'broadcast', 'address']: # bugzilla: 129840 kudzu (rhpl) will sometimes pad octets # with leading zeros, causing confusion; clean those up val = self.cleanse_ip_addr(val) vdict[mapping] = val self.ifaces[vdict['address']] = vdict
def _store_file(self, action_id, scap_file): r_dir = get_action_path(self.server.server['org_id'], self.server_id, action_id) if not r_dir: log_debug(1, self.server_id, "Error composing SCAP action directory path") raise rhnFault(5102) r_file = get_actionfile_path(self.server.server['org_id'], self.server_id, action_id, scap_file['filename']) if not r_file: log_debug(1, self.server_id, "Error composing SCAP action file path") raise rhnFault(5103) if not scap_file['content-encoding'] == 'base64': log_debug(1, self.server_id, "Invalid content encoding: %s" % scap_file['content-encoding']) raise rhnFault(5104) # Create the file on filer filecontent = decodestring(scap_file['filecontent']) # TODO assert for the size of the file absolute_dir = os.path.join(CFG.MOUNT_POINT, r_dir) absolute_file = os.path.join(absolute_dir, scap_file['filename']) if not os.path.exists(absolute_dir): log_debug(1, self.server_id, "Creating action directory: %s" % absolute_dir) os.makedirs(absolute_dir) mode = stat.S_IRWXU | stat.S_IRWXG | stat.S_IROTH | stat.S_IXOTH os.chmod(absolute_dir, mode) os.chmod(os.path.dirname(os.path.normpath(absolute_dir)), mode) log_debug(1, self.server_id, "Creating file: %s" % absolute_file) f = open(absolute_file, 'w+') f.write(filecontent) return {'result': True, }
def _repodata_taskomatic(self, file_name): log_debug(3, 'repodata', file_name) content_type = "application/x-gzip" if file_name in ["repomd.xml", "comps.xml"]: content_type = "text/xml" elif file_name not in ["primary.xml.gz", "other.xml.gz", "filelists.xml.gz", "updateinfo.xml.gz", "Packages.gz"]: log_debug(2, "Unknown repomd file requested: %s" % file_name) raise rhnFault(6) # XXX this won't be repconned or CDNd if file_name == "comps.xml": return self._repodata_python(file_name) file_path = "%s/%s/%s" % (CFG.REPOMD_PATH_PREFIX, self.channelName, file_name) rhnFlags.set('Content-Type', content_type) try: rhnFlags.set('Download-Accelerator-Path', file_path) return self._getFile(CFG.REPOMD_CACHE_MOUNT_POINT + "/" + file_path) except IOError, e: # For file not found, queue up a regen, and return 404 if e.errno == 2 and file_name != "comps.xml": taskomatic.add_to_repodata_queue(self.channelName, "repodata request", file_name, bypass_filters=True) rhnSQL.commit() # This returns 404 to the client raise rhnFault(6), None, sys.exc_info()[2] raise
def __processPackage(package, org_id, channels, source): log_debug(4, org_id, channels, source) if 'md5sum' in package: # for old rhnpush compatibility package['checksum_type'] = 'md5' package['checksum'] = package['md5sum'] del(package['md5sum']) if 'checksum' not in package: raise rhnFault(50, "The package's checksum digest has not been specified") if 'packageSize' not in package: raise rhnFault(50, "The package size has not been specified") header = rhn_rpm.headerLoad(package['header'].data) if not header: raise rhnFault(50) packageSize = package['packageSize'] relpath = package.get('relativePath') if 'header_start' in package: header_start = package['header_start'] else: header_start = 0 if 'header_end' in package: header_end = package['header_end'] else: # Just say the whole package header_end = packageSize checksum_type = package['checksum_type'] checksum = package['checksum'] p = createPackage(header, packageSize, checksum_type, checksum, relpath, org_id, header_start, header_end, channels) return p
def getSourcePackagePath(self, pkgFilename): """ OVERLOADS getSourcePackagePath in common/rhnRepository. snag src.rpm and nosrc.rpm from local repo, after ensuring we are authorized to fetch it. """ log_debug(3, pkgFilename) if pkgFilename[-8:] != '.src.rpm' and pkgFilename[-10:] != '.nosrc.rpm': raise rhnFault(17, _("Invalid SRPM package requested: %s") % pkgFilename) # Connect to the server to get an authorization for downloading this # package server = rpclib.Server(self.rhnParentXMLRPC, proxy=self.httpProxy, username=self.httpProxyUsername, password=self.httpProxyPassword) if self.caChain: server.add_trusted_cert(self.caChain) try: retval = server.proxy.package_source_in_channel( pkgFilename, self.channelName, self.clientInfo) except xmlrpclib.Fault, e: raise rhnFault(1000, _("Error retrieving source package: %s") % str(e)), None, sys.exc_info()[2]
def management_diff(self, dict): log_debug(1) self._get_and_validate_session(dict) param_names = ['config_channel_src', 'revision_src', 'path', ] for p in param_names: val = dict.get(p) if val is None: raise rhnFault(4007, "No content sent for `%s'" % p) log_debug(4, "Params sent", dict) path = dict['path'] config_channel_src = dict['config_channel_src'] revision_src = dict.get('revision_src') fsrc = self._get_file_revision(config_channel_src, revision_src, path) config_channel_dst = dict.get('config_channel_dst') if config_channel_dst is None: config_channel_dst = config_channel_src revision_dst = dict.get('revision_dst') fdst = self._get_file_revision(config_channel_dst, revision_dst, path) if fsrc['label'] != fdst['label']: raise rhnFault(4017, "Path %s is a %s in channel %s while it is a %s in channel %s" % (path, fsrc['label'], config_channel_src, fdst['label'], config_channel_dst), explain=0) if fsrc['label'] == 'symlink': if (fsrc["symlink"] != fdst['symlink']) or self.__attributes_differ(fsrc, fdst): (first_row, second_row) = self.__header(path, fsrc, config_channel_src, fdst, config_channel_dst) first_row += ' target: %s' % fsrc["symlink"] second_row += ' target: %s' % fdst["symlink"] return first_row + "\n" + second_row + "\n" return "" diff = difflib.unified_diff( fsrc['file_content'], fdst['file_content'], path, path, fsrc['modified'], fdst['modified'], lineterm='') try: first_row = next(diff) except StopIteration: return "" if not first_row.startswith('---'): # Hmm, weird return first_row + '\n'.join(list(diff)) try: second_row = next(diff) except StopIteration: second_row = '' if not second_row.startswith('+++'): # Hmm, weird return second_row + '\n'.join(list(diff)) (first_row, second_row) = self.__header(path, fsrc, config_channel_src, fdst, config_channel_dst) return first_row + "\n" + second_row + '\n' + '\n'.join(list(diff))
def entitle(self, server_id, history, virt_type=None): """ Entitle a server according to the entitlements we have configured. """ log_debug(3, self.entitlements) entitle_server = rhnSQL.Procedure("rhn_entitlements.entitle_server") # TODO: entitle_server calls can_entitle_server, so we're doing this # twice for each successful call. Is it necessary for external error # handling or can we ditch it? can_entitle_server = rhnSQL.Function( "rhn_entitlements.can_entitle_server", rhnSQL.types.NUMBER()) can_ent = None history["entitlement"] = "" # Do a quick check to see if both virt entitlements are present. (i.e. # activation keys stacked together) If so, give preference to the more # powerful virtualization platform and remove the regular virt # entitlement from the list. found_virt = False found_virt_platform = False for entitlement in self.entitlements: if entitlement[0] == VIRT_ENT_LABEL: found_virt = True elif entitlement[0] == VIRT_PLATFORM_ENT_LABEL: found_virt_platform = True for entitlement in self.entitlements: if virt_type is not None and entitlement[0] in \ (VIRT_ENT_LABEL, VIRT_PLATFORM_ENT_LABEL): continue # If both virt entitlements are present, skip the least powerful: if found_virt and found_virt_platform and entitlement[0] == VIRT_ENT_LABEL: log_debug(1, "Virtualization and Virtualization Platform " + "entitlements both present.") log_debug(1, "Skipping Virtualization.") continue try: can_ent = can_entitle_server(server_id, entitlement[0]) except rhnSQL.SQLSchemaError, e: can_ent = 0 try: # bugzilla #160077, skip attempting to entitle if we cant if can_ent: entitle_server(server_id, entitlement[0]) except rhnSQL.SQLSchemaError, e: log_error("Token failed to entitle server", server_id, self.get_names(), entitlement[0], e.errmsg) if e.errno == 20220: # ORA-20220: (servergroup_max_members) - Server group membership # cannot exceed maximum membership raise rhnFault(91, _("Registration failed: RHN Software service entitlements exhausted: %s") % entitlement[0]), None, sys.exc_info()[2] # No idea what error may be here... raise rhnFault(90, e.errmsg), None, sys.exc_info()[2]
def __init__(self, dict=None): log_debug(4, dict) self.ifaces = {} self.db_ifaces = [] # parameters which are not allowed to be empty and set to NULL self._autonull = ("hw_addr", "module") if not dict: return for name, info in dict.items(): if name == "class": # Ignore it continue if not isinstance(info, type({})): raise rhnFault(53, "Unexpected format for interface %s" % name) vdict = {} for key, mapping in self.key_mapping.items(): # Look at the mapping first; if not found, look for the key if mapping in info: k = mapping else: k = key if k not in info: raise rhnFault(53, "Unable to find required field %s" % key) val = info[k] vdict[mapping] = val if "ipaddr" in info and info["ipaddr"]: vdict["ipv4"] = NetIfaceAddress4( [{"ipaddr": info["ipaddr"], "broadcast": info["broadcast"], "netmask": info["netmask"]}] ) if "ipv6" in info and info["ipv6"]: vdict["ipv6"] = NetIfaceAddress6(info["ipv6"]) self.ifaces[name] = vdict
def validate_new_password(password): """ Perform all the checks required for new passwords """ log_debug(3, "Entered validate_new_password") # # We're copying the code because we don't want to # invalidate any of the existing passwords. # # Validate password based on configurable length # regular expression if not password: raise rhnFault(12) if len(password) < CFG.MIN_PASSWD_LEN: raise rhnFault(14, _("password must be at least %d characters") % CFG.MIN_PASSWD_LEN) if len(password) > CFG.MAX_PASSWD_LEN: raise rhnFault(701, _("Password must be shorter than %d characters") % CFG.MAX_PASSWD_LEN) password = password[:CFG.MAX_PASSWD_LEN] invalid_re = re.compile( r"[^ A-Za-z0-9`!@#$%^&*()-_=+[{\]}\\|;:'\",<.>/?~]") asterisks_re = re.compile(r"^\**$") # make sure the password isn't all *'s tmp = asterisks_re.match(password) if tmp is not None: raise rhnFault(15, "password cannot be all asterisks '*'") # make sure we have only printable characters tmp = invalid_re.search(password) if tmp is not None: pos = tmp.regs[0] raise rhnFault(15, _("password contains character `%s'") % password[pos[1] - 1])
def _get_file_revision(self, config_channel, revision, path): if revision and not revision.isdigit(): raise rhnFault(4016, "Invalid revision number '%s' specified for path %s " "in channel %s" % (revision, path, config_channel), explain=0) f = self._get_file(config_channel, path, revision=revision) if not f: raise rhnFault(4011, "File %s (revision %s) does not exist " "in channel %s" % (path, revision, config_channel), explain=0) if f['label'] == 'file' and f['is_binary'] == 'Y': raise rhnFault(4004, "File %s (revision %s) seems to contain " "binary data" % (path, revision), explain=0) # We have to read the contents of the first file here, because the LOB # object is tied to a cursor; if we re-execute the cursor, the LOB # seems to be invalid (bug 151220) # Empty files or directories may have NULL instead of lobs fc_lob = f.get('file_contents') if fc_lob: f['file_content'] = rhnSQL.read_lob(fc_lob).splitlines() else: f['file_content'] = '' return f
def _get_item_id(self, prefix, name, errnum, errmsg): prefix_len = len(prefix) if name[:prefix_len] != prefix: raise rhnFault(errnum, errmsg % name) try: id = int(name[prefix_len:]) except ValueError: raise rhnFault(errnum, errmsg % name), None, sys.exc_info()[2] return id
def validate_system_input(self, data): """ check the input data """ if not hash_validate(data, "os_release", "architecture", "profile_name"): log_error("Incomplete data hash") raise rhnFault(21, _("Required data missing")) # we require either a username and a password or a token if not hash_validate(data, "username", "password") and \ not hash_validate(data, "token"): raise rhnFault(21, _("Required members missing"))
def _get_item_id(prefix, name, errnum, errmsg): prefix_len = len(prefix) if name[:prefix_len] != prefix: raise rhnFault(errnum, errmsg % name) try: uuid = int(name[prefix_len:]) except ValueError: raise_with_tb(rhnFault(errnum, errmsg % name), sys.exc_info()[2]) return uuid
def __new_user_db(username, password, email, org_id, org_password): encrypted_password = CFG.encrypted_passwords log_debug(3, username, email, encrypted_password) # now search it in the database h = rhnSQL.prepare(""" select w.id, w.password, ui.use_pam_authentication from web_contact w, rhnUserInfo ui where w.login_uc = upper(:username) and w.id = ui.user_id """) h.execute(username=username) data = h.fetchone_dict() pre_existing_user = 0 if not data: # the username is not there, check the reserved user table h = rhnSQL.prepare(""" select login, password from rhnUserReserved where login_uc = upper(:username) """) h.execute(username=username) data = h.fetchone_dict() if not data: # nope, not reserved either raise rhnFault(1, _("Username `%s' has not been reserved") % username) else: pre_existing_user = 1 if not pre_existing_user and not email: # New accounts have to specify an e-mail address raise rhnFault(30, _("E-mail address not specified")) # we have to perform PAM authentication if data has a field called # 'use_pam_authentication' and its value is 'Y', and we do have a PAM # service set in the config file. # Note that if the user is only reserved we don't do PAM authentication if data.get('use_pam_authentication') == 'Y' and CFG.pam_auth_service: # Check the password with PAM import rhnAuthPAM if rhnAuthPAM.check_password(username, password, CFG.pam_auth_service) <= 0: # Bad password raise rhnFault(2) # We don't care about the password anymore, replace it with something import time password = '******' % time.time() else: # Regular authentication if check_password(password, data["password"]) == 0: # Bad password raise rhnFault(2) # creation of user was never supported in spacewalk but this call was mis-used # to check username/password in the past # so let's skip other checks and return now return 0
def _normalize_packages(self, system_id, packages, allow_none=0): """ the function checks if list of packages is well formated and also converts packages from old list of lists (extended_profile >= 2) to new list of dicts (extended_profile = 2) """ if allow_none and packages is None: return None # we need to be paranoid about the format of the argument because # if we accept wrong input then we might end up disposing in error # of all packages registered here if type(packages) != type([]): log_error("Invalid argument type", type(packages)) raise rhnFault(21) # Update the capabilities list server = self.auth_system(system_id) rhnCapability.update_client_capabilities(self.server_id) # old clients send packages as a list of arrays # while new (capability packages.extended_profile >= {version: 2, value: 1}) # use a list of dicts client_caps = rhnCapability.get_client_capabilities() package_is_dict = 0 packagesV2 = [] if client_caps and client_caps.has_key('packages.extended_profile'): cap_info = client_caps['packages.extended_profile'] if cap_info and int(cap_info['version']) >= 2: package_is_dict = 1 packagesV2 = packages for package in packages: if package_is_dict: # extended_profile >= 2 if type(package) != type({}): log_error("Invalid package spec for extended_profile >= 2", type(package), "len = %d" % len(package)) raise rhnFault(21) else: # extended_profile < 2 if (type(package) != type([]) or len(package) < 4): log_error("Invalid package spec", type(package), "len = %d" % len(package)) raise rhnFault(21) else: p = {'name' : package[0], 'version': package[1], 'release': package[2], 'epoch' : package[3], } if len(package) > 4: p['arch'] = package[4] if len(package) > 5: p['cookie'] = package[5] packagesV2.append(p) return packagesV2
def auth_system(self): if CFG.DISABLE_ISS: raise rhnFault(2005, _('ISS is disabled on this satellite.')) if not rhnSQL.fetchone_dict("select 1 from rhnISSSlave where slave = :hostname and enabled = 'Y'", hostname=idn_puny_to_unicode(self.remote_hostname)): raise rhnFault(2004, _('Server "%s" is not enabled for ISS.') % self.remote_hostname) return self.remote_hostname
def headerParserHandler(self, req): ret = basePackageUpload.BasePackageUpload.headerParserHandler(self, req) # Optional headers maps = [['Null-Org', 'null_org'], ['Packaging', 'packaging']] for hn, sn in maps: header_name = "%s-%s" % (self.header_prefix, hn) if req.headers_in.has_key(header_name): setattr(self, sn, req.headers_in[header_name]) if ret != apache.OK: return ret if CFG.SEND_MESSAGE_TO_ALL: rhnSQL.closeDB() log_debug(1, "send_message_to_all is set") rhnFlags.set("apache-return-code", apache.HTTP_NOT_FOUND) try: outage_message = open(CFG.MESSAGE_TO_ALL).read() except IOError: log_error("Missing outage message file") outage_message = "Outage mode" raise rhnFault(20001, outage_message, explain=0) # Init the database connection rhnSQL.initDB() use_session = 0 if self.field_data.has_key('Auth-Session'): session_token = self.field_data['Auth-Session'] use_session = 1 else: encoded_auth_token = self.field_data['Auth'] if not use_session: auth_token = self.get_auth_token(encoded_auth_token) if len(auth_token) < 2: log_debug(3, auth_token) raise rhnFault(105, "Unable to autenticate") self.username, self.password = auth_token[:2] force = self.field_data['Force'] force = int(force) log_debug(1, "Username", self.username, "Force", force) if use_session: self.org_id, self.force = rhnPackageUpload.authenticate_session(session_token, force=force, null_org=self.null_org) else: # We don't push to any channels self.org_id, self.force = rhnPackageUpload.authenticate(self.username, self.password, force=force, null_org=self.null_org) return apache.OK
def check_package_file(rel_path, logpkg, raisepkg): if rel_path is None: log_error("Package path null for package id", logpkg) raise rhnFault(17, _("Invalid RPM package %s requested") % raisepkg) filePath = "%s/%s" % (CFG.MOUNT_POINT, rel_path) if not os.access(filePath, os.R_OK): # Package not found on the filesystem log_error("Package not found", filePath) raise rhnFault(17, _("Package not found")) return filePath
def auth_username_password(username, password): # hrm. it'd be nice to move importlib.userAuth stuff here user = search(username) if not user: raise rhnFault(2, _("Invalid username/password combination")) if not user.check_password(password): raise rhnFault(2, _("Invalid username/password combination")) return user
def _validate_channels(self, channel_labels=None): log_debug(4) # Sanity check if channel_labels: if not isinstance(channel_labels, ListType): raise rhnFault(3000, "Expected list of channels, got %s" % type(channel_labels)) h = self.get_channels_statement() h.execute() # Hash the list of all available channels based on the label all_channels_hash = {} while 1: row = h.fetchone_dict() if not row: break all_channels_hash[row['label']] = row # Intersect the list of channels they've sent to us iss_slave_sha256_capable = (float(rhnFlags.get('X-RHN-Satellite-XML-Dump-Version')) >= constants.SHA256_SUPPORTED_VERSION) if not channel_labels: channels = all_channels_hash else: channels = {} for label in channel_labels: if label not in all_channels_hash: raise rhnFault(3001, "Could not retrieve channel %s" % label) if not (iss_slave_sha256_capable or all_channels_hash[label]['checksum_type'] in [None, 'sha1']): raise rhnFault(3001, ("Channel %s has incompatible rpm checksum (%s). Please contact\n" + "Red Hat support for information about upgrade to newer version\n" + "of Satellite Server which supports it.") % (label, all_channels_hash[label]['checksum_type'])) channels[label] = all_channels_hash[label] return channels
def _serverCommo(self): """ Handler part 2 Server (or next proxy) communication. """ log_debug(1) # Copy the method from the original request, and use the # handler for this server # We add path_info to the put (GET, CONNECT, HEAD, PUT, POST) request. log_debug(2, self.req.method, self.uri) self.responseContext.getConnection().putrequest(self.req.method, self.uri) # Send the headers, the body and expect a response try: status, headers, bodyFd = self._proxy2server() self.responseContext.setHeaders(headers) self.responseContext.setBodyFd(bodyFd) except IOError: # Raised by HTTP*Connection.getresponse # Server closed connection on us, no need to mail out # XXX: why are we not mailing this out??? Traceback("SharedHandler._serverCommo", self.req, mail=0) raise_with_tb(rhnFault(1000, _( "SUSE Manager Proxy error: connection with the SUSE Manager server failed")), sys.exc_info()[2]) except socket.error: # pylint: disable=duplicate-except # maybe self.req.read() failed? Traceback("SharedHandler._serverCommo", self.req) raise_with_tb(rhnFault(1000, _( "SUSE Manager Proxy error: connection with the SUSE Manager server failed")), sys.exc_info()[2]) log_debug(2, "HTTP status code (200 means all is well): %s" % status) # Now we need to decide how to deal with the server's response. We'll # defer to subclass-specific implementation here. The handler will # return apache.OK if the request was a success. return self._handleServerResponse(status)
def _repodata_taskomatic(self, file_name): log_debug(3, 'repodata', file_name) content_type = "application/x-gzip" if file_name in ["repomd.xml", "comps.xml", "products.xml"]: content_type = "text/xml" elif file_name in ["repomd.xml.asc", "repomd.xml.key"]: content_type = "text/plain" elif file_name not in [ "primary.xml.gz", "other.xml.gz", "filelists.xml.gz", "updateinfo.xml.gz", "Packages.gz", "modules.yaml", "InRelease", "Release", "Release.gpg", "susedata.xml.gz" ]: log_debug(2, "Unknown repomd file requested: %s" % file_name) raise rhnFault(6) # XXX this won't be repconned or CDNd if file_name in ["comps.xml", "modules.yaml"]: return self._repodata_python(file_name) file_path = "%s/%s/%s" % (CFG.REPOMD_PATH_PREFIX, self.channelName, file_name) rhnFlags.set('Content-Type', content_type) try: rhnFlags.set('Download-Accelerator-Path', file_path) return self._getFile(CFG.REPOMD_CACHE_MOUNT_POINT + "/" + file_path) except IOError: e = sys.exc_info()[1] # For file not found, queue up a regen, and return 404 if e.errno == 2 and file_name != "comps.xml" and file_name != "modules.yaml": taskomatic.add_to_repodata_queue(self.channelName, "repodata request", file_name, bypass_filters=True) rhnSQL.commit() # This returns 404 to the client raise_with_tb(rhnFault(6), sys.exc_info()[2]) raise
def parseRPMFilename(pkgFilename): """ IN: Package Name: xxx-yyy-ver.ver.ver-rel.rel_rel:e.ARCH.rpm (string) Understood rules: o Name can have nearly any char, but end in a - (well seperated by). Any character; may include - as well. o Version cannot have a -, but ends in one. o Release should be an actual number, and can't have any -'s. o Release can include the Epoch, e.g.: 2:4 (4 is the epoch) o Epoch: Can include anything except a - and the : seperator??? XXX: Is epoch info above correct? OUT: [n,e,v,r, arch]. """ if type(pkgFilename) != type(''): raise rhnFault(21, str(pkgFilename)) # Invalid arg. pkgFilename = os.path.basename(pkgFilename) # Check that this is a package NAME (with arch.rpm) and strip # that crap off. pkg = string.split(pkgFilename, '.') # 'rpm' at end? if string.lower(pkg[-1]) not in ['rpm', 'deb']: raise rhnFault( 21, 'neither an rpm nor a deb package name: %s' % pkgFilename) # Valid architecture next? if check_package_arch(pkg[-2]) is None: raise rhnFault(21, 'Incompatible architecture found: %s' % pkg[-2]) _arch = pkg[-2] # Nuke that arch.rpm. pkg = string.join(pkg[:-2], '.') ret = list(parseRPMName(pkg)) if ret: ret.append(_arch) return ret
def validate_new_password(password): """ Perform all the checks required for new passwords """ log_debug(3, "Entered validate_new_password") # # We're copying the code because we don't want to # invalidate any of the existing passwords. # # Validate password based on configurable length # regular expression if not password: raise rhnFault(12) if len(password) < CFG.MIN_PASSWD_LEN: raise rhnFault( 14, _("password must be at least %d characters") % CFG.MIN_PASSWD_LEN) if len(password) > CFG.MAX_PASSWD_LEN: raise rhnFault( 701, _("Password must be shorter than %d characters") % CFG.MAX_PASSWD_LEN) password = password[:CFG.MAX_PASSWD_LEN] invalid_re = re.compile( r"[^ A-Za-z0-9`!@#$%^&*()-_=+[{\]}\\|;:'\",<.>/?~]") asterisks_re = re.compile(r"^\**$") # make sure the password isn't all *'s tmp = asterisks_re.match(password) if tmp is not None: raise rhnFault(15, "password cannot be all asterisks '*'") # make sure we have only printable characters tmp = invalid_re.search(password) if tmp is not None: pos = tmp.regs[0] raise rhnFault( 15, _("password contains character `%s'") % password[pos[1] - 1])
def authzOrg(self, info): # This function is a lot more complicated than it should be; the # corner case is pushes without a channel; we have to deny regular # users the ability to push to their org. # If the org id is not specified, default to the user's org id if 'orgId' not in info: info['orgId'] = self.org_id log_debug(4, "info[orgId]", info['orgId'], "org id", self.org_id) org_id = info['orgId'] if org_id == '': # Satellites are not allowwd to push in the null org raise rhnFault(4, _("You are not authorized to manage packages in the null org")) if org_id and self.org_id != org_id: # Not so fast... raise rhnFault(32, _("You are not allowed to manage packages in the %s org") % org_id) # Org admins and channel admins have full privileges; we could use # user_manages_channes, except for the case where there are no chanels if self.isOrgAdmin() or self.isChannelAdmin(): log_debug(4, "Org authorized (org_admin or channel_admin)") return # regular user at this point... check if the user manages any channels if user_manages_channels(self.user_id): log_debug(4, "Org authorized (user manages a channel)") return # ok, you're a regular user who doesn't manage any channels. # take a hike. raise rhnFault(32, _("You are not allowed to perform administrative tasks"))
def get_package_path_by_filename(self, fileName, channel): log_debug(3, fileName, channel) fileName = str(fileName) n, e, v, r, a = rhnLib.parseRPMFilename(fileName) h = rhnSQL.prepare(self._query_get_package_path_by_nvra) h.execute(name=n, version=v, release=r, epoch=e, arch=a, channel=channel) try: return _get_path_from_cursor(h) except InvalidPackageError: log_debug(4, "Error", "Non-existent package requested", fileName) raise_with_tb(rhnFault(17, _("Invalid RPM package %s requested") % fileName), sys.exc_info()[2]) except NullPathPackageError: e = sys.exc_info()[1] package_id = e[0] log_error("Package path null for package id", package_id) raise_with_tb(rhnFault(17, _("Invalid RPM package %s requested") % fileName), sys.exc_info()[2]) except MissingPackageError: e = sys.exc_info()[1] filePath = e[0] log_error("Package not found", filePath) raise_with_tb(rhnFault(17, _("Package not found")), sys.exc_info()[2])
def get_repomd_file(self, channel, comps_type_id): comps_query = """ select relative_filename from rhnChannelComps where channel_id = ( select id from rhnChannel where label = :channel_label and comps_type_id = :ctype_id ) order by id desc """ channel_comps_sth = rhnSQL.prepare(comps_query) channel_comps_sth.execute(channel_label=channel, ctype_id=comps_type_id) row = channel_comps_sth.fetchone_dict() if not row: raise rhnFault(3015, "No comps/modules file for channel [%s]" % channel) path = os.path.join(CFG.MOUNT_POINT, row['relative_filename']) if not os.path.exists(path): log_error("Missing comps/modules file [%s] for channel [%s]" % (path, channel)) raise rhnFault(3016, "Unable to retrieve comps/modules file for channel [%s]" % channel) return self._send_stream(path)
def auth_system(self, system_id): log_debug(3) server = rhnServer.get(system_id, load_user=self.load_user) if not server: # Invalid server certificate. raise rhnFault(9, _("Please run rhn_register as root on this client")) self.server_id = server.getid() self.server = server # update the latest checkin time if self.update_checkin: server.checkin() # is the server entitled? if self.check_entitlement: entitlements = server.check_entitlement() if not entitlements: # we require entitlement for this functionality log_error("Server Not Entitled", self.server_id) raise rhnFault( 31, _('Service not enabled for system profile: "%s"') % server.server["name"]) # Kind of poking where we shouldn't, but what the hell if self.load_user and self.user is not None: self.user = server.user.username else: self.user = None if self.user is None: self.user = "" # Throttle users if necessary if self.throttle: server.throttle() # Set QOS if self.set_qos: server.set_qos() return server
def _authenticate(authobj, channels, null_org, force): params = {} if null_org: params['orgId'] = '' # XXX don't allow superusers to force stuff if force: raise rhnFault(4, "Cannot force push nullorg content", explain=0) if force and not CFG.FORCE_PACKAGE_UPLOAD: raise rhnFault(55, "Package Upload Failed", explain=0) authobj.authzOrg(params) if channels: authobj.authzChannels(channels) if null_org: org_id = None else: org_id = authobj.org_id return org_id, force
def push_file(self, config_channel_id, file): try: result = self._push_file(config_channel_id, file) except ConfigFilePathIncomplete: e = sys.exc_info()[1] raise rhnFault(4015, "Full path of file '%s' must be specified" % e.file.get('path'), explain=0).with_traceback(sys.exc_info()[2]) except ConfigFileExistsError: e = sys.exc_info()[1] raise rhnFault(4013, "File %s already uploaded" % e.file.get('path'), explain=0).with_traceback(sys.exc_info()[2]) except ConfigFileVersionMismatchError: e = sys.exc_info()[1] raise_with_tb( rhnFault(4012, "File %s uploaded with a different " "version" % e.file.get('path'), explain=0), sys.exc_info()[2]) except ConfigFileMissingDelimError: e = sys.exc_info()[1] raise_with_tb( rhnFault(4008, "Delimiter not specified for file %s" % e.file.get('path'), explain=0), sys.exc_info()[2]) except ConfigFileMissingContentError: e = sys.exc_info()[1] raise_with_tb( rhnFault(4007, "No content sent for file %s" % e.file.get('path'), explain=0), sys.exc_info()[2]) except ConfigFileExceedsQuota: e = sys.exc_info()[1] raise_with_tb( rhnFault(4014, "File size of %s exceeds free quota space" % e.file.get('path'), explain=0), sys.exc_info()[2]) except ConfigFileTooLargeError: e = sys.exc_info()[1] raise rhnFault(4003, "File size of %s larger than %s bytes" % (e.file.get('path'), self._get_maximum_file_size()), explain=0).with_traceback(sys.exc_info()[2]) rhnSQL.commit() return result
def session_reload(session_string): log_debug(4, session_string) session = rhnSession.load(session_string) web_user_id = session.uid if not web_user_id: raise rhnSession.InvalidSessionError("No user associated with session") u = User("", "") ret = u.reload(web_user_id) if ret != 0: # Something horked raise rhnFault(10) return u
def search(user): """ search the database for a user """ log_debug(3, user) userid = get_user_id(user) if not userid or is_user_disabled(user): # no user found or is disabled return None ret = User(user, "") if not ret.reload(userid) == 0: # something horked during reloading entry from database # we can not realy say that the entry does not exist... raise rhnFault(10) return ret
def auth_system(self, req): if CFG.DISABLE_ISS: raise rhnFault(2005, _('ISS is disabled on this satellite.')) remote_hostname = req.get_remote_host(apache.REMOTE_DOUBLE_REV) row = rhnSQL.fetchone_dict( """ select id, allow_all_orgs from rhnISSSlave where slave = :hostname and enabled = 'Y' """, hostname=idn_puny_to_unicode(remote_hostname)) if not row: raise rhnFault( 2004, _('Server "%s" is not enabled for ISS.') % remote_hostname) iss_slave_condition = "select id from web_customer" if not (row['allow_all_orgs'] == 'Y'): iss_slave_condition = "select rhnISSSlaveOrgs.org_id from rhnISSSlaveOrgs where slave_id = %d" % row[ 'id'] return iss_slave_condition
def getTinyUrlChannel(self, tinyurl, system_id): """ Gets channel information for this tinyurl""" log_debug(5, tinyurl) # authenticate that this request is initiated from a proxy self.auth_system(system_id) ret = rhnChannel.getChannelInfoForTinyUrl(tinyurl) if not ret or not 'url' in ret or len(ret['url'].split('/')) != 6: raise rhnFault( 40, "could not find any data on tiny url '%s'" % tinyurl) # tiny urls are always for kickstart sessions args = ret['url'].split('/') return self.__getKickstartSessionChannel(args[-1], args[-2])
def __processSystemid(self): """ update the systemid/serverid but only if they stat differently. returns 0=no updates made; or 1=updates were made """ if not os.access(ProxyAuth.__systemid_filename, os.R_OK): log_error("unable to access %s" % ProxyAuth.__systemid_filename) raise rhnFault( 1000, _("Spacewalk Proxy error (Spacewalk Proxy systemid has wrong permissions?). " "Please contact your system administrator.")) mtime = None try: mtime = os.stat(ProxyAuth.__systemid_filename)[-2] except IOError, e: log_error("unable to stat %s: %s" % (ProxyAuth.__systemid_filename, repr(e))) raise rhnFault( 1000, _("Spacewalk Proxy error (Spacewalk Proxy systemid has wrong permissions?). " "Please contact your system administrator.") ), None, sys.exc_info()[2]
def _connectToParent(self): """ Handler part 1 Should not return an error code -- simply connects. """ scheme, host, port, self.uri, query = self._parse_url(self.rhnParent) self.responseContext.setConnection(self._create_connection()) if not self.uri: self.uri = '/' # if this request is for an upstream server, use the original query string. # Otherwise, if it is for the local Squid instance, strip it so that # Squid will not keep multiple cached copies of the same resource if self.httpProxy not in ['127.0.0.1:8080', 'localhost:8080']: if 'X-Suse-Auth-Token' in self.req.headers_in: self.uri += '?%s' % self.req.headers_in['X-Suse-Auth-Token'] elif query: self.uri += '?%s' % query log_debug(3, 'Scheme:', scheme) log_debug(3, 'Host:', host) log_debug(3, 'Port:', port) log_debug(3, 'URI:', self.uri) log_debug(3, 'HTTP proxy:', self.httpProxy) log_debug(3, 'HTTP proxy username:'******'HTTP proxy password:'******'CA cert:', self.caChain) try: self.responseContext.getConnection().connect() except socket.error as e: log_error("Error opening connection", self.rhnParent, e) Traceback(mail=0) raise rhnFault(1000, _("SUSE Manager Proxy could not successfully connect its SUSE Manager parent. " "Please contact your system administrator.")), None, sys.exc_info()[2] # At this point the server should be okay log_debug(3, "Connected to parent: %s " % self.rhnParent) if self.httpProxy: if self.httpProxyUsername: log_debug(3, "HTTP proxy info: %s %s/<password>" % ( self.httpProxy, self.httpProxyUsername)) else: log_debug(3, "HTTP proxy info: %s" % self.httpProxy) else: log_debug(3, "HTTP proxy info: not using an HTTP proxy") peer = self.responseContext.getConnection().sock.getpeername() log_debug(4, "Other connection info: %s:%s%s" % (peer[0], peer[1], self.uri))
class ProxyAuth: __serverid = None __systemid = None __systemid_mtime = None __systemid_filename = UP2DATE_CONFIG['systemIdPath'] __nRetries = 3 # number of login retries hostname = None def __init__(self, hostname): log_debug(3) ProxyAuth.hostname = hostname self.__processSystemid() def __processSystemid(self): """ update the systemid/serverid but only if they stat differently. returns 0=no updates made; or 1=updates were made """ if not os.access(ProxyAuth.__systemid_filename, os.R_OK): log_error("unable to access %s" % ProxyAuth.__systemid_filename) raise rhnFault(1000, _("Spacewalk Proxy error (Spacewalk Proxy systemid has wrong permissions?). " "Please contact your system administrator.")) mtime = None try: mtime = os.stat(ProxyAuth.__systemid_filename)[-2] except IOError, e: log_error("unable to stat %s: %s" % (ProxyAuth.__systemid_filename, repr(e))) raise rhnFault(1000, _("Spacewalk Proxy error (Spacewalk Proxy systemid has wrong permissions?). " "Please contact your system administrator.")), None, sys.exc_info()[2] if not self.__systemid_mtime: ProxyAuth.__systemid_mtime = mtime if self.__systemid_mtime == mtime \ and self.__systemid and self.__serverid: # nothing to do return 0 # get systemid try: ProxyAuth.__systemid = open(ProxyAuth.__systemid_filename, 'r').read() except IOError, e: log_error("unable to read %s" % ProxyAuth.__systemid_filename) raise rhnFault(1000, _("Spacewalk Proxy error (Spacewalk Proxy systemid has wrong permissions?). " "Please contact your system administrator.")), None, sys.exc_info()[2]
def __init__(self, dict=None): log_debug(4, dict) self.ifaces = {} self.db_ifaces = [] # parameters which are not allowed to be empty and set to NULL self._autonull = ('hw_addr', 'module') if not dict: return for name, info in list(dict.items()): if name == 'class': # Ignore it continue if not isinstance(info, type({})): raise rhnFault(53, "Unexpected format for interface %s" % name) vdict = {} for key, mapping in list(self.key_mapping.items()): # Look at the mapping first; if not found, look for the key if mapping in info: k = mapping else: k = key if k not in info: raise rhnFault(53, "Unable to find required field %s" % key) val = info[k] vdict[mapping] = val if 'ipaddr' in info and info['ipaddr']: vdict['ipv4'] = NetIfaceAddress4([{ 'ipaddr': info['ipaddr'], 'broadcast': info['broadcast'], 'netmask': info['netmask'] }]) if 'ipv6' in info and info['ipv6']: vdict['ipv6'] = NetIfaceAddress6(info["ipv6"]) self.ifaces[name] = vdict
def __solveDep_prepare(self, system_id, deps, action, clientVersion): """ Response for clients: version 1: list version 2: hash """ log_debug(7, system_id, deps, action, clientVersion) faultString = _("Invalid value %s (%s)") if type(deps) not in (ListType, TupleType): log_error("Invalid argument type", type(deps)) raise rhnFault(30, faultString % (deps, type(deps))) for dep in deps: if type(dep) is not StringType: log_error("Invalid dependency member", type(dep)) raise rhnFault(30, faultString % (dep, type(dep))) # Ignore empty strings deps = list(filter(len, deps)) # anything left to do? if not deps: return [] # Authenticate the system certificate server = self.auth_system(action, system_id) log_debug(1, self.server_id, action, "items: %d" % len(deps)) return deps
def check_email(email): """ Do some minimal checks on the e-mail address """ if email is not None: email = email.strip() if not email: # Still supported return None if len(email) > CFG.MAX_EMAIL_LEN: raise rhnFault(100, _("Please limit your e-mail address to %s chars") % CFG.MAX_EMAIL_LEN) # XXX More to come (check the format is indeed [email protected] return email
def load_package(package_stream): if package_stream.name.endswith('.deb'): try: header, payload_stream = rhn_deb.load(filename=package_stream.name) except: raise_with_tb(rhnFault(50, "Unable to load package", explain=0), sys.exc_info()[2]) else: try: header, payload_stream = rhn_mpm.load(file=package_stream) except: raise_with_tb(rhnFault(50, "Unable to load package", explain=0), sys.exc_info()[2]) payload_stream.seek(0, 0) if header.packaging == "mpm" or header.packaging == "deb": header.header_start = header.header_end = 0 (header_start, header_end) = (0, 0) else: (header_start, header_end) = get_header_byte_range(payload_stream) payload_stream.seek(0, 0) return header, payload_stream, header_start, header_end
def management_remove_channel(self, dict): log_debug(1) self._get_and_validate_session(dict) config_channel = dict.get('config_channel') # XXX Validate the namespace row = rhnSQL.fetchone_dict(self._query_config_channel_by_label, org_id=self.org_id, label=config_channel) if not row: raise rhnFault(4009, "Channel not found") delete_call = rhnSQL.Procedure('rhn_config.delete_channel') try: delete_call(row['id']) except rhnSQL.SQLError, e: errno = e.args[0] if errno == 2292: raise rhnFault(4005, "Cannot remove non-empty channel %s" % config_channel, explain=0), None, sys.exc_info()[2] raise
def getUserGroups(login, password): # Authenticates a user and returns the list of groups it belongs # to, and the org id add_to_seclist(password) log_debug(4, login) user = rhnUser.search(login) if not user: log_debug("rhnUser.search failed") raise rhnFault(2) # Check the user's password if not user.check_password(password): log_debug("user.check_password failed") raise rhnFault(2) if rhnUser.is_user_disabled(username): msg = _(""" %s Account has been deactivated on this server. Please contact your Org administrator for more help.""") raise rhnFault(1, msg % username, explain=0) return getUserGroupsFromUserInstance(user)
def upload_result(self, system_id, action_id, scap_file): self.auth_system(system_id) self._authorize_request(action_id) required_keys = ['filename', 'filecontent', 'content-encoding'] for k in required_keys: if k not in scap_file: log_debug( 1, self.server_id, "The scap file data is invalid or incomplete: %s" % scap_file) raise rhnFault(5101, "Missing or invalid key: %s" % k) return self._store_file(action_id, scap_file)
def upgrade_version(self, system_id, newver): """ Upgrade a certificate's version to a different release. """ log_debug(5, system_id, newver) # we need to load the user because we will generate a new certificate self.load_user = 1 server = self.auth_system(system_id) newver = str(newver) if not newver: raise rhnFault(21, _("Invalid system release version requested")) #log the entry log_debug(1, server.getid(), newver) ret = server.change_base_channel(newver) server.save() return server.system_id()
def subscribeChannels(self, system_id, channelNames, username, passwd): """ Clients v2+ """ log_debug(5, system_id, channelNames, username, passwd) # Authenticate the system certificate self.auth_system('subscribeChannel', system_id) # log the entry log_debug(1, self.server_id, channelNames) server_lib.snapshot_server(self.server_id, 'Base Channel Updated') for channelName in channelNames: if NONSUBSCRIBABLE_CHANNELS.search(channelName): raise rhnFault(73, explain=False) else: rhnChannel.subscribe_channel(self.server_id, channelName, username, passwd) return 0
def listPackages(server, channel, version): """ Generates a list of objects by calling the function """ try: return server.listAllPackagesChecksum(channel, version) # pylint: disable=W0702 except: try: return server.listAllPackages(channel, version) except xmlrpclib.ProtocolError, e: errcode, errmsg = rpclib.reportError(e.headers) raise rhnFault( 1000, "SpacewalkProxy error (xmlrpclib.ProtocolError): " "errode=%s; errmsg=%s" % (errcode, errmsg)), None, sys.exc_info()[2]
def _get_method_params(self): # Returns the method name and params for this call # Split the request into parts array = self.req.path_info.split('/') if len(array) < 4: log_error("Invalid URI for GET request", self.req.path_info) raise rhnFault(21, _("Invalid URI %s" % self.req.path_info)) self.channel, method = (array[2], array[3]) if method == "getPackage": params = tuple([os.path.join(*array[4:])]) else: params = tuple(array[4:]) return method, params
def _handler(self, req): log_debug(3, "Method", req.method) # Read all the request data = req.read() log_debug(7, "Received", data) # Decode the data try: params, methodname = xmlrpclib.loads(data) except: raise log_debug(5, params, methodname) try: f = self.get_function(methodname, req) except FunctionRetrievalError: e = sys.exc_info()[1] Traceback(methodname, req) return self._send_xmlrpc(req, rhnFault(3008, str(e), explain=0)) if len(params) < 2: params = [] else: params = params[1:] result = f(*params) if result: # Error of some sort return self._send_xmlrpc(req, rhnFault(3009)) # Presumably the function did all the sending log_debug(4, "Exiting OK") return apache.OK