Shell login failed - invalid credentials 338

246 views
Skip to first unread message

adhdistracted

unread,
Jul 25, 2024, 11:28:04 AM7/25/24
to Event-Driven Servers
Hey Marc, 

I'm having an issue setting up tac_plus-ng to talk to our LDAP server. I'll preface that I'm not an expert with LDAP, nor perl, but my team has been helping out and some of them are much more familiar. In our configs, we have a local user set up that can log in without issue. But when trying to use an LDAP user, we get the error "Shell login failed [Invalid credentials (338)]". If I remove the defined user & password in the tac_plus-ng.cfg, we get "login denied by ACL" instead. Apologies if this is useless information overload, but I'll provide as much as I can because we've run out of ideas. 

We're running on RHEL 7, and using the RHEL LDAP server. It does have the memberOf plugin but we've been ignoring it so far. It does not allow anonymous binds. 
I may misunderstand, but it appears I should be able to test the connection to the LDAP server with mavis_tacplus-ng_ldap.pl; however when I provide the user credentials and fields, to include setting the environment variables, I always get:
"The 389 server will not return the memberOf attribute for anonymous binds. Please set the LDAP_USER and LDAP_PASSWD environment variables.
0 TACPLUS
4 ldapuser
6 NFD
8 basicpassword
49 AUTH
=16"

The LDAP user we're trying to connect on a device with has the following set:
tacacsClient: admin
tacacsClient: 192.168.0.0/16
tacacsMember: admin
tacacsProfile: { valid until 2025-06-06 }

We had trouble importing the ldif or schema files (I know they say deprecated but was hoping they would simplify creating the schema changes), so we manually created the fields as best we could. 
We created the object class "tacacsAccount" under top, and "tacacs" under "tacacsAccount". 
As custom attributes, we included "tacacsClient", "tacacsMember", and "tacacsProfile", with the OIDs 1.3.6.1.3.1.1.1.1.2.1/2/3, respectively.  

The config we are using, with alterations to sensitive info, is as below:
#!/usr/local/sbin/tac_plus-ng

id = spawnd {
background = no
# single process = yes
listen { port = 4949 }
listen {
port = 49
tls = true
}
spawn {
instances min = 1
instances max = 32
}
}

id = tac_plus-ng {
#debug = PACKET AUTHEN AUTHOR

log mysyslog
log authzlog { destination = /var/log/tac_plus/authz/%Y/%m/%d.log }
log authclog { destination = /var/log/tac_plus/authc/%Y/%m/%d.log }
log acctlog  { destination = /var/log/tac_plus/acct/%Y/%m/%d.log }

access log = mysyslog
accounting log = acctlog
authentication log = authclog
authorization log = authzlog

# debug log thing
log connlog { destination = /var/log/tac_plus/conn.log }
connection log = connlog

# pap password = login

# dns preload file = sample/hosts.txt
dns preload address 192.168.18.100 = ldap.example.net

# mavis module = tacinfo_cache {
# directory = /tmp/tacinfo0
# }

mavis module = groups {
resolve gids = yes
resolve gids attribute = TACMEMBER
groups filter = /^(guest|staff|ubuntu)$/
}

# PAM handling using the "external" module. Each "pammavis" process can handle
# exactly one authentication:
#
# mavis module = external {
# exec = /usr/local/sbin/pammavis pammavis -s ssh
# childs min = 4
# childs max = 64
# }

# Alternatively you may try the new new "external-mt" (multi-threading) module
# where a single "pammavis-mt" process handles multiple concurrent authentications
# via POSIX threads:
#
mavis module = external {
setenv LDAP_SERVER_TYPE = "tacacs_schema"
setenv LDAP_HOSTS = "ldap://ldap.example.net:389"
setenv LDAP_SCOPE = sub
setenv LDAP_BASE = "dc=example,dc=net"
setenv LDAP_FILTER = "(&(uid=%s)(objectClass=tacacsAccount))"
# setenv LDAP_FILTER_CHPW = "(&(uid=%s)(objectClass=tacacsAccount)(!(tacacsFlag=staticpasswd)))"
setenv LDAP_USER = admin
setenv LDAP_PASSWD = password
# setenv AD_GROUP_PREFIX =
# setenv REQUIRE_AD_GROUP_PREFIX =
setenv USE_TLS = 1
# setenv TLS_OPTIONS = "sslversion => 'tlsv1_3'"
# setenv FLAG_CHPW = 0/1
# setenv FLAG_PWPOLICY = 0/1
# setenv FLAG_CACHE_CONNECTION = 0/1
setenv FLAG_FALLTHROUGH = 1
# setenv FLAG_USE_MEMBEROF = 1
exec = /usr/local/lib/mavis/mavis_tacplus-ng_ldap.pl
}

user backend = mavis
login backend = mavis
pap backend = mavis

net private {
net rfc1918 { address = 10.0.0.0/8,172.16.0.0/12 address = 192.168.0.0/16 }
net local { address = 127.0.0.1 }
}

# net filetest {
# address file = sample/addre*ses.txt
# }

net base {
net primary {
address = 192.168.16.0/22
net base_16 {
address = 192.168.16.0/24
}
net base_17 {
address = 192.168.17.0/24
}
net base_18 {
address = 192.168.18.0/24
}
net base_19 {
address = 192.168.19.0/24
}
}
net base_100s {
address = 192.168.100.0/23
net base_100 {
address = 192.168.100.0/24
}
net base_101 {
address = 192.168.101.0/24
}
}
net base_172 {
address = 172.17.240.0/21
net base_240 {
address = 172.17.240.0/24
}
net base_241 {
address = 172.17.241.0/24
}
net base_242 {
address = 172.17.242.0/24
}
net base_243 {
address = 172.17.243.0/24
}
net base_244 {
address = 172.17.244.0/24
}
}
}

device base {
welcome banner = "test banner"
key = devicekey
enable 15 = clear password
address = ::/0
device bmain {
address = 192.168.16.0/22
}
device b100 {
address = 192.168.100.0/23
}
device b172 {
address = 172.17.240.0/21
}
}

device localhost {
address = 127.0.0.1
welcome banner = "Welcome home\n"
parent = base
}

device base-gw {
welcome banner = "Welcome to the network\n"
key = devicekey
enable 15 = clear basicpassword
address = 192.168.19.225
parent = base
}

acl demo1 { if (user != demo) permit deny }
# acl bacn1 { if (user == basic_user) permit deny }
# acl test1 { if (user == ldapuser) permit }

profile admin {
script {
if (service == shell) {
    if (cmd == "") {
set priv-lvl = 15
permit
    }
}
}
}

profile engineering {
enable 2 = permit
enable 14 = clear demodemo
enable 15 = login
script {
if ("${cmd}" != "")
message = "commandline=${cmd}"
if (service == shell) {
    if (cmd == "") {
# shell startup
set priv-lvl = 15
permit
    }
    set priv-lvl = 15
    if (cmd =~ /^healthcheck.*/) {
permit
    }
    #if (cmd =~ /^ping/) { message = "not now" deny }
    #if (device == lab) deny
    permit
}
if (service == demo) {
    set test = too
    permit
}
}
}

profile guest {
script {
if (service == shell) {
set priv-lvl = 1
permit
}
deny
}
}

profile ppp {
script {
if (service == ppp) {
if (arg[protocol] == ip) {
set addr = 1.2.3.4
permit
}
deny
}
deny
}
}

group admin {
group somegroup
group engineering { }
}

group ubuntu {
group someothergroup
group others
}

user demo {
password login = clear demo
password pap = login
member = engineering
}

user basic_user {
password login = clear basicpassword
member = admin
}

user readonly {
password {
pap = clear readonly
login = clear readonly
}
}

ruleset {
rule default {
enabled = yes
script {
if (member == admin) {
profile = admin
permit
}
}
}
rule from-localhost {
enabled = yes
script {
if (device == localhost && client == private) {
if (member ==  engineering ) {
profile = engineering
permit
}
if (member ==  admin) {
profile = admin
permit
}
}
}
}
rule from-base {
enabled = yes
script {
if (device == base && client == base) {
if (member == admin) {
profile = admin
permit
}
}
if (device == base-gw && client == base) {
if (member == admin) {
profile = admin
permit
}
}
}
}
}
}


Really appreciate any time you can spend on this, I know it's never fun attempting to understand other peoples issues. If there's anything more I can provide, I'll be happy to. 

Thanks, 
Alasdair

Marc Huber

unread,
Jul 25, 2024, 12:10:57 PM7/25/24
to event-driv...@googlegroups.com
Hi Alasdair,

On 25.07.2024 15:24, adhdistracted wrote:
> In our configs, we have a local user set up that can log in without
> issue. But when trying to use an LDAP user, we get the error "Shell
> login failed [Invalid credentials (338)]"

338 is actually the line number where the Perl script outputs the error
message. However, this doesn't seem to match the actual GIT code --
you're running a customized version?

About the "Please set the LDAP_USER and LDAP_PASSWD environment
variables." message you're seeing: The code that outputs that checks for
"$#LDAP_BIND < 0", so it's likely that either LDAP_USER or LDAP_PASSWD
aren't available. Given that you're getting a NFT (not found) result
seems to confirm that there's an issue with the environment variables
(LDAP_BASE not being recognized, perhaps). Your test looked similar to
the lines below?

printf "0 TACPLUS\n4 ldapuser\n8 basicpassword\n49AUTH\n=\n" | \
   env USE_TLS=1\
       LDAP_HOSTS="ldap://ldap.example.net:389"\
       LDAP_BASE="dc=example,dc=net"\
       LDAP_FILTER="(&(uid=%s)(objectClass=tacacsAccount))"\
       LDAP_USER=admin\
       LDAP_PASSWD=password\
     |/usr/local/lib/mavis/mavis_tacplus-ng_ldap.pl

Cheers,

Marc

adhdistracted

unread,
Jul 25, 2024, 1:10:48 PM7/25/24
to Event-Driven Servers
Marc, 

> 338 is actually the line number where the Perl script outputs the error
> message. However, this doesn't seem to match the actual GIT code --
> you're running a customized version?
I haven't customized or rewritten anything, only built/compiled the code on the machine we're testing with.
Is mavis_tacplus-ng_ldap.pl the script that is outputting the error and referencing line 338? Our line 338 is:
         $V[AV_A_USER_RESPONSE] = $mesg->error . " (" . __LINE__ . ")";
Which, without intensely understanding it, does look somewhat like it would output the error we get. 
I actually recompiled and built everything yesterday from the latest you had in GIT, which I believe was updated the day before. 

When I run the test the way you've formatted it above (because I admit I had wondered how excluding all those lines was reading any variables), I get a different error:
6 ERR
32 User not set.
=0
I find this error weird because I'm definitely specifying the LDAP_USER field in the test lines. 

Many thanks, 
Alasdair

Marc Huber

unread,
Jul 26, 2024, 2:16:58 PM7/26/24
to event-driv...@googlegroups.com
Hi,

sorry, my bad. I've messed this up. The correct command would be

printf "0 TACPLUS\n4 ldapuser\n8 basicpassword\n49AUTH\n=\n" | \
   env USE_TLS=1\
       LDAP_HOSTS="ldap://ldap.example.net:389
<http://ldap.example.net:389>"\
       LDAP_BASE="dc=example,dc=net"\
       LDAP_FILTER="(&(uid=%s)(objectClass=tacacsAccount))"\
       LDAP_USER=admin\
       LDAP_PASSWD=password\
        /usr/local/lib/mavis/mavis_tacplus-ng_ldap.pl
<http://mavis_tacplus-ng_ldap.pl>

(without any "|" in front of
"/usr/local/lib/mavis/mavis_tacplus-ng_ldap.pl
<http://mavis_tacplus-ng_ldap.pl>".

Cheers,

Marc

On 25.07.2024 19:10, adhdistracted wrote:
> Marc,
>
> /> 338 is actually the line number where the Perl script outputs the
> error/
> /> message. However, this doesn't seem to match the actual GIT code --
> > you're running a customized version?/
> <http://ldap.example.net:389>"\
>        LDAP_BASE="dc=example,dc=net"\
> LDAP_FILTER="(&(uid=%s)(objectClass=tacacsAccount))"\
>        LDAP_USER=admin\
>        LDAP_PASSWD=password\
>      |/usr/local/lib/mavis/mavis_tacplus-ng_ldap.pl
> <http://mavis_tacplus-ng_ldap.pl>
>
> Cheers,
>
> Marc
>
> --
> You received this message because you are subscribed to the Google
> Groups "Event-Driven Servers" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to event-driven-ser...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/event-driven-servers/418a43d1-a36b-496c-aa14-adbe33202fd9n%40googlegroups.com
> <https://groups.google.com/d/msgid/event-driven-servers/418a43d1-a36b-496c-aa14-adbe33202fd9n%40googlegroups.com?utm_medium=email&utm_source=footer>.

adhdistracted

unread,
Jul 26, 2024, 2:43:40 PM7/26/24
to Event-Driven Servers
Hey Marc, 

No worries! Easy enough to retest. It no longer gives me a warning message about the user being set. 
I now get:
0 TACPLUS
4 ldapuser
6 ERR
8 basicpassword
32 Invalid credentials (338)
49 AUTH
=0

If I try it with an intentionally invalid hostname, I get "32 No answer from LDAP backend.", so it seems to be at least communicating with the LDAP service. 
I can successfully execute ldapsearch queries as the user I am attempting to connect with, ie. "ldapsearch -x -b ou=users,dc=example,dc=net -D uid=ldapuser,ou=serviceaccounts,dc=example,dc=net -W"
What next best step can I take to help try and identify the root issue here?

Thanks, 
Alasdair

Marc Huber

unread,
Jul 26, 2024, 3:05:14 PM7/26/24
to event-driv...@googlegroups.com
Hi Alasdair,

the "6 ERR" AV pair, combined with "32 Invalid credentials (338)" would
indicate that LDAP_USER and/or LDAP_PASSWD aren't accepted by your LDAP
server. Does ldapsearch work when binding with these credentials?

Cheers,

Marc

adhdistracted

unread,
Jul 26, 2024, 3:56:12 PM7/26/24
to event-driv...@googlegroups.com

Hey,

> Does ldapsearch work when binding with these credentials?

Yes. I mentioned it in the last message, but I can successfully execute ldapsearch queries as the user I am attempting to connect with, ie. "ldapsearch -x -b ou=users,dc=example,dc=net -D uid=ldapuser,ou=serviceaccounts,dc=example,dc=net -W".

Thanks,
Alasdair


--
You received this message because you are subscribed to a topic in the Google Groups "Event-Driven Servers" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/event-driven-servers/CNpFt12sH-k/unsubscribe.
To unsubscribe from this group and all its topics, send an email to event-driven-ser...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/event-driven-servers/70bec5a6-ae22-4426-a585-c2d6dc90a99b%40googlemail.com.

Marc Huber

unread,
Jul 27, 2024, 6:44:43 AM7/27/24
to event-driv...@googlegroups.com
Hi Alasdair,

the ldap_bind() credentials used to search for "ldapuser" are those set with

setenv LDAP_USER = admin
setenv LDAP_PASSWD = password

These don't seem to work.

Cheers,

Marc

adhdistracted

unread,
Jul 29, 2024, 12:46:46 PM7/29/24
to Event-Driven Servers
Hi Marc, 

My fault for not being more specific. 
I can run "ldapsearch -x -b uid=ldapuser,ou=users,dc=example,dc=net -D uid=ldapadmin,ou=serviceaccounts,dc=example,dc=net -W", and it returns the user information successfully. 

However, when I try to run the test with the perl script, it fails. I run the command to lookup the admin account that I know works when running ldapsearch, but it does not seem to go through. Here is exactly what I ran:
printf "0 TACPLUS\n4 ldapadmin\n8 basicpassword\n49AUTH\n=\n" | \
  env USE_TLS=1\
    LDAP_HOSTS="ldap://ldap.example.net:389"\
    LDAP_BASE="dc=example,dc=net"\
    LDAP_FILTER="(&(uid=%s)(objectClass=tacacsAccount))"\
    LDAP_USER=ldapadmin\
    LDAP_PASSWD=basicpassword\
  /usr/local/lib/mavis/mavis_tacplus-ng_ldap.pl

And I still get the result of:
0 TACPLUS
4 ldapadmin
6 ERR
8 basicpassword
32 Invalid credentials (338)
49 AUTH
=0

I know the account is valid, and can login + perform ldap commands, even though the code keeps coming back with Invalid credentials. 
Is there a way to make the perl script output more information about what it is doing?

Thanks, 
Alasdair

Marc Huber

unread,
Jul 30, 2024, 11:28:48 AM7/30/24
to event-driv...@googlegroups.com
Hi Alasdair,

and your LDAP_USER variable is exactly the
"uid=ldapadmin,ou=serviceaccounts,dc=example,dc=net" (which works with
ldapsearch), but not just "ldapadmin"?

Cheers,

Marc


On 29.07.2024 18:46, adhdistracted wrote:
> Hi Marc,
>
> My fault for not being more specific.
> I can run "ldapsearch -x -b uid=ldapuser,ou=users,dc=example,dc=net -D
> uid=ldapadmin,ou=serviceaccounts,dc=example,dc=net -W", and it returns
> the user information successfully.
>
> However, when I try to run the test with the perl script, it fails. I
> run the command to lookup the admin account that I know works when
> running ldapsearch, but it does not seem to go through. Here is
> exactly what I ran:
> printf "0 TACPLUS\n4 ldapadmin\n8 basicpassword\n49AUTH\n=\n" | \
>   env USE_TLS=1\
>     LDAP_HOSTS="ldap://ldap.example.net:389
> <http://ldap.example.net:389/>"\
>     LDAP_BASE="dc=example,dc=net"\
> LDAP_FILTER="(&(uid=%s)(objectClass=tacacsAccount))"\
>     LDAP_USER=ldapadmin\
>     LDAP_PASSWD=basicpassword\
>   /usr/local/lib/mavis/mavis_tacplus-ng_ldap.pl
> <http://mavis_tacplus-ng_ldap.pl/>
> --
> You received this message because you are subscribed to the Google
> Groups "Event-Driven Servers" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to event-driven-ser...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/event-driven-servers/5f189405-5153-414e-9d8e-cdae64d34ac0n%40googlegroups.com
> <https://groups.google.com/d/msgid/event-driven-servers/5f189405-5153-414e-9d8e-cdae64d34ac0n%40googlegroups.com?utm_medium=email&utm_source=footer>.

adhdistracted

unread,
Jul 31, 2024, 8:44:04 AM7/31/24
to Event-Driven Servers
Marc, 

I was setting LDAP_USER to "ldapadmin", not the long string for ldapsearch. 
If I set LDAP_USER to "uid=ldapadmin,ou=serviceaccounts,dc=example,dc=net", the output changes to:
32 Username not valid. 

Thanks, 
Alasdair

Marc Huber

unread,
Jul 31, 2024, 11:38:47 AM7/31/24
to event-driv...@googlegroups.com
Hi Alasdair,

the LDAP_USER variable needs to be in DN format, but the user name you
want to authenticate is just a plain user name, not any LDAP DN.

I think that's your issue right now. The "32 Username not valid." is
exactly the result of matching

        if ($V[AV_A_USER] =~ /\(|\)|,|\||&|=|\*/){
                $V[AV_A_USER_RESPONSE] = "Username not valid.";
                goto fatal;
        }

Cheers,

Marc
> <http://ldap.example.net:389>
> <https://groups.google.com/d/msgid/event-driven-servers/5f189405-5153-414e-9d8e-cdae64d34ac0n%40googlegroups.com?utm_medium=email&utm_source=footer>>.
>
>
> --
> You received this message because you are subscribed to the Google
> Groups "Event-Driven Servers" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to event-driven-ser...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/event-driven-servers/b15f4434-0c8f-478b-a650-984b08aed36an%40googlegroups.com
> <https://groups.google.com/d/msgid/event-driven-servers/b15f4434-0c8f-478b-a650-984b08aed36an%40googlegroups.com?utm_medium=email&utm_source=footer>.

adhdistracted

unread,
Aug 1, 2024, 11:11:21 AM8/1/24
to Event-Driven Servers
Hey Marc, 

Many thanks! This was the key that I (and the others who were trying to help me) were missing. 
It doesn't explicitly call out that you need to use a DN formatted value in the docs, so it never occurred to us. 

Once I changed that, I can now get proper responses from the LDAP server.
I've changed over the configs for tac_plus-ng, and can at least see that it is now communicating with the server. 

However, I cannot actually log in as any LDAP users on the network devices, because I see in the authentication logs I am being blocked via ACL. 
I've been trying out different options and combinations for the logs to see if I could get it to be more verbose, and have played around with the ACLs a bit, but it sounds like I need to have a specific ACL that allows any authenticated LDAP users.

Is there a sample somewhere that I missed that details this? I've been looking around through the files and posts to see if someone else had something, but I haven't found it. 
And if you want me to move this section of the issue to a new thread, I can do that too, since it's not the same roadblock anymore. 

Thanks again!
Alasdair

Marc Huber

unread,
Aug 1, 2024, 12:47:58 PM8/1/24
to event-driv...@googlegroups.com
Hi Alasdair,

great that things are starting to work out better!

The "Denied by ACL" response is typically an issue with the rule set.
Using tactrace.pl (not part of the stock install, but just run: cd
tac_plus-ng/perl && make install) for testing usually gives a quick
insight on what goes wrong.

Cheers,

Marc

adhdistracted

unread,
Aug 1, 2024, 2:06:22 PM8/1/24
to Event-Driven Servers
Hi Marc, 

I won't get into the rabbit hole that is tactrace not working on my system, but the good news is that I was able to narrow down the issue to being rulesets. 
I'll have to sit with the system and figure out what the filters for member are actually reading in, but when I changed a ruleset to "member != ubuntu", I can actually log in with my LDAP accounts. 
This is really the key that we needed, and so fine tuning the system can happen over time at this point. For now though I think we can call this thread resolved. 

Again, really do appreciate all your time on this, and the hard work you've put into this whole project!

Thanks, 
Alasdair

Reply all
Reply to author
Forward
0 new messages