4

I'm getting a buffer error, but I have a line buffer in the 'with open()' block at line 123. Is this the correct location for the buffer? Should I have something in the connects class too/instead, or the parser argument maybe.

I'm trying to use a file with addresses or hostnames using a '--host_file' argument to run the SNMP commands on multiple ASA's. It works using the '--host' argument just fine.

Any help provided would be greatly appreceated.

Traceback (most recent call last):
  File "asaos-snmpv3-tool.py", line 145, in <module>
    main()
  File "asaos-snmpv3-tool.py", line 124, in main
    with open(hosts, mode='r', buffering=-1):
TypeError: coercing to Unicode: need string or buffer, file found

import pexpect
import argparse

PROMPT = ['# ', '>>> ', '>', '\$ ']
SNMPGROUPCMD = ' snmp-server group '
V3PRIVCMD = ' v3 priv '
SNMPSRVUSRCMD = ' snmp-server user '
V3AUTHCMD = ' v3 auth '
PRIVCMD = ' priv '
SNMPSRVHOSTCMD = ' snmp-server host '
VERSION3CMD = ' version 3 '
SHAHMACCMD = ' sha '
SNMPSRVENTRAP = ' snmp-server enable traps all '
WRME = ' write memory '

def send_command(child, cmd):
    child.sendline(cmd)
    child.expect(PROMPT)
    print child.before

def connect(user, host, passwd, en_passwd):
    ssh_newkey = 'Are you sure you want to continue connecting?'
    constr = 'ssh ' + user + '@' + host
    child = pexpect.spawn(constr)
    ret = child.expect([pexpect.TIMEOUT, ssh_newkey, '[P|p]assword:'])

    if ret == 0:
        print '[-] Error Connecting'
        return
    if ret == 1:
        child.sendline('yes')
        ret = child.expect([pexpect.TIMEOUT, '[P|p]assword:'])
        if ret == 0:
            print '[-] Error Connecting'
            return
    child.sendline(passwd)
    child.expect(PROMPT)
    child.sendline('enable')
    child.sendline(en_passwd)
    child.expect(PROMPT)
    child.sendline('config t')
    child.expect(PROMPT)
    return child

def connects(user, hosts, passwd, en_passwd):
    ssh_newkey = 'Are you sure you want to continue connecting?'
    constr = 'ssh ' + user + '@' + hosts
    child = pexpect.spawn(constr)
    ret = child.expect([pexpect.TIMEOUT, ssh_newkey, '[P|p]assword:'])

    if ret == 0:
        print '[-] Error Connecting'
        return
    if ret == 1:
        child.sendline('yes')
        ret = child.expect([pexpect.TIMEOUT, '[P|p]assword:'])
        if ret == 0:
            print '[-] Error Connecting'
            return
    child.sendline(passwd)
    child.expect(PROMPT)
    child.sendline('enable')
    child.sendline(en_passwd)
    child.expect(PROMPT)
    child.sendline('config t')
    child.expect(PROMPT)
    return child

def main():
    parser = argparse.ArgumentParser('usage %prog ' + '--host --host_file --username --password--enable --group --snmp_user --snmp_host --int_name --snmp_v3_auth --snmp_v3_hmac --snmp_v3_priv --snmp_v3_encr')
    parser.add_argument('--host', dest='host', type=str, help='specify a target host')
    parser.add_argument('--host_file', dest='hosts', type=file, help='specify a target host file')
    parser.add_argument('--username', dest='user', type=str, help='specify a user name')
    parser.add_argument('--password', dest='passwd', type=str, help='specify a passwd')
    parser.add_argument('--enable', dest='en_passwd', type=str, help='specify an enable passwd')
    parser.add_argument('--group', dest='group', type=str, help='specify an snmp group')
    parser.add_argument('--snmp_user', dest='snmpuser', type=str, help='specify an snmp user')
    parser.add_argument('--snmp_host', dest='snmphost', type=str, help='specify an snmp server host')
    parser.add_argument('--int_name', dest='intname', type=str, help='specify interface name')
    parser.add_argument('--snmp_v3_auth', dest='snmpauth', type=str, help='specify the snmp user authentication')
    parser.add_argument('--snmp_v3_hmac', dest='snmphmac', type=str, help='set snmp HMAC, md5 or sha')
    parser.add_argument('--snmp_v3_priv', dest='snmppriv', type=str, help='specify the snmp priv password')
    parser.add_argument('--snmp_v3_encr', dest='snmpencrypt', type=str, help='specify encryption, des, 3des, or aes(128/192/256)')

    args = parser.parse_args()
    host = args.host
    hosts = args.hosts
    user = args.user
    passwd = args.passwd
    en_passwd = args.en_passwd
    group = args.group
    snmpuser = args.snmpuser
    snmphost = args.snmphost
    intname = args.intname
    snmpauth = args.snmpauth
    snmppriv = args.snmppriv
    snmpencrypt = args.snmpencrypt

    if hosts:
        with open(hosts, mode='r', buffering=1):
            for line in hosts:
                hosts = line.rstrip
                child = connects(user, hosts, passwd, en_passwd)
                send_command(child, SNMPGROUPCMD + group + V3PRIVCMD)
                send_command(child, SNMPSRVUSRCMD + snmpuser + ' ' + group + V3AUTHCMD + SHAHMACCMD + snmpauth + PRIVCMD + snmpencrypt + ' ' + snmppriv)
                send_command(child, SNMPSRVHOSTCMD + intname + ' ' + snmphost + VERSION3CMD + snmpuser)
                send_command(child, SNMPSRVENTRAP)
                send_command(child, WRME)

    elif host:
        child = connect(user, host, passwd, en_passwd)
        send_command(child, SNMPGROUPCMD + group + V3PRIVCMD)
        send_command(child, SNMPSRVUSRCMD + snmpuser + ' ' + group + V3AUTHCMD + SHAHMACCMD + snmpauth + PRIVCMD + snmpencrypt + ' ' + snmppriv)
        send_command(child, SNMPSRVHOSTCMD + intname + ' ' + snmphost + VERSION3CMD + snmpuser)
        send_command(child, SNMPSRVENTRAP)
        send_command(child, WRME)
    else:
        print ('Specify either --host or --host_file or I have nothing to do')

if __name__ == '__main__':
    main()
5
  • 2
    Which line? Please show the full traceback, and the relevant function. Commented Jan 15, 2014 at 0:30
  • Traceback (most recent call last): File "asaos-snmpv3-tool.py", line 145, in <module> main() File "asaos-snmpv3-tool.py", line 124, in main with open(hosts, mode='r', buffering=-1): TypeError: coercing to Unicode: need string or buffer, file found Commented Jan 15, 2014 at 0:34
  • Also, in all of your questions, you keep saying that all the other parts work fine, but that's never true. For example, if I run this with --host=a.b.c, I'll get a TypeError about concatenating a str and None (because you made --user optional, with a default value of None, but then blindly concatenated it into a string). Please stop pretending that each new bug is the only thing wrong with your code. Commented Jan 15, 2014 at 0:47
  • Or, even better, don't post your whole program; post a Minimal, Complete, Valid Example that shows the problem you're having, and nothing irrelevant. Commented Jan 15, 2014 at 0:48
  • One last thing: Instead of copying and pasting all that code between the hosts and host_file cases, and between the connect and connects functions, refactor things so you only need to write it once. For example, as written, the only difference between connect and connects is the name of the second parameter and the one line of code where that parameter is used. So they do exactly the same thing. Is that intentional? If so, why have two different functions? If not, how are you going to remember how they were supposed to differ with that huge mess of copypasta? Commented Jan 15, 2014 at 0:53

2 Answers 2

6

There are a whole series of problems here:

if hosts:
    with open(hosts, mode='r', buffering=1):

Here, hosts is clearly meant to be a filename. You open that file… and then don't store it in a variable anywhere, and go on to use the filename as if it were a file.

But, before you even get there, hosts is not actually a filename. One of the nifty features of argparse is that it can automatically open files for you, and you're asking it to do that by using type=file in the argument spec. Which means that hosts is actually a file object, and you're trying to use that file object itself as a filename! Which is what' actually causing the TypeError: coercing to Unicode: need string or buffer, file found: open tries to convert filenames to Unicode strings, and it has no idea how to do that with a file object. If you want to open hosts, don't tell argparse to do it for you; just leave its type as a str.

        for line in hosts:

Since hosts is supposed to be a filename, as a string, this will give you each character in the filename, as a string. Which is not useful.

            hosts = line.rstrip

This overwrites the hosts variable, which you need. And, even worse, it overwrites it with the bound method line.rstrip, rather than the result of calling line.rstrip.

            child = connects(user, hosts, passwd, en_passwd)

And here, you're passing that bound method to a function that wants a string, which isn't going to work.

Don't keep using the same variable name over and over to mean different things. Use a different name for each thing. Ideally one whose name relates in some way to the thing it's holding. For example, a ech (stripped) line in a file named hosts is probably a host, or a hosts_entry… one thing it's not is all of your hosts.

Anyway, to fix all of these problems:

if hosts:
    for line in hosts:
        host = line.rstrip()
        child = connects(user, host, passwd, en_passwd)

Or, if you want to control how hosts is being opened (I'm not sure why you think it's important to specify buffering=1, but presumably you have some reason?):

parser.add_argument('--host_file', dest='hosts', type=str, help='specify a target host file')

# …

if hosts:
    with open(hosts, buffering=1) as hosts_file:
        for line in hosts_file:
            host = line.rstrip()
            child = connects(user, host, passwd, en_passwd)
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks for your help. I was only using the 'buffering' because of other examples. I'm not a developer as you can see, but I'm trying. When I use your first example, (without the open(hosts...)) I now get this errot.TypeError: cannot concatenate 'str' and 'builtin_function_or_method' objects
@insecure-IT: I, and at least two other people, have explained to you multiple times that posting an exception without the traceback, especially without even any indication of which line of code it came from, is completely useless. Please stop doing that.
@insecure-IT: But my first guess is that you didn't copy my code, but instead just changed your code to match whatever differences you happened to notice, and didn't notice the parentheses on line.rstrip(). If so, you will end up trying to use the bound method line.rstrip instead of the stripped string. If that's the case, I already explained that in the answer. I suspect you're not actually reading the answers, because, e.g., I explained the with open(…) as f: thing in your last question, but you left off the as f this time.
Sorry.Traceback (most recent call last): File "asaos-snmpv3-tool.py", line 121, in <module> main() File "asaos-snmpv3-tool.py", line 103, in main child = connect(user, host, passwd, en_passwd) File "asaos-snmpv3-tool.py", line 47, in connect constr = 'ssh ' + user + '@' + host TypeError: cannot concatenate 'str' and 'builtin_function_or_method' objects
@insecure-IT: OK, that code doesn't even come from the --host_file case, it comes from the --host case. So it has absolutely nothing to do with the code you were asking about in this question; instead, it's the code that you said "works". I'm not going to debug all of your problems one by one. If you need code developed, and aren't willing to learn to develop code, you need to go hire a developer.
|
1

it looks like you're iterating over the wrong thing here:

with open(hosts, mode='r', buffering=1):
    for line in hosts:
        hosts = line.rstrip

You maybe want this:

with open(hosts, mode='r', buffering=1) as lines:
    for line in lines:
        host = line.rstrip

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.