def walk(self, oid): """Walk over children of a given OID This is roughly equivalent to snmpwalk. It will automatically try to be a snmpbulkwalk if possible. :param oid: The SNMP object identifier """ # SNMP is a complicated mess of things. Will endeavor to shield caller # from as much as possible, assuming reasonable defaults when possible. # there may come a time where we add more parameters to override the # automatic behavior (e.g. DES is weak, so it's likely to be # overriden, but some devices only support DES) tp = _get_transport(self.server) ctx = snmp.ContextData(self.context) resolvemib = False if '::' in oid: resolvemib = True mib, field = oid.split('::') obj = snmp.ObjectType(snmp.ObjectIdentity(mib, field)) else: obj = snmp.ObjectType(snmp.ObjectIdentity(oid)) walking = snmp.bulkCmd(self.eng, self.authdata, tp, ctx, 0, 10, obj, lexicographicMode=False, lookupMib=resolvemib) try: for rsp in walking: errstr, errnum, erridx, answers = rsp if errstr: errstr = str(errstr) finerr = errstr + ' while trying to connect to ' \ '{0}'.format(self.server) if errstr in ('Unknown USM user', 'unknownUserName', 'wrongDigest', 'Wrong SNMP PDU digest'): raise exc.TargetEndpointBadCredentials(finerr) # need to do bad credential versus timeout raise exc.TargetEndpointUnreachable(finerr) elif errnum: raise exc.ConfluentException(errnum.prettyPrint() + ' while trying to connect to ' '{0}'.format(self.server)) for ans in answers: if not obj[0].isPrefixOf(ans[0]): # PySNMP returns leftovers in a bulk command # filter out such leftovers break yield ans except snmperr.WrongValueError: raise exc.TargetEndpointBadCredentials('Invalid SNMPv3 password')
def cnos_login(node, configmanager, creds): wc = webclient.SecureHTTPConnection( node, port=443, verifycallback=util.TLSCertVerifier( configmanager, node, 'pubkeys.tls_hardwaremanager').verify_cert) wc.set_basic_credentials( creds[node]['secret.hardwaremanagementuser']['value'], creds[node]['secret.hardwaremanagementpassword']['value']) wc.request('GET', '/nos/api/login/') rsp = wc.getresponse() body = rsp.read() if rsp.status == 401: # CNOS gives 401 on first attempt... wc.request('GET', '/nos/api/login/') rsp = wc.getresponse() body = rsp.read() if rsp.status >= 200 and rsp.status < 300: return wc raise exc.TargetEndpointBadCredentials('Unable to authenticate')
def _bmcconfig(self, nodename, reset=False, customconfig=None, vc=None): # TODO(jjohnson2): set ip parameters, user/pass, alert cfg maybe # In general, try to use https automation, to make it consistent # between hypothetical secure path and today. creds = self.configmanager.get_node_attributes(nodename, [ 'secret.hardwaremanagementuser', 'secret.hardwaremanagementpassword' ], decrypt=True) user = creds.get(nodename, {}).get('secret.hardwaremanagementuser', {}).get('value', None) passwd = creds.get(nodename, {}).get('secret.hardwaremanagementpassword', {}).get('value', None) try: ic = self._get_ipmicmd() passwd = self.DEFAULT_PASS except pygexc.IpmiException as pi: havecustomcreds = False if user is not None and user != self.DEFAULT_USER: havecustomcreds = True else: user = self.DEFAULT_USER if passwd is not None and passwd != self.DEFAULT_PASS: havecustomcreds = True else: passwd = self.DEFAULT_PASS if havecustomcreds: ic = self._get_ipmicmd(user, passwd) else: raise if vc: ic.register_key_handler(vc) currusers = ic.get_users() lanchan = ic.get_network_channel() userdata = ic.xraw_command(netfn=6, command=0x44, data=(lanchan, 1)) userdata = bytearray(userdata['data']) maxusers = userdata[0] & 0b111111 enabledusers = userdata[1] & 0b111111 lockedusers = userdata[2] & 0b111111 cfg = self.configmanager cd = cfg.get_node_attributes(nodename, [ 'secret.hardwaremanagementuser', 'secret.hardwaremanagementpassword', 'hardwaremanagement.manager' ], True) cd = cd.get(nodename, {}) if ('secret.hardwaremanagementuser' not in cd or 'secret.hardwaremanagementpassword' not in cd): raise exc.TargetEndpointBadCredentials( 'secret.hardwaremanagementuser and/or ' 'secret.hardwaremanagementpassword was not configured') newuser = cd['secret.hardwaremanagementuser']['value'] newpass = cd['secret.hardwaremanagementpassword']['value'] for uid in currusers: if currusers[uid]['name'] == newuser: # Use existing account that has been created newuserslot = uid if newpass != passwd: # don't mess with existing if no change ic.set_user_password(newuserslot, password=newpass) ic = self._get_ipmicmd(user, passwd) if vc: ic.register_key_handler(vc) break else: newuserslot = lockedusers + 1 if newuserslot < 2: newuserslot = 2 if newpass != passwd: # don't mess with existing if no change ic.set_user_password(newuserslot, password=newpass) ic.set_user_name(newuserslot, newuser) if havecustomcreds: ic = self._get_ipmicmd(user, passwd) if vc: ic.register_key_handler(vc) #We are remote operating on the account we are #using, no need to try to set user access #ic.set_user_access(newuserslot, lanchan, # privilege_level='administrator') # Now to zap others for uid in currusers: if uid != newuserslot: if uid <= lockedusers: # we cannot delete, settle for disable ic.disable_user(uid, 'disable') else: # lead with the most critical thing, removing user access ic.set_user_access(uid, channel=None, callback=False, link_auth=False, ipmi_msg=False, privilege_level='no_access') # next, try to disable the password ic.set_user_password(uid, mode='disable', password=None) # ok, now we can be less paranoid try: ic.user_delete(uid) except pygexc.IpmiException as ie: if ie.ipmicode != 0xd5: # some response to the 0xff # name... # the user will remain, but that is life raise if customconfig: customconfig(ic) if ('hardwaremanagement.manager' in cd and cd['hardwaremanagement.manager']['value'] and not cd['hardwaremanagement.manager']['value'].startswith( 'fe80::')): newip = cd['hardwaremanagement.manager']['value'] newipinfo = getaddrinfo(newip, 0)[0] # This getaddrinfo is repeated in get_nic_config, could be # optimized, albeit with a more convoluted api.. newip = newipinfo[-1][0] if ':' in newip: raise exc.NotImplementedException('IPv6 remote config TODO') netconfig = netutil.get_nic_config(cfg, nodename, ip=newip) plen = netconfig['prefix'] newip = '{0}/{1}'.format(newip, plen) currcfg = ic.get_net_configuration() if currcfg['ipv4_address'] != newip: # do not change the ipv4_config if the current config looks # like it is already accurate ic.set_net_configuration( ipv4_address=newip, ipv4_configuration='static', ipv4_gateway=netconfig['ipv4_gateway']) elif self.ipaddr.startswith('fe80::'): cfg.set_node_attributes( {nodename: { 'hardwaremanagement.manager': self.ipaddr }}) else: raise exc.TargetEndpointUnreachable( 'hardwaremanagement.manager must be set to desired address') if reset: ic.reset_bmc() return ic