Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

PAM_IGNORE (was Re: Why should setcred be called after session open?)

58 views
Skip to first unread message

Nicolas Williams

unread,
May 16, 2001, 4:39:54 PM5/16/01
to
[Cc'ing pam-...@redhat.com]

On Wed, May 16, 2001 at 03:06:14PM -0500, Stephen Langasek wrote:
> On Tue, 15 May 2001, Nicolas Williams wrote:
>
> > pam_sm_acct_mgmt() (and pam_sm_setcred(), for that matter) MUST return
> > PAM_IGNORE if pam_sm_authenticate() returned PAM_IGNORE, and what to
> > return if pam_sm_authenticate() was not called is a bit more
> > complicated.
>
> Ok, I can see your point here. pam_sm_acct_mgmt() should not contribute a
> success code to the return value of the function if we don't have any data
> from pam_sm_authenticate(), but this is not necessarily the same thing as
> returning a failure (i.e., we have PAM_IGNORE to work with).

When a module returns PAM_IGNORE< it's ignored, EVEN IF it was a
required module -- i.e., it's treated as if it hadn't even been on the
stack. Certainly this is how Solaris PAM works. I know, not only
empirically, but also because I have access to Solaris source code.

> However, consider this configuration:
>
> auth sufficient pam_krb5.so
> account requisite pam_krb5.so
> account requisite pam_unix.so
>
> This config specifies that pam_krb5 is used for all authentication, and that
> the user must pass /both/ Kerberos /and/ Unix (shadow) authorization checks
> in order to gain access. Is this a valid config? If so, what happens when
> pam_sm_acct_mgmt() returns PAM_IGNORE because it doesn't /know/ if the user
> is authorized?

It's ignored, as if it had not even been mentioned in the config.

Consider this:

rlogin auth sufficient pam_rhosts
rlogin auth whatever pam_krb5
rlogin auth whatever pam_unix
rlogin account required pam_krb5
rlogin account required pam_unix

If pam_rhosts succeeds, then pam_krb5:auth will never be tried, but
pam_krb5:account MUST be tried just in case pam_krb5:auth was tried. So
pam_krb5:account is tried, but it can't actually *DO* anything, so it
MUST return PAM_IGNORE.

Trust me, Solaris PAM does the right thing, and I believe Linux-PAM must
as well. The right thing is to treat modules returning PAM_IGNORE as if
they weren't even on the stack (except that setcred() will be called
even if auth() returned PAM_IGNORE -- similarly with open/close).

> Keep in mind that an app calling pam_authenticate() on a different handle
> than pam_acct_mgmt() is effectively broken, at least with respect to our
> module's requirements. I think it's appropriate to expose this brokenness,
> rather than silently ignoring it with PAM_IGNORE; this is more likely to
> result in the application being fixed, making everyone happier.

Nope. See above. Account MUST return PAM_IGNORE if it lacks inputs
(e.g., pam data whence a principal name can be obtained that can be fed
to krb5_kuserok() and krb5_aname_to_lname()).

I know this because I got bitten already by this. Amond the many fixes
we'll check in this week is a fix to have setcred() and acct_mgmt()
return PAM_IGNORE if there's nothing for them to do. It's needed, else
things break.

I discovered this when a user who is used to using .rhosts auth could
no longer use rlogin when I PAM_KRB5'ed his servers. Ooops.

> > I was just bitten by a situation where I'd added pam_krb5 to the rlogin
> > service, but pam_rhosts was stacked above it as sufficient, so here
> > there was a situation where pam_krb5:pam_sm_authenticate() might not be
> > called (if rhosts auth succeeded) and so if pam_sm_setcred() returned
> > anything other than PAM_IGNORE or PAM_SUCCESS then rlogin/login would
> > fail.
>
> Yes, this is similar to the problem I have when using pam_krb5 with OpenSSH:
> when I use RSA authentication, openssh calls pam_setcred() without ever
> calling pam_authenticate(), and of course pam_krb5 returns a failure code.
> But whereas it may be more polite for us to return PAM_IGNORE, there is an
> actual bug in openssh that needs to be fixed.

Nope. It's legal to call pam_setcred() without calling
pam_authenticate(), if not as documented, then de facto. Think about
/bin/login -f...

> Under Solaris w/ rlogin, is pam_krb5's pam_sm_setcred() being called even
> though its pam_sm_authenticate() function was never called? Some of your

Yes. Andrew Morgan says this would not be the case with Linux-PAM,
ALTHOUGH, if PAM_KRB5:pam_sm_authenticate() is called and returns
PAM)IGNORE, then PAM_KRB5:pam_sm_setcred() WOULD be called in the
Linux-PAM case.

> comments on the pam-list suggest that Solaris does this. If so, then it
> seems we do need to gracefully handle the case where pam_sm_setcred() is
> called before (or without) pam_sm_authenticate().

Yup.

> > The problem is: how can PAM_KRB5 detect if pam_sm_authenticate() was not
> > called because:
>
> > a) the app didn't call it (e.g. login -f)
>
> Hmm... I think the app is allowed to ignore the return value of
> pam_authenticate(), but I'm not sure the spec allows the app to not call it.
> In this config, pam_krb5 is aware it's configured in 'acceptor' mode,
> correct? So it has enough information about the environment to always do
> the right thing, whether or not pam_authenticate() was called.

How is /bin/login supposed to communicate the -f argument to PAM? So the
user is authenticated, but there is still value in doing setcred() and
acct_mgmt() and firends...

> > or
>
> > b) a sufficient module, higher up the stack *and* sufficient returned
> > PAM_SUCCESS
>
> In which case, does it matter that pam_krb5 doesn't return success? If
> pam_authenticate() didn't need a go-ahead from pam_krb5 in order to succeed,
> why should it care about it when calling pam_setcred()?

Because Solaris PAM calls ALL auth module's setcred() method, regardless
of the return values of the sm_authenticate() calls, or even if some
modules' pam_sm_authenticate() did not get called.

> > And what can pam_krb5:pam_sm_acct_mgmt() do if
> > pam_krb5:pam_sm_authenticate() is not called?!
>
>
> > One answer: nothing, return PAM_IGNORE. In fact, that is the only valid
> > answer, because pam_krb5:pam_sm_acct_mgmt() at the very least needs a
> > principal name to authorize, and if pam_krb5:pam_sm_authenticate()
> > doesn't run then there would be no way for pam_krb5:pam_sm_acct_mgmt()
> > to discover the principal name to authorize.
>
> See above for possible reasons why PAM_IGNORE is not appropriate in this
> situation. I consider the above scenario, in which the app cares about
> pam_krb5's retval from pam_sm_acct_mgmt() but did not call
> pam_authenticate() correctly, to be a bug in either the application or the
> PAM configuration.

It's always appropriate to return PAM_IGNORE if there's nothing the
method can do to satisfy its purpose. This is because PAM_IGNORE cannot
contribute to the success of the stack.

> Steve Langasek
> postmodern programmer

Cheers,

Nico
--

_______________________________________________
Pam-list mailing list
Pam-...@redhat.com
https://listman.redhat.com/mailman/listinfo/pam-list

Steve Langasek

unread,
May 16, 2001, 5:11:13 PM5/16/01
to
On Wed, 16 May 2001, Nicolas Williams wrote:

> When a module returns PAM_IGNORE< it's ignored, EVEN IF it was a
> required module -- i.e., it's treated as if it hadn't even been on the
> stack. Certainly this is how Solaris PAM works. I know, not only
> empirically, but also because I have access to Solaris source code.

> > However, consider this configuration:

> > auth sufficient pam_krb5.so
> > account requisite pam_krb5.so
> > account requisite pam_unix.so

> > This config specifies that pam_krb5 is used for all authentication, and that
> > the user must pass /both/ Kerberos /and/ Unix (shadow) authorization checks
> > in order to gain access. Is this a valid config? If so, what happens when
> > pam_sm_acct_mgmt() returns PAM_IGNORE because it doesn't /know/ if the user
> > is authorized?

> It's ignored, as if it had not even been mentioned in the config.

Exactly, and this is /wrong/. PAM_IGNORE means "I have nothing useful to
contribute". Returning an error when we don't know who the principal is is
not only useful, it's imperative in the case of configs such as the above. If
we want admins to be able to turn this behavior off with a module option,
that's fine, but returning PAM_IGNORE here is not sane default behavior.

If I list two authorization modules as 'requisite' or 'required' in my PAM
config, then by God, I don't want that user to be allowed access to the
service unless both of those modules are *sure* that he should be.

> Consider this:

> rlogin auth sufficient pam_rhosts
> rlogin auth whatever pam_krb5
> rlogin auth whatever pam_unix
> rlogin account required pam_krb5
> rlogin account required pam_unix

> If pam_rhosts succeeds, then pam_krb5:auth will never be tried, but
> pam_krb5:account MUST be tried just in case pam_krb5:auth was tried. So
> pam_krb5:account is tried, but it can't actually *DO* anything, so it
> MUST return PAM_IGNORE.

Only if you accept that the above config is reasonable. This is /not/ a
reasonable config; you've just said that the applicant must pass
authorization checks with both pam_krb5 and pam_unix, but you're allowing them
to authenticate using only pam_rhosts -- so they're not authenticated to the
Kerberos realm, and they /can't/ pass the authorization checks. This is an
inconsistent PAM config, and the config needs to be fixed, not the modules.

rlogin auth sufficient pam_rhosts
rlogin auth whatever pam_krb5
rlogin auth whatever pam_unix

rlogin account optional pam_krb5
rlogin account optional pam_unix

Isn't this what you're really trying to say? Isn't it more straightforward to
simply say this in the config file, rather than opening security holes in the
module that will let crippled apps get by with behavior that shouldn't be
allowed?

> Trust me, Solaris PAM does the right thing, and I believe Linux-PAM must
> as well. The right thing is to treat modules returning PAM_IGNORE as if
> they weren't even on the stack (except that setcred() will be called
> even if auth() returned PAM_IGNORE -- similarly with open/close).

Yes, the PAM libraries handle a PAM_IGNORE retval correctly. What's at issue
is whether it's appropriate for a module to return PAM_IGNORE when we have
reason to believe there's an error which should not be ignored.

> > Under Solaris w/ rlogin, is pam_krb5's pam_sm_setcred() being called even
> > though its pam_sm_authenticate() function was never called? Some of your

> Yes. Andrew Morgan says this would not be the case with Linux-PAM,
> ALTHOUGH, if PAM_KRB5:pam_sm_authenticate() is called and returns
> PAM)IGNORE, then PAM_KRB5:pam_sm_setcred() WOULD be called in the
> Linux-PAM case.

Ok, then pam_krb5 will need to handle this Solaris case.

> > > The problem is: how can PAM_KRB5 detect if pam_sm_authenticate() was not
> > > called because:

> > > a) the app didn't call it (e.g. login -f)

> > Hmm... I think the app is allowed to ignore the return value of
> > pam_authenticate(), but I'm not sure the spec allows the app to not call it.
> > In this config, pam_krb5 is aware it's configured in 'acceptor' mode,
> > correct? So it has enough information about the environment to always do
> > the right thing, whether or not pam_authenticate() was called.

> How is /bin/login supposed to communicate the -f argument to PAM? So the
> user is authenticated, but there is still value in doing setcred() and
> acct_mgmt() and firends...

>From your descriptions of kerberized login in the past, I understood that this
is communicated to PAM by means of the service name -- login will invoke PAM
with a different service name for an already-authenticated user than for one
that still needs to be authenticated.

In which case there's no harm to the application in calling pam_authenticate()
before pam_setcred() and ignoring the result, and there's no harm to the
modules if it's not called; either way, the only things you can do in
pam_setcred() in this scenario are those which /don't/ require
pam_authenticate() to be called successfully, which in fact rules out most
credential-setting activities except for those like 'pam_krb5.so acceptor'.

> > In which case, does it matter that pam_krb5 doesn't return success? If
> > pam_authenticate() didn't need a go-ahead from pam_krb5 in order to succeed,
> > why should it care about it when calling pam_setcred()?

> Because Solaris PAM calls ALL auth module's setcred() method, regardless
> of the return values of the sm_authenticate() calls, or even if some
> modules' pam_sm_authenticate() did not get called.

Ok, so it calls pam_krb5's pam_sm_setcred() function, and this function
returns an error. So what? If that error was insubstantial in
pam_authenticate(), why does it matter now in pam_setcred(), given that
the flow of both function calls is governed by the same PAM config lines?

> > See above for possible reasons why PAM_IGNORE is not appropriate in this
> > situation. I consider the above scenario, in which the app cares about
> > pam_krb5's retval from pam_sm_acct_mgmt() but did not call
> > pam_authenticate() correctly, to be a bug in either the application or the
> > PAM configuration.

> It's always appropriate to return PAM_IGNORE if there's nothing the
> method can do to satisfy its purpose. This is because PAM_IGNORE cannot
> contribute to the success of the stack.

The authorization module's purpose is to guarantee that the applicant is
authorized. Returning PAM_IGNORE when we know the applicant is /not/
authorized is inconsistent with this goal.

Steve Langasek
postmodern programmer

Nicolas Williams

unread,
May 16, 2001, 7:03:07 PM5/16/01
to
On Wed, May 16, 2001 at 04:10:23PM -0500, Steve Langasek wrote:

> On Wed, 16 May 2001, Nicolas Williams wrote:
>
> > It's ignored, as if it had not even been mentioned in the config.
>
> Exactly, and this is /wrong/. PAM_IGNORE means "I have nothing useful to
> contribute". Returning an error when we don't know who the principal is is
> not only useful, it's imperative in the case of configs such as the above. If
> we want admins to be able to turn this behavior off with a module option,
> that's fine, but returning PAM_IGNORE here is not sane default behavior.

I disagree. It's always appropriate to return PAM_IGNORE because it
cannot contribute to success of the stack.

> If I list two authorization modules as 'requisite' or 'required' in my PAM
> config, then by God, I don't want that user to be allowed access to the
> service unless both of those modules are *sure* that he should be.

Well, this is PAM. It's how it works. Perhaps Andrew Morgan can settle
this.

> > Consider this:
>
> > rlogin auth sufficient pam_rhosts
> > rlogin auth whatever pam_krb5
> > rlogin auth whatever pam_unix
> > rlogin account required pam_krb5
> > rlogin account required pam_unix
>
> > If pam_rhosts succeeds, then pam_krb5:auth will never be tried, but
> > pam_krb5:account MUST be tried just in case pam_krb5:auth was tried. So
> > pam_krb5:account is tried, but it can't actually *DO* anything, so it
> > MUST return PAM_IGNORE.
>

> Only if you accept that the above config is reasonable. This is /not/ a
> reasonable config; you've just said that the applicant must pass

It's perfectly reasonable. I said that pam_rhosts is SUFFICIENT for
authentication. That means that if pam_rhosts:auth succeeds then the
other auth modules are NOT even tried.

> authorization checks with both pam_krb5 and pam_unix, but you're allowing them
> to authenticate using only pam_rhosts -- so they're not authenticated to the
> Kerberos realm, and they /can't/ pass the authorization checks. This is an
> inconsistent PAM config, and the config needs to be fixed, not the modules.

Which is why PAM_KRB5:account MUST return PAM_IGNORE in such cases.

> rlogin auth sufficient pam_rhosts
> rlogin auth whatever pam_krb5
> rlogin auth whatever pam_unix

> rlogin account optional pam_krb5
> rlogin account optional pam_unix
>
> Isn't this what you're really trying to say? Isn't it more straightforward to
> simply say this in the config file, rather than opening security holes in the
> module that will let crippled apps get by with behavior that shouldn't be
> allowed?

Nope. There's no security hole there.

Case 1: a) pam_rhosts:auth succeeds, short-circuiting the remainder of
the auth stack
b) pam_krb5:account returns PAM_IGNORE and is ignored
c) pam_unix:account is a pretty simple module and it works as
expected, even though pam_unix:auth was not tried

The other cases also have no bug, but I'd have to pick a value for
"whatever" above to run through all the possibilities.

> > Trust me, Solaris PAM does the right thing, and I believe Linux-PAM must
> > as well. The right thing is to treat modules returning PAM_IGNORE as if
> > they weren't even on the stack (except that setcred() will be called
> > even if auth() returned PAM_IGNORE -- similarly with open/close).
>

> Yes, the PAM libraries handle a PAM_IGNORE retval correctly. What's at issue
> is whether it's appropriate for a module to return PAM_IGNORE when we have
> reason to believe there's an error which should not be ignored.

But it's not an error to have no inputs!

> > > Under Solaris w/ rlogin, is pam_krb5's pam_sm_setcred() being called even
> > > though its pam_sm_authenticate() function was never called? Some of your
>
> > Yes. Andrew Morgan says this would not be the case with Linux-PAM,
> > ALTHOUGH, if PAM_KRB5:pam_sm_authenticate() is called and returns
> > PAM)IGNORE, then PAM_KRB5:pam_sm_setcred() WOULD be called in the
> > Linux-PAM case.
>

> Ok, then pam_krb5 will need to handle this Solaris case.

Yes. But there's no reason to treat this differently on Linux-PAM either.

> > How is /bin/login supposed to communicate the -f argument to PAM? So the
> > user is authenticated, but there is still value in doing setcred() and
> > acct_mgmt() and firends...
>

> >From your descriptions of kerberized login in the past, I understood that this
> is communicated to PAM by means of the service name -- login will invoke PAM
> with a different service name for an already-authenticated user than for one
> that still needs to be authenticated.

No that was just Sun's SEAM login.krb5/PAM_KRB5 stuff. Plain old
/bin/login has always (well, for a very, very long time anyways) had a
-f argument, and the only way to implement that with PAM is to either
skip pam_authenticate() OR use a service name whose auth stack is known
to contain ONLY pam_permit (or the equivalent).

> In which case there's no harm to the application in calling pam_authenticate()
> before pam_setcred() and ignoring the result, and there's no harm to the
> modules if it's not called; either way, the only things you can do in
> pam_setcred() in this scenario are those which /don't/ require
> pam_authenticate() to be called successfully, which in fact rules out most
> credential-setting activities except for those like 'pam_krb5.so acceptor'.

There may be harm because the auth modules may desire to prompt the user/
converse with the app, but there's no valid semantics at that point in
handling such prompts when the user is already authenticated.

And the acceptor thing in Sun's SEAM is a perfect example of why there
can be value to calling setcred() when authenticate() is skipped.

> > Because Solaris PAM calls ALL auth module's setcred() method, regardless
> > of the return values of the sm_authenticate() calls, or even if some
> > modules' pam_sm_authenticate() did not get called.
>

> Ok, so it calls pam_krb5's pam_sm_setcred() function, and this function
> returns an error. So what? If that error was insubstantial in
> pam_authenticate(), why does it matter now in pam_setcred(), given that
> the flow of both function calls is governed by the same PAM config lines?

Because /bin/login will fail if pam_setcred() fails and I can't have
pam_krb5:setcred() treated differently from pam_krb5:authenticate() as
far as required/requisite/... is concerned.

> > It's always appropriate to return PAM_IGNORE if there's nothing the
> > method can do to satisfy its purpose. This is because PAM_IGNORE cannot
> > contribute to the success of the stack.
>

> The authorization module's purpose is to guarantee that the applicant is
> authorized. Returning PAM_IGNORE when we know the applicant is /not/
> authorized is inconsistent with this goal.

Why? Returning PAM_IGNORE *cannot* contribute to success of the stack.
It cannot contribute to allowing the user to login. If not one module in
a stack returns PAM_SUCCESS then the stack will not return PAM_SUCCESS
either.

Steve Langasek

unread,
May 16, 2001, 7:19:59 PM5/16/01
to
Nico,

On Wed, 16 May 2001, Nicolas Williams wrote:

> > > It's ignored, as if it had not even been mentioned in the config.

> > Exactly, and this is /wrong/. PAM_IGNORE means "I have nothing useful to
> > contribute". Returning an error when we don't know who the principal is is
> > not only useful, it's imperative in the case of configs such as the above. If
> > we want admins to be able to turn this behavior off with a module option,
> > that's fine, but returning PAM_IGNORE here is not sane default behavior.

> I disagree. It's always appropriate to return PAM_IGNORE because it
> cannot contribute to success of the stack.

It also will not contribute to the failure of the stack, which is where the
problem lies.

> > Only if you accept that the above config is reasonable. This is /not/ a
> > reasonable config; you've just said that the applicant must pass

> It's perfectly reasonable. I said that pam_rhosts is SUFFICIENT for
> authentication. That means that if pam_rhosts:auth succeeds then the
> other auth modules are NOT even tried.

So in this context, what do the lines

rlogin account required pam_krb5
rlogin account required pam_unix

mean? I believe this should mean that both pam_krb5 and pam_unix must
*approve* the applicant for access. If pam_krb5 is going to punt whenever it
doesn't know what to do, then I have no way to achieve the semantics I'm
looking for.[1] Conversely, there are ways to structure the PAM config to
give you the results you desire without making use of a PAM_IGNORE return code
from pam_krb5.


> > Isn't this what you're really trying to say? Isn't it more straightforward to
> > simply say this in the config file, rather than opening security holes in the
> > module that will let crippled apps get by with behavior that shouldn't be
> > allowed?

> Nope. There's no security hole there.

> Case 1: a) pam_rhosts:auth succeeds, short-circuiting the remainder of
> the auth stack
> b) pam_krb5:account returns PAM_IGNORE and is ignored
> c) pam_unix:account is a pretty simple module and it works as
> expected, even though pam_unix:auth was not tried

> The other cases also have no bug, but I'd have to pick a value for
> "whatever" above to run through all the possibilities.

There's no security hole in your example config, because you're assigning a
different meaning to 'required' than I am. If I have a config of

auth required pam_krb5
account required pam_krb5
account required pam_unix

I have an expectation that the users who are granted access to this service
have valid, non-expired Kerberos accounts *and* valid, non-expired Unix
accounts. If the application calls pam_acct_mgmt() on a different handle than
was used when calling pam_authenticate(), and this triggers pam_krb5 to return
PAM_IGNORE, the user will be granted access. Now, think about what this means
if the user's password expired, and pam_sm_authenticate() stored a token that
should have been passed to pam_sm_acct_mgmt(). If pam_sm_acct_mgmt() says
'no news is good news' and returns PAM_IGNORE, a user with an expired
principal will get access to the service -- something I've explicitly tried to
prevent in my configuration! Not only that, but because we don't have a TGT
for the user (can't get one, the user's password is expired), we don't have
cryptographic proof of the user's identity (the KDC's response could've been
spoofed), but we'd be granting him access to the service anyway!

And because this all traces back to brokenness on the part of the application,
I as an admin may never know about the problem until it's too late.

Returning PAM_IGNORE from pam_sm_setcred() is one thing; this function doesn't
really pose a security risk if something goes wrong. pam_authenticate() and
pam_acct_mgmt(), because they deal with authentication and authorization, must
be treated more cautiously.


> > > Trust me, Solaris PAM does the right thing, and I believe Linux-PAM must
> > > as well. The right thing is to treat modules returning PAM_IGNORE as if
> > > they weren't even on the stack (except that setcred() will be called
> > > even if auth() returned PAM_IGNORE -- similarly with open/close).
> >
> > Yes, the PAM libraries handle a PAM_IGNORE retval correctly. What's at issue
> > is whether it's appropriate for a module to return PAM_IGNORE when we have
> > reason to believe there's an error which should not be ignored.

> But it's not an error to have no inputs!

Yes, it /is/. :) Asking pam_krb5 to authorize a user when she has not first
been authenticated against the Kerberos realm is meaningless, and represents
an error in either the PAM config or the application. If the error should not
be considered fatal, let the admin spell that out in the config. Don't
override the PAM config by denying that there's an error.

> > In which case there's no harm to the application in calling pam_authenticate()
> > before pam_setcred() and ignoring the result, and there's no harm to the
> > modules if it's not called; either way, the only things you can do in
> > pam_setcred() in this scenario are those which /don't/ require
> > pam_authenticate() to be called successfully, which in fact rules out most
> > credential-setting activities except for those like 'pam_krb5.so acceptor'.

> There may be harm because the auth modules may desire to prompt the user/
> converse with the app, but there's no valid semantics at that point in
> handling such prompts when the user is already authenticated.

> And the acceptor thing in Sun's SEAM is a perfect example of why there
> can be value to calling setcred() when authenticate() is skipped.

Ok, so skip pam_authenticate(). If you call pam_setcred() and it works,
everything's fine (this is the case with pam_krb5 acceptor). If you call
pam_setcred() and it fails, it's because you're requiring a module in the auth
section that can't fulfill your setcred() request without first calling
authenticate(). In that case, it sounds like a broken config to me -- why is
a module that needs pam_authenticate() found in the config for an application
that isn't calling pam_authenticate()?


> > Ok, so it calls pam_krb5's pam_sm_setcred() function, and this function
> > returns an error. So what? If that error was insubstantial in
> > pam_authenticate(), why does it matter now in pam_setcred(), given that
> > the flow of both function calls is governed by the same PAM config lines?

> Because /bin/login will fail if pam_setcred() fails and I can't have
> pam_krb5:setcred() treated differently from pam_krb5:authenticate() as
> far as required/requisite/... is concerned.

In the case of pam_krb5 on Solaris, the only possible reason why
pam_krb5:setcred() is being called when pam_krb5:authenticate() was not is if
there's a module listed above pam_krb5 that returned PAM_SUCCESS and
short-circuited the auth stack. IOW,

auth required pam_foo
auth sufficient pam_bar
auth optional pam_blee
auth required pam_krb5

and pam_bar:authenticate() returns PAM_SUCCESS, causing the last two modules
in the stack to be skipped. When the app then calls pam_setcred(), are you
saying that pam_bar:setcred() is going to return something other than
PAM_SUCCESS? That's the only way I see that pam_krb5:setcred()'s return value
would contribute to the return value of pam_setcred() here.

Unless we're talking again about the 'login -f' case, and the problem is
that you have a single PAM config being used both with and without
pam_authenticate(). Honestly, I don't think this can be made to work reliably
without seriously botching things for other applications. login needs to have
two different configurations, with two different service names, because the
configuration requirements when pam_authenticate() is used are different than
those when it is not used.

Cheers,
Steve Langasek
postmodern programmer


[1] Ok, with Linux-PAM, this isn't exactly true. Using Linux-PAM's extended
config syntax, I can map the 'ignore' return code to a failure, but this is
prohibitively complex. I want a solution that works for more than the dozen
Linux admins on the planet who know about this extended config file syntax. :)

Nicolas Williams

unread,
May 16, 2001, 10:34:56 PM5/16/01
to
On Wed, May 16, 2001 at 06:18:29PM -0500, Steve Langasek wrote:
> Nico,

>
> On Wed, 16 May 2001, Nicolas Williams wrote:
>
> > I disagree. It's always appropriate to return PAM_IGNORE because it
> > cannot contribute to success of the stack.
>
> It also will not contribute to the failure of the stack, which is where the
> problem lies.

Sure it does! PAM stacks fail by default.

Here's another way to put it:

- PAM_IGNORE is a device to help cope with lack of expressibility in
pam.conf and the PAM SPI

- some modules present auth, account and other facilities which can be
used separately (e.g., pam_unix).

- some modules' various facilities cannot be used separately (e.g.,
PAM_KRB5)

- there is no way to tie execution of modules in the account stack to
events in the auth stack (and so on)

- so, sometimes you need to be able to neither contribute nor hinder
authentication, authorization, and so on -- thus PAM_IGNORE


> > It's perfectly reasonable. I said that pam_rhosts is SUFFICIENT for
> > authentication. That means that if pam_rhosts:auth succeeds then the
> > other auth modules are NOT even tried.
>

> So in this context, what do the lines
>

> rlogin account required pam_krb5
> rlogin account required pam_unix
>

> mean? I believe this should mean that both pam_krb5 and pam_unix must
> *approve* the applicant for access. If pam_krb5 is going to punt whenever it
> doesn't know what to do, then I have no way to achieve the semantics I'm
> looking for.[1] Conversely, there are ways to structure the PAM config to
> give you the results you desire without making use of a PAM_IGNORE return code
> from pam_krb5.

If the authors of PAM_KRB5 document that PAM_KRB5:account will return
PAM_IGNORE if there is no pam data from PAM_KRB5:auth or
PAM_KRB5:setcred which can be used to perform the authorization check,
then it's ok to return PAM_IGNORE in such circumstances.

Here's what the example you give means:

- if Kerberos password validation was performed, then also perform
Kerberos principal->username authorization

- if no Kerberos password validation was done (e.g., a sufficient auth
module short-circuited the auth stack before pam_krb5), then no
Kerberos authorization check can be performed either

BUT,

- because the admin specified that some other module was sufficient
for auth, that means

- and because we can't kerberos-authorize a principal name we don't
know

- kerberos authorization MUST be skipped

BUT, PAM gives us no way to do this *other than* by returning
PAM_IGNORE.

So it's ok for PAM_KRB5:account to return PAM_IGNORE in this case.

Consider this stack:

rlogin auth sufficient pam_rhosts
rlogin auth required pam_unix
rlogin account required pam_unix
rlogin account required pam_nologin

And now:

rlogin auth sufficient pam_rhosts
rlogin auth required pam_krb5
rlogin auth required pam_unix


rlogin account required pam_krb5
rlogin account required pam_unix

rlogin account required pam_nologin

We've added Kerberos, but we say pam_rhosts is sufficient, so what
happens when pam_rhosts succeeds? The answer: the user should get in,
unless pam_unix or pam_nologin say otherwiise. Kerberos is out of the
picture.

But if pam_rhosts auth fails, then it's another story.

If it were not ok for PAM_KRB5:account to return PAM_IGNORE when it
can't do anything, then the above would NEVER work with rhosts
authentication (that may be a good thing, if you think rhosts is a bad
thing, but that's another story!).

> There's no security hole in your example config, because you're assigning a
> different meaning to 'required' than I am. If I have a config of

I'm making a legal use of PAM_IGNORE to modify required, yes, but only
because you cannot use pam_krb5 to do account checks if you don't use
pam_krb5 to authenticate the user or get his/her credentials.

> auth required pam_krb5
> account required pam_krb5
> account required pam_unix

> I have an expectation that the users who are granted access to this service
> have valid, non-expired Kerberos accounts *and* valid, non-expired Unix
> accounts. If the application calls pam_acct_mgmt() on a different handle than
> was used when calling pam_authenticate(), and this triggers pam_krb5 to return
> PAM_IGNORE, the user will be granted access. Now, think about what this means
> if the user's password expired, and pam_sm_authenticate() stored a token that
> should have been passed to pam_sm_acct_mgmt(). If pam_sm_acct_mgmt() says
> 'no news is good news' and returns PAM_IGNORE, a user with an expired
> principal will get access to the service -- something I've explicitly tried to
> prevent in my configuration! Not only that, but because we don't have a TGT
> for the user (can't get one, the user's password is expired), we don't have
> cryptographic proof of the user's identity (the KDC's response could've been
> spoofed), but we'd be granting him access to the service anyway!

No, no, here pam_krb5:auth is not skipped, therefore pam_krb5:account
will NOT return PAM_IGNORE.

> And because this all traces back to brokenness on the part of the application,
> I as an admin may never know about the problem until it's too late.

No, no, no. Please, step back. PAM_KRB5:account would only return
PAM_IGNORE if PAM_KRB5:auth was not called. That can only happen if: a)
the sysadmin did not put pam_krb5 in the auth stack (stupid) or b)
something higher and suficient in the auth stack caused pam_krb5:auth to
be skipped. In the (b) case pam_krb5:account should not and cannot get
in the way of the other modules in the account stack.

> > But it's not an error to have no inputs!
>

> Yes, it /is/. :) Asking pam_krb5 to authorize a user when she has not first
> been authenticated against the Kerberos realm is meaningless, and represents
> an error in either the PAM config or the application. If the error should not
> be considered fatal, let the admin spell that out in the config. Don't
> override the PAM config by denying that there's an error.

But it's meaningful to make pam_rhosts sufficient ahead of pam_krb5!

[...]

[this is on a different note]

> Unless we're talking again about the 'login -f' case, and the problem is
> that you have a single PAM config being used both with and without
> pam_authenticate(). Honestly, I don't think this can be made to work reliably
> without seriously botching things for other applications. login needs to have
> two different configurations, with two different service names, because the
> configuration requirements when pam_authenticate() is used are different than

> those when it is not used.

I was talking about -f.

> Cheers,
> Steve Langasek
> postmodern programmer
>
>
> [1] Ok, with Linux-PAM, this isn't exactly true. Using Linux-PAM's extended
> config syntax, I can map the 'ignore' return code to a failure, but this is
> prohibitively complex. I want a solution that works for more than the dozen
> Linux admins on the planet who know about this extended config file syntax. :)

If NO module in a stack returns PAM_SUCCESS, the stack fails.

Nicolas Williams

unread,
May 17, 2001, 9:09:52 AM5/17/01
to
Perhaps we can specify the behaviour of PAM_KRB5:account. Here I go:

- pam_krb5:authenticate() MUST record the fact that it's been called
and its return value in pam data

- pam_krb5:authenticate() MUST records, in pam data, wether the user's
password is expired

- IF pam_krb5:authenticate() returned PAM_SUCCESS and the user's
password IS NOT expired then pam_krb5:acct_mgmt() MUST check the user
principal's access to the PAM_USER account as usual

- if pam_krb5:authenticate() returned PAM_SUCCESS and the user's
password IS expired then pam_krb5:acct_mgmt() MUST return
PAM_NEW_AUTHTOK_REQD

- if pam_krb5:authenticate() returned an error, then
pam_krb5:acct_mgmt() MUST NOT return PAM_SUCCESS

- if pam_krb5:authenticate() returned an PAM_IGNORE then
pam_krb5:acct_mgmt() MUST return PAM_IGNORE.

NOTE: pam_krb5:chauthtok() MUST re-authenticate and authorize the user
after changing an expired password. This is because with Kerberos
authentication cannot happen until the expired password is
changed. The easiest way to do this is to call
pam_krb5:authenticate() and pam_krb5:acct_mgmt() from within
pam_krb5:chauthtok() after changing the expired password.

NOTE: pam_krb5:authenticate() MUST reset those state flags when it
starts as it can be called more than once (i.e., if the app calls
pam_authenticate() more than once on the sam pam handle). It does
not currently make sense to stack pam_krb5 more than once in a pam
stack.

Cheers,

Nico

On Wed, May 16, 2001 at 10:30:26PM -0400, Nicolas Williams wrote:
> On Wed, May 16, 2001 at 06:18:29PM -0500, Steve Langasek wrote:
> > Nico,
> >

> > On Wed, 16 May 2001, Nicolas Williams wrote:
> >
> > > I disagree. It's always appropriate to return PAM_IGNORE because it
> > > cannot contribute to success of the stack.
> >

> > It also will not contribute to the failure of the stack, which is where the
> > problem lies.
>
> Sure it does! PAM stacks fail by default.
>
> Here's another way to put it:
>
> - PAM_IGNORE is a device to help cope with lack of expressibility in
> pam.conf and the PAM SPI
>
> - some modules present auth, account and other facilities which can be
> used separately (e.g., pam_unix).
>
> - some modules' various facilities cannot be used separately (e.g.,
> PAM_KRB5)
>
> - there is no way to tie execution of modules in the account stack to
> events in the auth stack (and so on)
>
> - so, sometimes you need to be able to neither contribute nor hinder
> authentication, authorization, and so on -- thus PAM_IGNORE
>
>

> > > It's perfectly reasonable. I said that pam_rhosts is SUFFICIENT for
> > > authentication. That means that if pam_rhosts:auth succeeds then the
> > > other auth modules are NOT even tried.
> >

> > So in this context, what do the lines
> >

> > rlogin account required pam_krb5
> > rlogin account required pam_unix
> >

> rlogin auth sufficient pam_rhosts


> rlogin auth required pam_unix
> rlogin account required pam_unix
> rlogin account required pam_nologin
>
> And now:
>

> rlogin auth sufficient pam_rhosts
> rlogin auth required pam_krb5
> rlogin auth required pam_unix


> rlogin account required pam_krb5
> rlogin account required pam_unix

> > > But it's not an error to have no inputs!
> >

> > Yes, it /is/. :) Asking pam_krb5 to authorize a user when she has not first
> > been authenticated against the Kerberos realm is meaningless, and represents
> > an error in either the PAM config or the application. If the error should not
> > be considered fatal, let the admin spell that out in the config. Don't
> > override the PAM config by denying that there's an error.
>
> But it's meaningful to make pam_rhosts sufficient ahead of pam_krb5!
>
> [...]
>
> [this is on a different note]
>
> > Unless we're talking again about the 'login -f' case, and the problem is
> > that you have a single PAM config being used both with and without
> > pam_authenticate(). Honestly, I don't think this can be made to work reliably
> > without seriously botching things for other applications. login needs to have
> > two different configurations, with two different service names, because the
> > configuration requirements when pam_authenticate() is used are different than
> > those when it is not used.
>
> I was talking about -f.
>
> > Cheers,
> > Steve Langasek
> > postmodern programmer
> >
> >
> > [1] Ok, with Linux-PAM, this isn't exactly true. Using Linux-PAM's extended
> > config syntax, I can map the 'ignore' return code to a failure, but this is
> > prohibitively complex. I want a solution that works for more than the dozen
> > Linux admins on the planet who know about this extended config file syntax. :)
>

> If NO module in a stack returns PAM_SUCCESS, the stack fails.

Nicolas Williams

unread,
May 17, 2001, 9:20:54 AM5/17/01
to
I left something out: the original issue of this thread. Inline.


On Thu, May 17, 2001 at 09:04:05AM -0400, Nicolas Williams wrote:
> Perhaps we can specify the behaviour of PAM_KRB5:account. Here I go:
>
> - pam_krb5:authenticate() MUST record the fact that it's been called
> and its return value in pam data
>
> - pam_krb5:authenticate() MUST records, in pam data, wether the user's
> password is expired
>
> - IF pam_krb5:authenticate() returned PAM_SUCCESS and the user's
> password IS NOT expired then pam_krb5:acct_mgmt() MUST check the user
> principal's access to the PAM_USER account as usual
>
> - if pam_krb5:authenticate() returned PAM_SUCCESS and the user's
> password IS expired then pam_krb5:acct_mgmt() MUST return
> PAM_NEW_AUTHTOK_REQD
>
> - if pam_krb5:authenticate() returned an error, then
> pam_krb5:acct_mgmt() MUST NOT return PAM_SUCCESS
>
> - if pam_krb5:authenticate() returned an PAM_IGNORE then
> pam_krb5:acct_mgmt() MUST return PAM_IGNORE.

- if pam_krb5:authenticate() was not called then pam_krb5:acct_mgmt()
MUST return PAM_IGNORE.

This item changes radically if we do the thing that SEAM's PAM_KRB5
does. I.e., if PAM is used in the case of kerberos-network-
authenticated telnet (and the like) then the authenticated user
principal name MUST be made available to pam_krb5:acct_mgmt()
somehow (PAM_RUSER?).

> NOTE: pam_krb5:chauthtok() MUST re-authenticate and authorize the user
> after changing an expired password. This is because with Kerberos
> authentication cannot happen until the expired password is
> changed. The easiest way to do this is to call
> pam_krb5:authenticate() and pam_krb5:acct_mgmt() from within
> pam_krb5:chauthtok() after changing the expired password.
>
> NOTE: pam_krb5:authenticate() MUST reset those state flags when it
> starts as it can be called more than once (i.e., if the app calls
> pam_authenticate() more than once on the sam pam handle). It does
> not currently make sense to stack pam_krb5 more than once in a pam
> stack.

Andrew Morgan

unread,
May 25, 2001, 12:55:07 PM5/25/01
to
Nicolas Williams wrote:
> > Exactly, and this is /wrong/. PAM_IGNORE means "I have nothing useful to
> > contribute". Returning an error when we don't know who the principal is is
> > not only useful, it's imperative in the case of configs such as the above. If
> > we want admins to be able to turn this behavior off with a module option,
> > that's fine, but returning PAM_IGNORE here is not sane default behavior.
>
> I disagree. It's always appropriate to return PAM_IGNORE because it
> cannot contribute to success of the stack.
>
> > If I list two authorization modules as 'requisite' or 'required' in my PAM
> > config, then by God, I don't want that user to be allowed access to the
> > service unless both of those modules are *sure* that he should be.
>
> Well, this is PAM. It's how it works. Perhaps Andrew Morgan can settle
> this.

There are some modules that cannot be used for authentication. Those
modules are supposed to be the ones that return PAM_IGNORE. pam_nologin
seems like a good example of this sort of thing.

There is also a control token of 'optional' that permits an admin to
take an authenticating module (which returns pass/fail) and make it
irrelevant to whether the user gets authenticated or not.

I believe Steve's concern is that, in Nicolas' scheme, a simple stack
like this:

auth requisite pam_ruser_rhost_is_trusted
auth required pam_krb5

will succeed - even if the user is unknown to kerberos. This sort of
thing looks very wrong to me. I believe that pam_krb5 gets called as an
auth module it should pass/fail within its own sphere of knowledge.
PAM_IGNORE, might be a legitimate alternative to PAM_USER_UNKNOWN only
if forced by some pam_krb5 module argument - which implies that the
admin has read the documentation and knows what they are doing.

> > > > Under Solaris w/ rlogin, is pam_krb5's pam_sm_setcred() being called even
> > > > though its pam_sm_authenticate() function was never called? Some of your
> >
> > > Yes. Andrew Morgan says this would not be the case with Linux-PAM,
> > > ALTHOUGH, if PAM_KRB5:pam_sm_authenticate() is called and returns
> > > PAM)IGNORE, then PAM_KRB5:pam_sm_setcred() WOULD be called in the
> > > Linux-PAM case.

Actually, I (should have - I can't remember if I actually did) said that
pam_krb5:pam_sm_setcred() gets called iff pam_krb5:pam_sm_authenticate()
was called. The return code of pam_krb5:pam_sm_authenticate() is not
important. If pam_authenticate() led to libpam invoking
pam_krb5:pam_sm_authenticate(), then pam_setcred() when called, will
definitely invoke pam_krb5:pam_sm_setcred(). [The path through the
'auth' configuration for the setcred stack evaluation is defined by the
path taken during the authenticate stack evaluation.]

Cheers

Andrew

Nicolas Williams

unread,
May 25, 2001, 1:20:51 PM5/25/01
to
On Fri, May 25, 2001 at 09:54:11AM -0700, Andrew Morgan wrote:
> Nicolas Williams wrote:
>
> There are some modules that cannot be used for authentication. Those
> modules are supposed to be the ones that return PAM_IGNORE. pam_nologin
> seems like a good example of this sort of thing.
>
> There is also a control token of 'optional' that permits an admin to
> take an authenticating module (which returns pass/fail) and make it
> irrelevant to whether the user gets authenticated or not.

Optional does not make the module irrelevant. If there's no
required/requisite modules on the stack, then a single successful
optional module suffices for the stack to succeed.

> I believe Steve's concern is that, in Nicolas' scheme, a simple stack
> like this:
>
> auth requisite pam_ruser_rhost_is_trusted
> auth required pam_krb5

What is pam_ruser_rhost_is_trusted? pam_rhosts? The idea is for it to be
sufficient. Making it requisite breaks the model.

I think that Steve would agree to a different observation/proposal I
made on the pam-krb5 list (he's not responded -- silence denotes consent
:).

That is this:

- it is not incorrect to call pam_krb5:account without calling
pam_krb5:auth, it's just meaningless, but nonetheless allowable

- it IS incorrect to call pam_krb5:auth without also calling
pam_krb5:account, in the same pam handle

- if desired we can add code to detect the second item above and
complain loudly.

> will succeed - even if the user is unknown to kerberos. This sort of
> thing looks very wrong to me. I believe that pam_krb5 gets called as an
> auth module it should pass/fail within its own sphere of knowledge.
> PAM_IGNORE, might be a legitimate alternative to PAM_USER_UNKNOWN only
> if forced by some pam_krb5 module argument - which implies that the
> admin has read the documentation and knows what they are doing.

Right.

> > > > > Under Solaris w/ rlogin, is pam_krb5's pam_sm_setcred() being called even
> > > > > though its pam_sm_authenticate() function was never called? Some of your
> > >
> > > > Yes. Andrew Morgan says this would not be the case with Linux-PAM,
> > > > ALTHOUGH, if PAM_KRB5:pam_sm_authenticate() is called and returns
> > > > PAM)IGNORE, then PAM_KRB5:pam_sm_setcred() WOULD be called in the
> > > > Linux-PAM case.
>

> Actually, I (should have - I can't remember if I actually did) said that
> pam_krb5:pam_sm_setcred() gets called iff pam_krb5:pam_sm_authenticate()
> was called. The return code of pam_krb5:pam_sm_authenticate() is not
> important. If pam_authenticate() led to libpam invoking
> pam_krb5:pam_sm_authenticate(), then pam_setcred() when called, will
> definitely invoke pam_krb5:pam_sm_setcred(). [The path through the
> 'auth' configuration for the setcred stack evaluation is defined by the
> path taken during the authenticate stack evaluation.]

I thought that is what I said you said. Isn't it?

I take advantage of this behaviour in our pam_krb5. By default, if
there's no keytab with which to validate a user's Kerberos credentials
then pam_krb5:auth returns PAM_IGNORE (since it cannot really validate
the password), but it does fetch Kerberos credentials, if possible, so
that pam_krb5:setcred() can create a ccache. In such situations pam_krb5
acts as a convinience kinit and cannot contribute to actually
authenticating the user.

> Cheers
>
> Andrew

Andrew Morgan

unread,
May 25, 2001, 3:01:10 PM5/25/01
to
Nicolas Williams wrote:
>
> On Fri, May 25, 2001 at 09:54:11AM -0700, Andrew Morgan wrote:
> > Nicolas Williams wrote:
> >
> > There are some modules that cannot be used for authentication. Those
> > modules are supposed to be the ones that return PAM_IGNORE. pam_nologin
> > seems like a good example of this sort of thing.
> >
> > There is also a control token of 'optional' that permits an admin to
> > take an authenticating module (which returns pass/fail) and make it
> > irrelevant to whether the user gets authenticated or not.
>
> Optional does not make the module irrelevant. If there's no
> required/requisite modules on the stack, then a single successful
> optional module suffices for the stack to succeed.

Yes, I guess that is fair. But, in the case where your module returns
PAM_SUCCESS or PAM_IGNORE (in lieu of PAM_PERM_DENIED), I believe the
'optional' control token is an admin way of obtaining the result you
want.

> > I believe Steve's concern is that, in Nicolas' scheme, a simple stack
> > like this:
> >
> > auth requisite pam_ruser_rhost_is_trusted
> > auth required pam_krb5
>
> What is pam_ruser_rhost_is_trusted? pam_rhosts? The idea is for it to be

I made it up. Its a module that doesn't care what PAM_USER is, just that
PAM_RUSER and PAM_RHOST are known to the system as requesting users that
are not denied access the service.

> sufficient. Making it requisite breaks the model.

What model? The modules are supposed to be generic authentication
machines, my concern is that by returning PAM_IGNORE, you are making an
assumption that krb5 is not the only authentication module in the stack
that requires that the PAM_USER exists.

> I think that Steve would agree to a different observation/proposal I
> made on the pam-krb5 list (he's not responded -- silence denotes consent
>:).
>
> That is this:
>
> - it is not incorrect to call pam_krb5:account without calling
> pam_krb5:auth, it's just meaningless, but nonetheless allowable
>
> - it IS incorrect to call pam_krb5:auth without also calling
> pam_krb5:account, in the same pam handle
>
> - if desired we can add code to detect the second item above and
> complain loudly.

What has this got to do with the PAM_IGNORE return code for
pam_sm_authenticate()?

> > Actually, I (should have - I can't remember if I actually did) said that
> > pam_krb5:pam_sm_setcred() gets called iff pam_krb5:pam_sm_authenticate()
> > was called. The return code of pam_krb5:pam_sm_authenticate() is not
> > important. If pam_authenticate() led to libpam invoking
> > pam_krb5:pam_sm_authenticate(), then pam_setcred() when called, will
> > definitely invoke pam_krb5:pam_sm_setcred(). [The path through the
> > 'auth' configuration for the setcred stack evaluation is defined by the
> > path taken during the authenticate stack evaluation.]
>
> I thought that is what I said you said. Isn't it?

Your remark implied that PAM_IGNORE was in some way special. I wanted to
point out that if the pam_sm_authenticate() function returned anything
at all, it was guaranteed to cause pam_sm_setcred to be invoked.

> I take advantage of this behaviour in our pam_krb5. By default, if
> there's no keytab with which to validate a user's Kerberos credentials
> then pam_krb5:auth returns PAM_IGNORE (since it cannot really validate
> the password), but it does fetch Kerberos credentials, if possible, so
> that pam_krb5:setcred() can create a ccache. In such situations pam_krb5
> acts as a convinience kinit and cannot contribute to actually
> authenticating the user.

Since I'm not all that clueful about kerberos, I don't really understand
how one could not authenticate a user and yet successfully fetch a
user's credentials... Perhaps I should let Steve continue to speak for
himself...?

Cheers

Andrew

Nicolas Williams

unread,
May 25, 2001, 3:32:28 PM5/25/01
to
On Fri, May 25, 2001 at 11:56:09AM -0700, Andrew Morgan wrote:
> Nicolas Williams wrote:
> >
> > On Fri, May 25, 2001 at 09:54:11AM -0700, Andrew Morgan wrote:
> > > Nicolas Williams wrote:
> > Optional does not make the module irrelevant. If there's no
> > required/requisite modules on the stack, then a single successful
> > optional module suffices for the stack to succeed.
>
> Yes, I guess that is fair. But, in the case where your module returns
> PAM_SUCCESS or PAM_IGNORE (in lieu of PAM_PERM_DENIED), I believe the
> 'optional' control token is an admin way of obtaining the result you
> want.

I suppuse an "insufficient" specifier might be useful...

> > sufficient. Making it requisite breaks the model.
>
> What model? The modules are supposed to be generic authentication
> machines, my concern is that by returning PAM_IGNORE, you are making an
> assumption that krb5 is not the only authentication module in the stack
> that requires that the PAM_USER exists.

The model we were discussing, whereby successful pam_rhosts should
suffice, but when it fails then pam_krb5 authentication should be
required. The issue is that in such cases, though pam_krb5's
pam_sm_authenticate() is NOT called, it's pam_sm_acct_mgmt() would still
be called:

auth sufficient pam_rhosts


auth required pam_krb5
account required pam_krb5

...

> > I think that Steve would agree to a different observation/proposal I
> > made on the pam-krb5 list (he's not responded -- silence denotes consent
> >:).
> >
> > That is this:
> >
> > - it is not incorrect to call pam_krb5:account without calling
> > pam_krb5:auth, it's just meaningless, but nonetheless allowable
> >
> > - it IS incorrect to call pam_krb5:auth without also calling
> > pam_krb5:account, in the same pam handle
> >
> > - if desired we can add code to detect the second item above and
> > complain loudly.
>
> What has this got to do with the PAM_IGNORE return code for
> pam_sm_authenticate()?

Nothing -- it's to do with pam_sm_acct_mgmt() returning PAM_IGNORE. See
above.

My contention is that pam_krb5:pam_sm_acct_mgmt() should return
PAM_IGNORE if pam_krb5:pam_sm_authenticate() is not called (see above
for an example).

> > I thought that is what I said you said. Isn't it?
>
> Your remark implied that PAM_IGNORE was in some way special. I wanted to
> point out that if the pam_sm_authenticate() function returned anything
> at all, it was guaranteed to cause pam_sm_setcred to be invoked.

Ok.

> > I take advantage of this behaviour in our pam_krb5. By default, if
> > there's no keytab with which to validate a user's Kerberos credentials
> > then pam_krb5:auth returns PAM_IGNORE (since it cannot really validate
> > the password), but it does fetch Kerberos credentials, if possible, so
> > that pam_krb5:setcred() can create a ccache. In such situations pam_krb5
> > acts as a convinience kinit and cannot contribute to actually
> > authenticating the user.
>
> Since I'm not all that clueful about kerberos, I don't really understand
> how one could not authenticate a user and yet successfully fetch a
> user's credentials... Perhaps I should let Steve continue to speak for
> himself...?

Because, with Kerberos you authenticate to the KDC to get your
credentials, but the credentials aren't signed with a KDC public key
(there's no such thing currently) so authenticating to the KDC does not
imply authenticating to your local host!

To authenticate to the local host you must use your credentials to get a
service ticket that your local host can validate, and that requires that
your host have a Kerberos service account. It's valid to run a Kerberos
realm where some hosts have no such account, and thus have no way to use
Kerberos to validate passwords and authenticate users.

Yes, it's somewhat odd. But it works, and well.

Similarly, expired passwords can't be validated with Kerberos until
they are changed -- this is because expired password can only be used
to get service tickets to the password changing service, and such
tickets cannot be used to authenticate to the local host. This is why
our pam_krb5's (devl branch) pam_sm_chauthtok() calls its
pam_sm_authenticate() and pam_sm_acct_mgmt() after changing an expired
password!

Just as there's an error, PAM_NEW_AUTHTOK_REQD, that pam_acct_mgmt() can
return to indicate that the app should call pam_chauthtok(), methinks
there could be an error which pam_chauthtok() can return to indicate
that the user should be re-authenticated/re-authorized. But, as you can
see, one can work around the absence of such an error.

> Cheers
>
> Andrew

Steve Langasek

unread,
May 28, 2001, 3:51:52 PM5/28/01
to
On Fri, 25 May 2001, Andrew Morgan wrote:

> > > If I list two authorization modules as 'requisite' or 'required' in my PAM
> > > config, then by God, I don't want that user to be allowed access to the
> > > service unless both of those modules are *sure* that he should be.

> > Well, this is PAM. It's how it works. Perhaps Andrew Morgan can settle
> > this.

> There are some modules that cannot be used for authentication. Those
> modules are supposed to be the ones that return PAM_IGNORE. pam_nologin
> seems like a good example of this sort of thing.

> There is also a control token of 'optional' that permits an admin to
> take an authenticating module (which returns pass/fail) and make it
> irrelevant to whether the user gets authenticated or not.

> I believe Steve's concern is that, in Nicolas' scheme, a simple stack
> like this:

> auth requisite pam_ruser_rhost_is_trusted
> auth required pam_krb5

> will succeed - even if the user is unknown to kerberos. This sort of
> thing looks very wrong to me. I believe that pam_krb5 gets called as an
> auth module it should pass/fail within its own sphere of knowledge.
> PAM_IGNORE, might be a legitimate alternative to PAM_USER_UNKNOWN only
> if forced by some pam_krb5 module argument - which implies that the
> admin has read the documentation and knows what they are doing.

I think all the salient arguments have also been made on the pam-krb5 list
now, but this does nicely summarize the issue. I greatly prefer that the
default behavior inconvenience some admins by denying access to some of their
users who should be allowed, than that it inconvenience others by allowing
access to users who should be denied. That such a situation depends on the
presence of buggy applications, and that the behavior of pam_krb5 is
documented, will be of little comfort to the admin who finds his system
security compromised.

Steve Langasek
postmodern programmer

0 new messages