We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
adding root:x:!password to userdb.txt doesn't exclude root/password as valid credentials
Fresh install.

I tried to exclude 'password' or 'abc123' from valid passwords for the user root

Now file looks like 
```
root:x:!root
root:x:!123456
root:x:!password
root:x:*
```

Retarted cowrie, but no way to deny login with root/password credentials

Maybe, some sort of problem with new regexp checking?

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/cowrie/core/auth.py`
Content:
```
1 # Copyright (c) 2009-2014 Upi Tamminen <desaster@gmail.com>
2 # See the COPYRIGHT file for more information
3 
4 """
5 This module contains authentication code
6 """
7 
8 from __future__ import absolute_import, division
9 
10 import json
11 import re
12 from collections import OrderedDict
13 from os import path
14 from random import randint
15 
16 from twisted.python import log
17 
18 from cowrie.core.config import CONFIG
19 
20 _USERDB_DEFAULTS = [
21     'root:x:!root',
22     'root:x:!123456',
23     'root:x:!/honeypot/i',
24     'root:x:*',
25     'richard:x:*',
26     'richard:x:fout',
27 ]
28 
29 
30 class UserDB(object):
31     """
32     By Walter de Jong <walter@sara.nl>
33     """
34 
35     def __init__(self):
36         self.userdb = OrderedDict()
37         self.load()
38 
39     def load(self):
40         """
41         load the user db
42         """
43 
44         try:
45             with open('{}/userdb.txt'.format(CONFIG.get('honeypot', 'etc_path')), 'r') as db:
46                 userdb = db.readlines()
47         except IOError:
48             log.msg("Could not read etc/userdb.txt, default database activated")
49             userdb = _USERDB_DEFAULTS
50 
51         for user in userdb:
52             if not user.startswith('#'):
53                 try:
54                     login = user.split(':')[0].encode('utf8')
55                     password = user.split(':')[2].strip().encode('utf8')
56                 except IndexError:
57                     continue
58                 else:
59                     self.adduser(login, password)
60 
61     def checklogin(self, thelogin, thepasswd, src_ip='0.0.0.0'):
62         for credentials, policy in self.userdb.items():
63             login, passwd = credentials
64 
65             if self.match_rule(login, thelogin):
66                 if self.match_rule(passwd, thepasswd):
67                     return policy
68 
69         return False
70 
71     def match_rule(self, rule, input):
72         if type(rule) is bytes:
73             return rule in [b'*', input]
74         else:
75             return bool(rule.search(input))
76 
77     def re_or_str(self, rule):
78         """
79         Convert a /.../ type rule to a regex, otherwise return the string as-is
80 
81         @param login: rule
82         @type login: bytes
83         """
84         res = re.match(br'/(.+)/(i)?$', rule)
85         if res:
86             return re.compile(res.group(1), re.IGNORECASE if res.group(2) else 0)
87 
88         return rule
89 
90     def adduser(self, login, passwd):
91         """
92         All arguments are bytes
93 
94         @param login: user id
95         @type login: bytes
96         @param passwd: password
97         @type passwd: bytes
98         """
99         login = self.re_or_str(login)
100 
101         if passwd[0] == b'!':
102             policy = False
103             passwd = passwd[1:]
104         else:
105             policy = True
106 
107         passwd = self.re_or_str(passwd)
108         self.userdb[(login, passwd)] = policy
109 
110 
111 class AuthRandom(object):
112     """
113     Alternative class that defines the checklogin() method.
114     Users will be authenticated after a random number of attempts.
115     """
116 
117     def __init__(self):
118         # Default values
119         self.mintry, self.maxtry, self.maxcache = 2, 5, 10
120 
121         # Are there auth_class parameters?
122         if CONFIG.has_option('honeypot', 'auth_class_parameters'):
123             parameters = CONFIG.get('honeypot', 'auth_class_parameters')
124             parlist = parameters.split(',')
125             if len(parlist) == 3:
126                 self.mintry = int(parlist[0])
127                 self.maxtry = int(parlist[1])
128                 self.maxcache = int(parlist[2])
129 
130         if self.maxtry < self.mintry:
131             self.maxtry = self.mintry + 1
132             log.msg("maxtry < mintry, adjusting maxtry to: {}".format(self.maxtry))
133         self.uservar = {}
134         self.uservar_file = '{}/auth_random.json'.format(CONFIG.get('honeypot', 'state_path'))
135         self.loadvars()
136 
137     def loadvars(self):
138         """
139         Load user vars from json file
140         """
141         if path.isfile(self.uservar_file):
142             with open(self.uservar_file, 'r') as fp:
143                 try:
144                     self.uservar = json.load(fp)
145                 except Exception:
146                     self.uservar = {}
147 
148     def savevars(self):
149         """
150         Save the user vars to json file
151         """
152         data = self.uservar
153         # Note: this is subject to races between cowrie logins
154         with open(self.uservar_file, 'w') as fp:
155             json.dump(data, fp)
156 
157     def checklogin(self, thelogin, thepasswd, src_ip):
158         """
159         Every new source IP will have to try a random number of times between
160         'mintry' and 'maxtry' before succeeding to login.
161         All username/password combinations  must be different.
162         The successful login combination is stored with the IP address.
163         Successful username/passwords pairs are also cached for 'maxcache' times.
164         This is to allow access for returns from different IP addresses.
165         Variables are saved in 'uservar.json' in the data directory.
166         """
167 
168         auth = False
169         userpass = str(thelogin) + ':' + str(thepasswd)
170 
171         if 'cache' not in self.uservar:
172             self.uservar['cache'] = []
173         cache = self.uservar['cache']
174 
175         # Check if it is the first visit from src_ip
176         if src_ip not in self.uservar:
177             self.uservar[src_ip] = {}
178             ipinfo = self.uservar[src_ip]
179             ipinfo['try'] = 0
180             if userpass in cache:
181                 log.msg("first time for {}, found cached: {}".format(src_ip, userpass))
182                 ipinfo['max'] = 1
183                 ipinfo['user'] = str(thelogin)
184                 ipinfo['pw'] = str(thepasswd)
185                 auth = True
186                 self.savevars()
187                 return auth
188             else:
189                 ipinfo['max'] = randint(self.mintry, self.maxtry)
190                 log.msg("first time for {}, need: {}".format(src_ip, ipinfo['max']))
191         else:
192             if userpass in cache:
193                 ipinfo = self.uservar[src_ip]
194                 log.msg("Found cached: {}".format(userpass))
195                 ipinfo['max'] = 1
196                 ipinfo['user'] = str(thelogin)
197                 ipinfo['pw'] = str(thepasswd)
198                 auth = True
199                 self.savevars()
200                 return auth
201 
202         ipinfo = self.uservar[src_ip]
203 
204         # Fill in missing variables
205         if 'max' not in ipinfo:
206             ipinfo['max'] = randint(self.mintry, self.maxtry)
207         if 'try' not in ipinfo:
208             ipinfo['try'] = 0
209         if 'tried' not in ipinfo:
210             ipinfo['tried'] = []
211 
212         # Don't count repeated username/password combinations
213         if userpass in ipinfo['tried']:
214             log.msg('already tried this combination')
215             self.savevars()
216             return auth
217 
218         ipinfo['try'] += 1
219         attempts = ipinfo['try']
220         need = ipinfo['max']
221         log.msg("login attempt: {}".format(attempts))
222 
223         # Check if enough login attempts are tried
224         if attempts < need:
225             self.uservar[src_ip]['tried'].append(userpass)
226         elif attempts == need:
227             ipinfo['user'] = str(thelogin)
228             ipinfo['pw'] = str(thepasswd)
229             cache.append(userpass)
230             if len(cache) > self.maxcache:
231                 cache.pop(0)
232             auth = True
233         # Returning after successful login
234         elif attempts > need:
235             if 'user' not in ipinfo or 'pw' not in ipinfo:
236                 log.msg('return, but username or password not set!!!')
237                 ipinfo['tried'].append(userpass)
238                 ipinfo['try'] = 1
239             else:
240                 log.msg("login return, expect: [{}/{}]".format(ipinfo['user'], ipinfo['pw']))
241                 if thelogin == ipinfo['user'] and str(thepasswd) == ipinfo['pw']:
242                     auth = True
243         self.savevars()
244         return auth
245
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/cowrie/core/auth.py b/src/cowrie/core/auth.py
--- a/src/cowrie/core/auth.py
+++ b/src/cowrie/core/auth.py
@@ -98,7 +98,7 @@
         """
         login = self.re_or_str(login)
 
-        if passwd[0] == b'!':
+        if passwd[0] == ord("!"):
             policy = False
             passwd = passwd[1:]
         else:

{"golden_diff": "diff --git a/src/cowrie/core/auth.py b/src/cowrie/core/auth.py\n--- a/src/cowrie/core/auth.py\n+++ b/src/cowrie/core/auth.py\n@@ -98,7 +98,7 @@\n         \"\"\"\n         login = self.re_or_str(login)\n \n-        if passwd[0] == b'!':\n+        if passwd[0] == ord(\"!\"):\n             policy = False\n             passwd = passwd[1:]\n         else:\n", "issue": "adding root:x:!password to userdb.txt doesn't exclude root/password as valid credentials\nFresh install.\r\n\r\nI tried to exclude 'password' or 'abc123' from valid passwords for the user root\r\n\r\nNow file looks like \r\n```\r\nroot:x:!root\r\nroot:x:!123456\r\nroot:x:!password\r\nroot:x:*\r\n```\r\n\r\nRetarted cowrie, but no way to deny login with root/password credentials\r\n\r\nMaybe, some sort of problem with new regexp checking?\n", "before_files": [{"content": "# Copyright (c) 2009-2014 Upi Tamminen <desaster@gmail.com>\n# See the COPYRIGHT file for more information\n\n\"\"\"\nThis module contains authentication code\n\"\"\"\n\nfrom __future__ import absolute_import, division\n\nimport json\nimport re\nfrom collections import OrderedDict\nfrom os import path\nfrom random import randint\n\nfrom twisted.python import log\n\nfrom cowrie.core.config import CONFIG\n\n_USERDB_DEFAULTS = [\n    'root:x:!root',\n    'root:x:!123456',\n    'root:x:!/honeypot/i',\n    'root:x:*',\n    'richard:x:*',\n    'richard:x:fout',\n]\n\n\nclass UserDB(object):\n    \"\"\"\n    By Walter de Jong <walter@sara.nl>\n    \"\"\"\n\n    def __init__(self):\n        self.userdb = OrderedDict()\n        self.load()\n\n    def load(self):\n        \"\"\"\n        load the user db\n        \"\"\"\n\n        try:\n            with open('{}/userdb.txt'.format(CONFIG.get('honeypot', 'etc_path')), 'r') as db:\n                userdb = db.readlines()\n        except IOError:\n            log.msg(\"Could not read etc/userdb.txt, default database activated\")\n            userdb = _USERDB_DEFAULTS\n\n        for user in userdb:\n            if not user.startswith('#'):\n                try:\n                    login = user.split(':')[0].encode('utf8')\n                    password = user.split(':')[2].strip().encode('utf8')\n                except IndexError:\n                    continue\n                else:\n                    self.adduser(login, password)\n\n    def checklogin(self, thelogin, thepasswd, src_ip='0.0.0.0'):\n        for credentials, policy in self.userdb.items():\n            login, passwd = credentials\n\n            if self.match_rule(login, thelogin):\n                if self.match_rule(passwd, thepasswd):\n                    return policy\n\n        return False\n\n    def match_rule(self, rule, input):\n        if type(rule) is bytes:\n            return rule in [b'*', input]\n        else:\n            return bool(rule.search(input))\n\n    def re_or_str(self, rule):\n        \"\"\"\n        Convert a /.../ type rule to a regex, otherwise return the string as-is\n\n        @param login: rule\n        @type login: bytes\n        \"\"\"\n        res = re.match(br'/(.+)/(i)?$', rule)\n        if res:\n            return re.compile(res.group(1), re.IGNORECASE if res.group(2) else 0)\n\n        return rule\n\n    def adduser(self, login, passwd):\n        \"\"\"\n        All arguments are bytes\n\n        @param login: user id\n        @type login: bytes\n        @param passwd: password\n        @type passwd: bytes\n        \"\"\"\n        login = self.re_or_str(login)\n\n        if passwd[0] == b'!':\n            policy = False\n            passwd = passwd[1:]\n        else:\n            policy = True\n\n        passwd = self.re_or_str(passwd)\n        self.userdb[(login, passwd)] = policy\n\n\nclass AuthRandom(object):\n    \"\"\"\n    Alternative class that defines the checklogin() method.\n    Users will be authenticated after a random number of attempts.\n    \"\"\"\n\n    def __init__(self):\n        # Default values\n        self.mintry, self.maxtry, self.maxcache = 2, 5, 10\n\n        # Are there auth_class parameters?\n        if CONFIG.has_option('honeypot', 'auth_class_parameters'):\n            parameters = CONFIG.get('honeypot', 'auth_class_parameters')\n            parlist = parameters.split(',')\n            if len(parlist) == 3:\n                self.mintry = int(parlist[0])\n                self.maxtry = int(parlist[1])\n                self.maxcache = int(parlist[2])\n\n        if self.maxtry < self.mintry:\n            self.maxtry = self.mintry + 1\n            log.msg(\"maxtry < mintry, adjusting maxtry to: {}\".format(self.maxtry))\n        self.uservar = {}\n        self.uservar_file = '{}/auth_random.json'.format(CONFIG.get('honeypot', 'state_path'))\n        self.loadvars()\n\n    def loadvars(self):\n        \"\"\"\n        Load user vars from json file\n        \"\"\"\n        if path.isfile(self.uservar_file):\n            with open(self.uservar_file, 'r') as fp:\n                try:\n                    self.uservar = json.load(fp)\n                except Exception:\n                    self.uservar = {}\n\n    def savevars(self):\n        \"\"\"\n        Save the user vars to json file\n        \"\"\"\n        data = self.uservar\n        # Note: this is subject to races between cowrie logins\n        with open(self.uservar_file, 'w') as fp:\n            json.dump(data, fp)\n\n    def checklogin(self, thelogin, thepasswd, src_ip):\n        \"\"\"\n        Every new source IP will have to try a random number of times between\n        'mintry' and 'maxtry' before succeeding to login.\n        All username/password combinations  must be different.\n        The successful login combination is stored with the IP address.\n        Successful username/passwords pairs are also cached for 'maxcache' times.\n        This is to allow access for returns from different IP addresses.\n        Variables are saved in 'uservar.json' in the data directory.\n        \"\"\"\n\n        auth = False\n        userpass = str(thelogin) + ':' + str(thepasswd)\n\n        if 'cache' not in self.uservar:\n            self.uservar['cache'] = []\n        cache = self.uservar['cache']\n\n        # Check if it is the first visit from src_ip\n        if src_ip not in self.uservar:\n            self.uservar[src_ip] = {}\n            ipinfo = self.uservar[src_ip]\n            ipinfo['try'] = 0\n            if userpass in cache:\n                log.msg(\"first time for {}, found cached: {}\".format(src_ip, userpass))\n                ipinfo['max'] = 1\n                ipinfo['user'] = str(thelogin)\n                ipinfo['pw'] = str(thepasswd)\n                auth = True\n                self.savevars()\n                return auth\n            else:\n                ipinfo['max'] = randint(self.mintry, self.maxtry)\n                log.msg(\"first time for {}, need: {}\".format(src_ip, ipinfo['max']))\n        else:\n            if userpass in cache:\n                ipinfo = self.uservar[src_ip]\n                log.msg(\"Found cached: {}\".format(userpass))\n                ipinfo['max'] = 1\n                ipinfo['user'] = str(thelogin)\n                ipinfo['pw'] = str(thepasswd)\n                auth = True\n                self.savevars()\n                return auth\n\n        ipinfo = self.uservar[src_ip]\n\n        # Fill in missing variables\n        if 'max' not in ipinfo:\n            ipinfo['max'] = randint(self.mintry, self.maxtry)\n        if 'try' not in ipinfo:\n            ipinfo['try'] = 0\n        if 'tried' not in ipinfo:\n            ipinfo['tried'] = []\n\n        # Don't count repeated username/password combinations\n        if userpass in ipinfo['tried']:\n            log.msg('already tried this combination')\n            self.savevars()\n            return auth\n\n        ipinfo['try'] += 1\n        attempts = ipinfo['try']\n        need = ipinfo['max']\n        log.msg(\"login attempt: {}\".format(attempts))\n\n        # Check if enough login attempts are tried\n        if attempts < need:\n            self.uservar[src_ip]['tried'].append(userpass)\n        elif attempts == need:\n            ipinfo['user'] = str(thelogin)\n            ipinfo['pw'] = str(thepasswd)\n            cache.append(userpass)\n            if len(cache) > self.maxcache:\n                cache.pop(0)\n            auth = True\n        # Returning after successful login\n        elif attempts > need:\n            if 'user' not in ipinfo or 'pw' not in ipinfo:\n                log.msg('return, but username or password not set!!!')\n                ipinfo['tried'].append(userpass)\n                ipinfo['try'] = 1\n            else:\n                log.msg(\"login return, expect: [{}/{}]\".format(ipinfo['user'], ipinfo['pw']))\n                if thelogin == ipinfo['user'] and str(thepasswd) == ipinfo['pw']:\n                    auth = True\n        self.savevars()\n        return auth\n", "path": "src/cowrie/core/auth.py"}], "after_files": [{"content": "# Copyright (c) 2009-2014 Upi Tamminen <desaster@gmail.com>\n# See the COPYRIGHT file for more information\n\n\"\"\"\nThis module contains authentication code\n\"\"\"\n\nfrom __future__ import absolute_import, division\n\nimport json\nimport re\nfrom collections import OrderedDict\nfrom os import path\nfrom random import randint\n\nfrom twisted.python import log\n\nfrom cowrie.core.config import CONFIG\n\n_USERDB_DEFAULTS = [\n    'root:x:!root',\n    'root:x:!123456',\n    'root:x:!/honeypot/i',\n    'root:x:*',\n    'richard:x:*',\n    'richard:x:fout',\n]\n\n\nclass UserDB(object):\n    \"\"\"\n    By Walter de Jong <walter@sara.nl>\n    \"\"\"\n\n    def __init__(self):\n        self.userdb = OrderedDict()\n        self.load()\n\n    def load(self):\n        \"\"\"\n        load the user db\n        \"\"\"\n\n        try:\n            with open('{}/userdb.txt'.format(CONFIG.get('honeypot', 'etc_path')), 'r') as db:\n                userdb = db.readlines()\n        except IOError:\n            log.msg(\"Could not read etc/userdb.txt, default database activated\")\n            userdb = _USERDB_DEFAULTS\n\n        for user in userdb:\n            if not user.startswith('#'):\n                try:\n                    login = user.split(':')[0].encode('utf8')\n                    password = user.split(':')[2].strip().encode('utf8')\n                except IndexError:\n                    continue\n                else:\n                    self.adduser(login, password)\n\n    def checklogin(self, thelogin, thepasswd, src_ip='0.0.0.0'):\n        for credentials, policy in self.userdb.items():\n            login, passwd = credentials\n\n            if self.match_rule(login, thelogin):\n                if self.match_rule(passwd, thepasswd):\n                    return policy\n\n        return False\n\n    def match_rule(self, rule, input):\n        if type(rule) is bytes:\n            return rule in [b'*', input]\n        else:\n            return bool(rule.search(input))\n\n    def re_or_str(self, rule):\n        \"\"\"\n        Convert a /.../ type rule to a regex, otherwise return the string as-is\n\n        @param login: rule\n        @type login: bytes\n        \"\"\"\n        res = re.match(br'/(.+)/(i)?$', rule)\n        if res:\n            return re.compile(res.group(1), re.IGNORECASE if res.group(2) else 0)\n\n        return rule\n\n    def adduser(self, login, passwd):\n        \"\"\"\n        All arguments are bytes\n\n        @param login: user id\n        @type login: bytes\n        @param passwd: password\n        @type passwd: bytes\n        \"\"\"\n        login = self.re_or_str(login)\n\n        if passwd[0] == ord(\"!\"):\n            policy = False\n            passwd = passwd[1:]\n        else:\n            policy = True\n\n        passwd = self.re_or_str(passwd)\n        self.userdb[(login, passwd)] = policy\n\n\nclass AuthRandom(object):\n    \"\"\"\n    Alternative class that defines the checklogin() method.\n    Users will be authenticated after a random number of attempts.\n    \"\"\"\n\n    def __init__(self):\n        # Default values\n        self.mintry, self.maxtry, self.maxcache = 2, 5, 10\n\n        # Are there auth_class parameters?\n        if CONFIG.has_option('honeypot', 'auth_class_parameters'):\n            parameters = CONFIG.get('honeypot', 'auth_class_parameters')\n            parlist = parameters.split(',')\n            if len(parlist) == 3:\n                self.mintry = int(parlist[0])\n                self.maxtry = int(parlist[1])\n                self.maxcache = int(parlist[2])\n\n        if self.maxtry < self.mintry:\n            self.maxtry = self.mintry + 1\n            log.msg(\"maxtry < mintry, adjusting maxtry to: {}\".format(self.maxtry))\n        self.uservar = {}\n        self.uservar_file = '{}/auth_random.json'.format(CONFIG.get('honeypot', 'state_path'))\n        self.loadvars()\n\n    def loadvars(self):\n        \"\"\"\n        Load user vars from json file\n        \"\"\"\n        if path.isfile(self.uservar_file):\n            with open(self.uservar_file, 'r') as fp:\n                try:\n                    self.uservar = json.load(fp)\n                except Exception:\n                    self.uservar = {}\n\n    def savevars(self):\n        \"\"\"\n        Save the user vars to json file\n        \"\"\"\n        data = self.uservar\n        # Note: this is subject to races between cowrie logins\n        with open(self.uservar_file, 'w') as fp:\n            json.dump(data, fp)\n\n    def checklogin(self, thelogin, thepasswd, src_ip):\n        \"\"\"\n        Every new source IP will have to try a random number of times between\n        'mintry' and 'maxtry' before succeeding to login.\n        All username/password combinations  must be different.\n        The successful login combination is stored with the IP address.\n        Successful username/passwords pairs are also cached for 'maxcache' times.\n        This is to allow access for returns from different IP addresses.\n        Variables are saved in 'uservar.json' in the data directory.\n        \"\"\"\n\n        auth = False\n        userpass = str(thelogin) + ':' + str(thepasswd)\n\n        if 'cache' not in self.uservar:\n            self.uservar['cache'] = []\n        cache = self.uservar['cache']\n\n        # Check if it is the first visit from src_ip\n        if src_ip not in self.uservar:\n            self.uservar[src_ip] = {}\n            ipinfo = self.uservar[src_ip]\n            ipinfo['try'] = 0\n            if userpass in cache:\n                log.msg(\"first time for {}, found cached: {}\".format(src_ip, userpass))\n                ipinfo['max'] = 1\n                ipinfo['user'] = str(thelogin)\n                ipinfo['pw'] = str(thepasswd)\n                auth = True\n                self.savevars()\n                return auth\n            else:\n                ipinfo['max'] = randint(self.mintry, self.maxtry)\n                log.msg(\"first time for {}, need: {}\".format(src_ip, ipinfo['max']))\n        else:\n            if userpass in cache:\n                ipinfo = self.uservar[src_ip]\n                log.msg(\"Found cached: {}\".format(userpass))\n                ipinfo['max'] = 1\n                ipinfo['user'] = str(thelogin)\n                ipinfo['pw'] = str(thepasswd)\n                auth = True\n                self.savevars()\n                return auth\n\n        ipinfo = self.uservar[src_ip]\n\n        # Fill in missing variables\n        if 'max' not in ipinfo:\n            ipinfo['max'] = randint(self.mintry, self.maxtry)\n        if 'try' not in ipinfo:\n            ipinfo['try'] = 0\n        if 'tried' not in ipinfo:\n            ipinfo['tried'] = []\n\n        # Don't count repeated username/password combinations\n        if userpass in ipinfo['tried']:\n            log.msg('already tried this combination')\n            self.savevars()\n            return auth\n\n        ipinfo['try'] += 1\n        attempts = ipinfo['try']\n        need = ipinfo['max']\n        log.msg(\"login attempt: {}\".format(attempts))\n\n        # Check if enough login attempts are tried\n        if attempts < need:\n            self.uservar[src_ip]['tried'].append(userpass)\n        elif attempts == need:\n            ipinfo['user'] = str(thelogin)\n            ipinfo['pw'] = str(thepasswd)\n            cache.append(userpass)\n            if len(cache) > self.maxcache:\n                cache.pop(0)\n            auth = True\n        # Returning after successful login\n        elif attempts > need:\n            if 'user' not in ipinfo or 'pw' not in ipinfo:\n                log.msg('return, but username or password not set!!!')\n                ipinfo['tried'].append(userpass)\n                ipinfo['try'] = 1\n            else:\n                log.msg(\"login return, expect: [{}/{}]\".format(ipinfo['user'], ipinfo['pw']))\n                if thelogin == ipinfo['user'] and str(thepasswd) == ipinfo['pw']:\n                    auth = True\n        self.savevars()\n        return auth\n", "path": "src/cowrie/core/auth.py"}]}