def __init__(self, db, seq): if not seq or type(seq) != type(""): raise rhnException("First argument needs to be a sequence name", seq) self.__seq = seq if not isinstance(db, sql_base.Database): raise rhnException("Argument db is not a database instance", db) self.__db = db
def select(self, row): if not type(row) == type({}) and not isinstance(row, UserDictCase): raise rhnException("Expecting hash argument. %s is invalid" % type(row), row) if row == {}: raise rhnException("The hash argument is empty", row) keys = row.keys() # Sort the list of keys, to always get the same list of arguments keys.sort() args = [] for col in keys: if row[col] in (None, ''): clause = "%s is null" % col else: clause = "%s = :%s" % (col, col) args.append(clause) sql = "select * from %s where " % self.__table cursor = self.__db.prepare(sql + string.join(args, " and ")) apply(cursor.execute, (), row) rows = cursor.fetchall_dict() if rows is None: return None # fill up the cache if self.__cache is not None: for row in rows: self.__cache[row[self.__hashid]] = row return map(lambda a: UserDictCase(a), rows)
def initDB(dsn=None, backend=None, host="localhost", port=None, username=None, password=None, database=None): """ Initialize the database. For Oracle connections: provide just a string dsn argument, or a username, password, and database. (sid in this case) """ if backend == None: backend=CFG.DB_BACKEND if not SUPPORTED_BACKENDS.has_key(backend): raise rhnException("Unsupported database backend", backend) if backend == ORACLE: # For Oracle, must provide either dsn or username, password, # and database. if not dsn and not (username and password and database): # Grab the default from the config file: dsn = CFG.DEFAULT_DB if dsn: # split the dsn up into username/pass/sid so we can call the rest of # the code in a uniform fashion for all database backends: (username, temp) = dsn.split("/") (password, database) = temp.split("@") if backend == POSTGRESQL: host = None port = None dsn = CFG.DEFAULT_DB (username, temp) = dsn.split("/") (password, dsn) = temp.split("@") for i in dsn.split(';'): (k, v) = i.split('=') if k == 'dbname': database = v elif k == 'host': host = v elif k == 'port': port = int(v) else: raise rhnException("Unknown piece in default_db string", i) # Hide the password add_to_seclist(dsn) try: __init__DB(backend, host, port, username, password, database) # except (rhnException, SQLError): # raise # pass on, we know those ones # except (KeyboardInterrupt, SystemExit): # raise except: raise #e_type, e_value = sys.exc_info()[:2] #raise rhnException("Could not initialize Oracle database connection", # str(e_type), str(e_value)) return 0
def __init__(self, db, table, hashid, cache = 0): if not table or not type(table) == type(""): raise rhnException("First argument needs to be a table name", table) self.__table = table if not hashid or not type(hashid) == type(""): raise rhnException("Second argument needs to be the name of the unique index column", hashid) self.__hashid = hashid if not isinstance(db, sql_base.Database): raise rhnException("Argument db is not a database instance", db) self.__db = db self.__cache = None if cache: self.__cache = {}
def reload(self, server, reload_all = 0): log_debug(4, server, "reload_all = %d" % reload_all) if not self.server.load(int(server)): log_error("Could not find server record for reload", server) raise rhnFault(29, "Could not find server record in the database") self.cert = None # it is lame that we have to do this h = rhnSQL.prepare(""" select label from rhnServerArch where id = :archid """) h.execute(archid = self.server["server_arch_id"]) data = h.fetchone_dict() if not data: raise rhnException("Found server with invalid numeric " "architecture reference", self.server.data) self.archname = data['label'] # we don't know this one anymore (well, we could look for, but # why would we do that?) self.user = None # XXX: Fix me if reload_all: if not self.reload_packages_byid(self.server["id"]) == 0: return -1 if not self.reload_hardware_byid(self.server["id"]) == 0: return -1 return 0
def _push_config_file(self, file): config_info_query = self._query_lookup_non_symlink_config_info if self._is_link(file) and file.get("symlink"): config_info_query = self._query_lookup_symlink_config_info # Look up the config info first h = rhnSQL.prepare(config_info_query) apply(h.execute, (), file) row = h.fetchone_dict() if not row: # Hmm raise rhnException("This query should always return a row") config_info_id = row['id'] file['config_info_id'] = config_info_id # Look up the config file itself h = rhnSQL.prepare(self._query_lookup_config_file) apply(h.execute, (), file) row = h.fetchone_dict() if row: # Yay we already have this file # Later down the road, we're going to update modified for this # table file['config_file_id'] = row['id'] return # Have to insert this config file, gotta use the api to keep quotas up2date... #h = rhnSQL.prepare(self._query_insert_config_file) #apply(h.execute, (), file) insert_call = rhnSQL.Function("rhn_config.insert_file", rhnSQL.types.NUMBER()) file['config_file_id'] = insert_call(file['config_channel_id'], file['path'])
def update_kickstart_session(server_id, action_id, action_status, kickstart_state, next_action_type): log_debug(3, server_id, action_id, action_status, kickstart_state, next_action_type) # Is this a kickstart-related action? ks_session_id = get_kickstart_session_id(server_id, action_id) if ks_session_id is None: # Nothing more to do log_debug(4, "Kickstart session not found") return None # Check the current action state if action_status == 2: # Completed ks_status = kickstart_state # Get the next action - it has to be of the right type next_action_id = get_next_action_id(action_id, next_action_type) elif action_status == 3: # Failed ks_status = 'failed' next_action_id = None else: raise rhnException("Invalid action state %s" % action_status) update_ks_session_table(ks_session_id, ks_status, next_action_id, server_id) return ks_session_id
def check_password(self, password): good_pwd = str(self.contact["password"]) old_pwd = str(self.contact["old_password"]) if CFG.pam_auth_service: # a PAM service is defined # We have to check the user's rhnUserInfo.use_pam_authentication # XXX Should we create yet another __init_blah function? # since it's the first time we had to lool at rhnUserInfo, # I'll assume it's not something to happen very frequently, # so I'll use a query for now # - misa # h = rhnSQL.prepare(""" select ui.use_pam_authentication from web_contact w, rhnUserInfo ui where w.login_uc = UPPER(:login) and w.id = ui.user_id""") h.execute(login=self.contact["login"]) data = h.fetchone_dict() if not data: # This should not happen raise rhnException("No entry found for user %s" % self.contact["login"]) if data['use_pam_authentication'] == 'Y': # use PAM import rhnAuthPAM return rhnAuthPAM.check_password(self.contact["login"], password, CFG.pam_auth_service) # If the entry in rhnUserInfo is 'N', perform regular # authentication return check_password(password, good_pwd, old_pwd)
def __create_server_group(group_label, org_id, maxnum = ''): # Add this new server to the pending group h = rhnSQL.prepare(""" select sg.id, sg.current_members from rhnServerGroup sg where sg.group_type = ( select id from rhnServerGroupType where label = :group_label ) and sg.org_id = :org_id """) h.execute(org_id = org_id, group_label = group_label) data = h.fetchone_dict() if not data: # create the requested group ret_id = rhnSQL.Sequence("rhn_server_group_id_seq")() h = rhnSQL.prepare(""" insert into rhnServerGroup ( id, name, description, max_members, group_type, org_id) select :new_id, sgt.name, sgt.name, :maxnum, sgt.id, :org_id from rhnServerGroupType sgt where sgt.label = :group_label """) rownum = h.execute(new_id = ret_id, org_id = org_id, group_label = group_label, maxnum = str(maxnum)) if rownum == 0: # No rows were created, probably invalid label raise rhnException("Could not create new group for org=`%s'" % org_id, group_label) else: ret_id = data["id"] return ret_id
def get_kickstart_session_info(kickstart_session_id, server_id): h = rhnSQL.prepare(_query_get_kickstart_session_info) h.execute(kickstart_session_id=kickstart_session_id) row = h.fetchone_dict() if not row: raise rhnException("Could not fetch kickstart session id %s " "for server %s" % (kickstart_session_id, server_id)) return row
def configure(serverId, actionId, dry_run=0): log_debug(3, dry_run) h = rhnSQL.prepare(_query_lookup_interval) h.execute(action_id=actionId) row = h.fetchone_dict() if not row: raise rhnException("rhnsd reconfig action scheduled, but no entries " "in rhnActionDaemonConfig found") # Format: (interval, restart) return (row['interval'], row['restart'])
def insert(self, rows): # insert a single row into the table def insert_row(row, self = self): if self.__cache is not None: self.__cache[row[self.__hashid]] = row return self.__setitem__(None, row) if type(rows) == type({}) or isinstance(rows, UserDictCase): return insert_row(rows) if type(rows) == type([]): for x in rows: insert_row(x) return None raise rhnException("Invalid data %s passed" % type(rows), rows)
def reload(self, user_id): log_debug(3, user_id) # If we can not load these we have a fatal condition if not self.contact.load(user_id): raise rhnException("Could not find contact record for id", user_id) if not self.customer.load(self.contact["org_id"]): raise rhnException("Could not find org record", "user_id = %s" % user_id, "org_id = %s" % self.contact["org_id"]) # These other ones are non fatal because we can create dummy records if not self.info.load(user_id): self.__init_info() if not self.perms.load(user_id): self.__init_perms() # The site info is trickier, we need to find it first if not self.site.load_sql("web_user_id = :userid and type = 'M'", { "userid" : user_id }): self.__init_site() # Fix the username self.username = self.contact['login'] return 0
def __init__(self, db, table, hashname, hashval = None): UserDictCase.__init__(self) if not isinstance(db, sql_base.Database): raise rhnException("Argument db is not a database instance", db) self.db = db self.table = table self.hashname = string.lower(hashname) # and the data dictionary self.data = {} # is this a real entry (ie, use insert or update) self.real = 0 if hashval is not None: # if we have to load an entry already... self.load(hashval)
def handler(self, req): """ main Apache handler """ log_debug(2) ret = apacheSession.handler(self, req) if ret != apache.OK: return ret if not CFG.SEND_MESSAGE_TO_ALL: # Need to get any string template overrides here, before any app # code gets executed, as the rhnFault error messages use the # templates # If send_message_to_all, we don't have DB connectivity though h = rhnSQL.prepare("select label, value from rhnTemplateString") h.execute() templateStrings = {} while 1: row = h.fetchone_dict() if not row: break templateStrings[row['label']] = row['value'] if templateStrings: rhnFlags.set('templateOverrides', templateStrings) log_debug(4, "template strings: %s" % templateStrings) if not CFG.SECRET_KEY: # Secret key not defined, complain loudly try: raise rhnException("Secret key not found!") except: rhnTB.Traceback(mail=1, req=req, severity="schema") req.status = 500 req.send_http_header() return apache.OK # Try to authenticate the proxy if it this request passed # through a proxy. if self.proxyVersion: try: ret = self._req_processor.auth_proxy() except rhnFault, f: return self._req_processor.response(f.getxml())
def _prepHandler(self): """ Handler part 0 """ # Just to be on the safe side if self.req.main: # A subrequest return apache.DECLINE log_debug(4, rhnFlags.all()) if not self.rhnParent: raise rhnException("Oops, no proxy parent! Exiting") # Copy the headers. rhnFlags.get('outputTransportOptions').clear() rhnFlags.get('outputTransportOptions').update(self._getHeaders(self.req)) return apache.OK
def _check_token_limits(server_id, token_rec): token_id = token_rec["token_id"] # Mark that we used this token server_used_token(server_id, token_id) # now check we're not using this token too much h = rhnSQL.prepare(_query_check_token_limits) h.execute(token_id = token_id) ret = h.fetchone_dict() if not ret: raise rhnException("Could not check usage limits for token", server_id, token_rec) # See bug #79095: if usage_limit is NULL, it means unlimited reg tokens if ret["max_nr"] is not None and ret["max_nr"] < ret["curr_nr"]: log_error("Token usage limit exceeded", token_rec, ret["max_nr"], server_id) raise rhnFault(61, _("Maximum usage count of %s reached") % ret["max_nr"]) # all clean, we're below usage limits return 0
def _validate_version(self, req): server_version = constants.PROTOCOL_VERSION vstr = "X-RHN-Satellite-XML-Dump-Version" if not req.headers_in.has_key(vstr): raise rhnFault(3010, "Missing version string") client_version = req.headers_in[vstr] # set the client version through rhnFlags to access later rhnFlags.set("X-RHN-Satellite-XML-Dump-Version", client_version) log_debug(1, "Server version", server_version, "Client version", client_version) client_ver_arr = str(client_version).split(".") server_ver_arr = str(server_version).split(".") client_major = client_ver_arr[0] server_major = server_ver_arr[0] if len(client_ver_arr) >= 2: client_minor = client_ver_arr[1] else: client_minor = 0 server_minor = server_ver_arr[1] try: client_major = int(client_major) client_minor = int(client_minor) except ValueError: raise rhnFault(3011, "Invalid version string %s" % client_version) try: server_major = int(server_major) server_minor = int(server_minor) except ValueError: raise rhnException("Invalid server version string %s" % server_version) if client_major != server_major: raise rhnFault( 3012, "Client version %s does not match" " server version %s" % (client_version, server_version), explain=0, )
def join_groups(self): """ For a new server, join server groups """ # Sanity check - we should always have a user if not self.user: raise rhnException("User not specified") server_id = self.getid() user_id = self.user.getid() h = rhnSQL.prepare(""" select system_group_id from rhnUserDefaultSystemGroups where user_id = :user_id """) h.execute(user_id=user_id) while 1: row = h.fetchone_dict() if not row: break server_group_id = row['system_group_id'] log_debug(5, "Subscribing server to group %s" % server_group_id) server_lib.join_server_group(server_id, server_group_id)
return None return resp def check_password(username, password, service): global __username, __password auth = PAM.pam() auth.start(service, username, __pam_conv) # Save the username and passwords in the globals, the conversation # function needs access to them __username = username __password = password try: try: auth.authenticate() auth.acct_mgmt() finally: # Something to be always executed - cleanup __username = __password = None except PAM.error, e: resp, code = e.args[:2] log_error("Password check failed (%s): %s" % (code, resp)) return 0 except: raise rhnException('Internal PAM error') else: # Good password return 1
def change_base_channel(self, new_rel): log_debug(3, self.server["id"], new_rel) old_rel = self.server["release"] # test noops if old_rel == new_rel: return 1 current_channels = rhnChannel.channels_for_server(self.server["id"]) # Extract the base channel off of old_base = filter(lambda x: not x['parent_channel'], current_channels) # Quick sanity check base_channels_count = len(old_base) if base_channels_count == 1: old_base = old_base[0] elif base_channels_count == 0: old_base = None else: raise rhnException("Server %s subscribed to multiple base channels" % (self.server["id"], )) #bz 442355 #Leave custom base channels alone, don't alter any of the channel subscriptions if not CFG.RESET_BASE_CHANNEL and rhnChannel.isCustomChannel(old_base["id"]): log_debug(3, "Custom base channel detected, will not alter channel subscriptions") self.server["release"] = new_rel self.server.save() msg = """The Red Hat Network Update Agent has detected a change in the base version of the operating system running on your system, additionaly you are subscribed to a custom channel as your base channel. Due to this configuration your channel subscriptions will not be altered. """ self.add_history("Updated system release from %s to %s" % ( old_rel, new_rel), msg) self.save_history_byid(self.server["id"]) return 1 s = rhnChannel.LiteServer().init_from_server(self) s.release = new_rel s.arch = self.archname # Let get_server_channels deal with the errors and raise rhnFault target_channels = rhnChannel.guess_channels_for_server(s) target_base = filter(lambda x: not x['parent_channel'], target_channels)[0] channels_to_subscribe = [] channels_to_unsubscribe = [] if old_base and old_base['id'] == target_base['id']: # Same base channel. Preserve the currently subscribed child # channels, just add the ones that are missing hash = {} for c in current_channels: hash[c['id']] = c for c in target_channels: channel_id = c['id'] if hash.has_key(channel_id): # Already subscribed to this one del hash[channel_id] continue # Have to subscribe to this one channels_to_subscribe.append(c) # We don't want to lose subscriptions to prior channels, so don't # do anything with hash.values() else: # Different base channel channels_to_unsubscribe = current_channels channels_to_subscribe = target_channels rhnSQL.transaction("change_base_channel") self.server["release"] = new_rel self.server.save() if not (channels_to_subscribe or channels_to_unsubscribe): # Nothing to do, just add the history entry self.add_history("Updated system release from %s to %s" % ( old_rel, new_rel)) self.save_history_byid(self.server["id"]) return 1 # XXX: need a way to preserve existing subscriptions to # families so we can restore access to non-public ones. rhnChannel.unsubscribe_channels(self.server["id"], channels_to_unsubscribe) rhnChannel.subscribe_channels(self.server["id"], channels_to_subscribe) # now that we changed, recompute the errata cache for this one rhnSQL.Procedure("queue_server")(self.server["id"]) # Make a history note sub_channels = rhnChannel.channels_for_server(self.server["id"]) if sub_channels: channel_list = map(lambda a: a["name"], sub_channels) msg = """The Red Hat Network Update Agent has detected a change in the base version of the operating system running on your system and has updated your channel subscriptions to reflect that. Your server has been automatically subscribed to the following channels:\n%s\n""" % (string.join(channel_list, "\n"),) else: msg = """*** ERROR: *** While trying to subscribe this server to software channels: There are no channels serving release %s""" % new_rel self.add_history("Updated system release from %s to %s" % ( old_rel, new_rel), msg) self.save_history_byid(self.server["id"]) return 1
def set_org_id(self, org_id): if not org_id: raise rhnException("Invalid org_id requested for user", org_id) self.contact["org_id"] = int(org_id) self.customer.load(int(org_id))
def _push_contents(self, file): checksum_type = 'md5' # FIXME: this should be configuration option file['file_size'] = 0 file['is_binary'] = 'N' file_path = file.get('path') file_contents = file.get('file_contents') or '' if file.has_key('enc64') and file_contents: file_contents = base64.decodestring(file_contents) if not file.has_key('config_file_type_id'): log_debug(4, "Client does not support config directories, so set file_type_id to 1") file['config_file_type_id'] = '1' file['checksum_type'] = checksum_type file['checksum'] = getStringChecksum(checksum_type, file_contents or '') if file_contents: file['file_size'] = len(file_contents) if file['file_size'] > self._get_maximum_file_size(): raise ConfigFileTooLargeError(file_path, file['file_size']) # Is the content binary data? # XXX We may need a heuristic; this is what the web site does, and we # have to be consistent # XXX Yes this is iterating over a string for c in file_contents: if ord(c) > 127: file['is_binary'] = 'Y' break h = rhnSQL.prepare(self._query_content_lookup) apply(h.execute, (), file) row = h.fetchone_dict() if row: db_contents = rhnSQL.read_lob(row['contents']) or '' if file_contents == db_contents: # Same content file['config_content_id'] = row['id'] log_debug(5, "same content") return # We have to insert a new file now content_seq = rhnSQL.Sequence('rhn_confcontent_id_seq') config_content_id = content_seq.next() file['config_content_id'] = config_content_id if file_contents: h = rhnSQL.prepare(self._query_insert_content) else: h = rhnSQL.prepare(self._query_insert_null_content) apply(h.execute, (), file) # Row should be there now h = rhnSQL.prepare(self._query_get_content_row) apply(h.execute, (), file) row = h.fetchone_dict() if not row: # Ouch raise rhnException("Row should have been inserted but it's not") if file_contents: log_debug(5, "writing file contents to blob") lob = row['contents'] lob.write(file_contents)
def __save(self): is_admin = 0 if self.customer.real: # get the org_id and the applicant group id for this org org_id = self.customer["id"] h = rhnSQL.prepare(""" select ug.id from rhnUserGroup ug, rhnUserGroupType ugt where ugt.label = 'org_applicant' and ug.group_type = ugt.id and ug.org_id = :org_id """) h.execute(org_id=org_id) data = h.fetchone_dict() # XXX: prone to errors, but we'll need to see them first grp_id = data["id"] else: # an org does not exist... create one create_new_org = rhnSQL.Procedure("create_new_org") ret = create_new_org( self.customer["name"], self.customer["password"], None, None, "B", rhnSQL.types.NUMBER(), rhnSQL.types.NUMBER(), rhnSQL.types.NUMBER(), ) org_id, adm_grp_id, app_grp_id = ret[-3:] # We want to make sure we set the group limits right tbl = rhnSQL.Row("rhnUserGroup", "id") # Set the default admin limits to Null tbl.load(adm_grp_id) # bz:210230: this value should default to Null tbl.save() # Set the default applicats limit to 0 tbl.load(app_grp_id) tbl["max_members"] = 0 tbl.save() # reload the customer table self.customer.load(org_id) # and finally, we put this one in the admin group grp_id = adm_grp_id is_admin = 1 # save the contact if self.contact.real: if not self.contact["org_id"]: raise rhnException("Undefined org_id for existing user entry", self.contact.data) userid = self.contact["id"] self.contact.save() else: userid = self.getid() self.contact["org_id"] = org_id # if not admin, obfuscate the password # (and leave the old_password set) if not is_admin: # we only do this for new users. log_debug(5, "Obfuscating user password") user_pwd = self.contact["password"] crypt_pwd = crypt.crypt(user_pwd, str(userid)[-2:]) self.contact["password"] = crypt_pwd self.contact.create(userid) # rhnUserInfo h = rhnSQL.prepare("insert into rhnUserInfo (user_id) " "values (:user_id)") h.execute(user_id=userid) # now add this user to the admin/applicant group for his org create_ugm = rhnSQL.Procedure("rhn_user.add_to_usergroup") # grp_id is the admin or the applicant, depending on whether we # just created the org or not create_ugm(userid, grp_id) # and now reload this data self.contact.load(userid) # do the same for the other structures indexed by web_user_id # personal info if self.info.real: self.info.save() else: self.info.create(userid) # contact permissions if self.perms.real: self.perms.save() else: self.perms.create(userid) # And now save the site information if self.site.real: siteid = self.site["id"] self.site.save() else: siteid = rhnSQL.Sequence("web_user_site_info_id_seq")() self.site["web_user_id"] = userid self.site.create(siteid) return 0