Discussion:
Can I execute a script _after_ PAP authentication is complete?
(too old to reply)
Chris Nelson
2006-05-25 19:10:51 UTC
Permalink
I'm using mgetty to answer the phone for a dial-in PPP connection. It
recognizes caller ID and puts the caller's phone number in $CALLER_ID.
So far so good.

I want to set up security based on the combination of caller's phone
number and user name but the program invoked by /AutoPPP/ in mgetty's
login.config doesn't know the user. If I put the PPP users into
/etc/passwd, I could use login and a custom shell which checked the
user ID and caller ID and acted accordingly. But I'd really prefer to
keep my PPP users and system users separate so I have my PPP users only
in pap-secrets (and I use papcrypt and require-pap in my options file).

So, it there any way to have a script invoked _after_ PAP
authentication? Presumably at that point, CALLER_ID would still be in
the environment and, I'd hope, the PPP user name would be available
somehow so I could act on the combination of those two values.

Chris
James Carlson
2006-05-25 19:35:59 UTC
Permalink
Post by Chris Nelson
So, it there any way to have a script invoked _after_ PAP
authentication? Presumably at that point, CALLER_ID would still be in
the environment and, I'd hope, the PPP user name would be available
somehow so I could act on the combination of those two values.
There are at least two ways to do this. One is listed in the pppd man
page -- see the "/etc/ppp/auth-up" script.

The other is to write a program (a "plugin" dynamically linked module)
that uses the existing 'pap_auth_hook' feature in pppd.

I suspect it's really this latter one that you'll want to use.
--
James Carlson, KISS Network <***@sun.com>
Sun Microsystems / 1 Network Drive 71.232W Vox +1 781 442 2084
MS UBUR02-212 / Burlington MA 01803-2757 42.496N Fax +1 781 442 1677
Chris Nelson
2006-05-26 11:32:19 UTC
Permalink
Post by James Carlson
Post by Chris Nelson
So, it there any way to have a script invoked _after_ PAP
authentication? Presumably at that point, CALLER_ID would still be in
the environment and, I'd hope, the PPP user name would be available
somehow so I could act on the combination of those two values.
There are at least two ways to do this.
At least. I found a third, possibily kludgey way: ip-up. ;-)
Post by James Carlson
One is listed in the pppd man page -- see the "/etc/ppp/auth-up" script.
Thanks. I found that now. I was looking in the Files section, not
Scripts.
Post by James Carlson
The other is to write a program (a "plugin" dynamically linked module)
that uses the existing 'pap_auth_hook' feature in pppd.
I suspect it's really this latter one that you'll want to use.
Why the latter? Building a binary plug-in seems a *lot* more work than
writing a script. Is it just that it's a more secure mechanism (the
code can't be read, even if the file can be seen)? Also, while I said
"after PAP authentication" I really meant just authentication; I'm
using PAP now but I'd rather be flexible in case I add/use another
method later.

It seems to me that by using ip-up, I can secure against
misconfiguration or hacking so that if someone gets in without
authentication I can trap it and drop the link in ip-up. If I put my
code in auth-up then if noauth gets into the mix my code won't get
executed. Right?

So this is what I've done. Since ip-up "runs in a deliberately
restricted environment to enhance security" (http://tinyurl.com/nx2dg),
I had to do some calisthenics to get CALLER_ID from mgetty to ip-up. I
added two lines to the standard /etc/ppp/ppplogin:

#!/bin/sh
stty -echo
echo "CALLER_ID=$CALLER_ID;export CALLER_ID" >/etc/ppp/cid.$DEVICE
/usr/sbin/pppd silent auth -chap +pap
rm /etc/ppp/cid.$DEVICE

I haven't yet coded the logic to act on the information but so far my
ip-up has:

#!/bin/sh
. /etc/ppp/cid.`basename $DEVICE`
echo "Remote user \"$PEERNAME\" logged in from phone number
\"$CALLER_ID\""

I imagine the same code could be in auth-up.

Chris
James Carlson
2006-05-29 03:50:21 UTC
Permalink
Post by Chris Nelson
Post by James Carlson
Post by Chris Nelson
authentication? Presumably at that point, CALLER_ID would still be in
the environment and, I'd hope, the PPP user name would be available
somehow so I could act on the combination of those two values.
[...]
Post by Chris Nelson
Post by James Carlson
I suspect it's really this latter one that you'll want to use.
Why the latter? Building a binary plug-in seems a *lot* more work than
writing a script. Is it just that it's a more secure mechanism (the
code can't be read, even if the file can be seen)? Also, while I said
No, that's not the reason.

The reason is that it sounds like you want to make the access decision
based on a combination of factors -- the authentication data supplied
by the peer *plus* some additional factors.

In order to do that correctly, you need to be synchronous with the
rest of the framework operation. If you use auth-up (or, worse,
ip-up), then the "bad" user who authenticates correctly but is calling
from the wrong location will be able to gain access for a short period
of time before your script runs, you find the problem, and you kill
off the connection.

You're introducing an unnecessary race condition.
Post by Chris Nelson
"after PAP authentication" I really meant just authentication; I'm
using PAP now but I'd rather be flexible in case I add/use another
method later.
Sure. auth-up works for both, though it's not what you really need
here.
Post by Chris Nelson
It seems to me that by using ip-up, I can secure against
misconfiguration or hacking so that if someone gets in without
authentication I can trap it and drop the link in ip-up. If I put my
code in auth-up then if noauth gets into the mix my code won't get
executed. Right?
How exactly does "noauth" get "into the mix?" It needs to be added by
someone with root privileges -- all of the files that can specify that
option are writable only by root. If it's getting "into the mix," I
think it means that you have a root user who is vandalizing the
system. All bets are off if that happens, as such a user can scribble
on /dev/kmem.

In any event, if you want to use it with "noauth" (relying on just
some external data to authenticate the connection, and nothing else),
then the same sorts of issues apply, though the regular PAP auth hook
won't work. I think you'll need to modify the main pppd code to do
that correctly.
Post by Chris Nelson
echo "CALLER_ID=$CALLER_ID;export CALLER_ID" >/etc/ppp/cid.$DEVICE
Nit: use /var instead. I also suggest that you just write the value
itself into the file, and read it back, rather than using "." to
execute that file. Executing dynamically-created content can be a bit
hazardous.
Post by Chris Nelson
/usr/sbin/pppd silent auth -chap +pap
That might not do what you're expecting. "+pap" is the deprecated
(obsolete) alias of the "require-pap" option. It causes pppd to
demand PAP from the peer.

However, "-chap" is "refuse-chap." That means that if the peer asks
us to identify *ourselves* using CHAP, we'll refuse. Do your clients
ask your server for authentication? That's not often done.

The +/- flags here are not at all symmetric in operation.

Also note that "silent" likely doesn't do anything good here. This
should *not* have to be done. If it does, then it sounds like there
are bugs somewhere.
Post by Chris Nelson
I imagine the same code could be in auth-up.
The problem is (still) that those scripts are fired off by pppd when
the event occurs, but that the PPP link itself intentionally isn't
"paused" to wait for them to complete.

If you're trying to add another authentication factor, this isn't the
place to do it.
--
James Carlson, KISS Network <***@sun.com>
Sun Microsystems / 1 Network Drive 71.232W Vox +1 781 442 2084
MS UBUR02-212 / Burlington MA 01803-2757 42.496N Fax +1 781 442 1677
Chris Nelson
2006-06-05 14:17:27 UTC
Permalink
Post by James Carlson
The reason is that it sounds like you want to make the access decision
based on a combination of factors -- the authentication data supplied
by the peer *plus* some additional factors.
In order to do that correctly, you need to be synchronous with the
rest of the framework operation. ...
OK. I see what you're saying.
Post by James Carlson
Post by Chris Nelson
echo "CALLER_ID=$CALLER_ID;export CALLER_ID" >/etc/ppp/cid.$DEVICE
Nit: use /var instead.
OK.
Post by James Carlson
I also suggest that you just write the value
itself into the file, and read it back, rather than using "." to
execute that file. Executing dynamically-created content can be a bit
hazardous.
A valid point. What I showed was an first draft. Thanks.
Post by James Carlson
...
Post by Chris Nelson
I imagine the same code could be in auth-up.
The problem is (still) that those scripts are fired off by pppd when
the event occurs, but that the PPP link itself intentionally isn't
"paused" to wait for them to complete.
If you're trying to add another authentication factor, this isn't the
place to do it.
OK. So I'm writing a plugin to set the ppp_auth_hook. My code uses
stdbool.h which conflicts with pppd.h's bool typedef. Any thoughts...?
James Carlson
2006-06-05 14:44:54 UTC
Permalink
Post by Chris Nelson
Post by James Carlson
If you're trying to add another authentication factor, this isn't the
place to do it.
OK. So I'm writing a plugin to set the ppp_auth_hook. My code uses
stdbool.h which conflicts with pppd.h's bool typedef. Any thoughts...?
Two possibilities:

- split your code into two or more .c files, with dedicated pppd
glue logic in one file, and the internals of your implementation
in another, and then 'ld -r' them into a single module.

- "don't do that" (i.e., just don't use stdbool.h)
--
James Carlson, KISS Network <***@sun.com>
Sun Microsystems / 1 Network Drive 71.232W Vox +1 781 442 2084
MS UBUR02-212 / Burlington MA 01803-2757 42.496N Fax +1 781 442 1677
Chris Nelson
2006-06-05 14:50:16 UTC
Permalink
Post by James Carlson
Post by Chris Nelson
Post by James Carlson
If you're trying to add another authentication factor, this isn't the
place to do it.
OK. So I'm writing a plugin to set the ppp_auth_hook. My code uses
stdbool.h which conflicts with pppd.h's bool typedef. Any thoughts...?
- split your code into two or more .c files, with dedicated pppd
glue logic in one file, and the internals of your implementation
in another, and then 'ld -r' them into a single module.
I guess.
Post by James Carlson
- "don't do that" (i.e., just don't use stdbool.h)
Thanks. :-/

Is there some reason pppd doesn't use stdbool.h?


Another question: certain users should be called back. I've got a
sketch of a ppp_auth_hook that looks like:

// search my users for a record with a matching user
// if not found, return NOT_AUTHENTICATED

// compare passwords
// if password doesn't match, return NOT_AUTHENTICATED

// if no callback and no caller id, return AUTHENTICATED

// if caller ID and numbers don't match, return NOT_AUTHENTICATED

// if callback
// FIXME - what to do?

It seems that even if I'm going to call back, the user is
authenticated. I can use system() to invoke another program to call
back but I don't quite see how to make pppd drop the line. I don't
think the idle hook would come into play but maybe I don't understand
it yet.
James Carlson
2006-06-05 15:18:19 UTC
Permalink
Post by Chris Nelson
Thanks. :-/
Is there some reason pppd doesn't use stdbool.h?
It's historical: pppd greatly predates that file being part of any
standard (as well as Linux and a number of other things). It's still
that way as a portability issue, but if someone wanted to work through
those issues and contribute well-tested fixes, I'm sure we'd be happy
to have them.
Post by Chris Nelson
Another question: certain users should be called back. I've got a
For what it's worth, we have _only_ the client portion of Microsoft's
proprietary CBCP in pppd. If you need the server side of CBCP, you'll
need to do more work here.
Post by Chris Nelson
It seems that even if I'm going to call back, the user is
authenticated. I can use system() to invoke another program to call
back but I don't quite see how to make pppd drop the line. I don't
think the idle hook would come into play but maybe I don't understand
it yet.
No, none of that will work. pppd just isn't currently designed to do
the server side of callback.

There are at least two ways this can be done.

- Classic callback comes in two minor flavors:

- One involves just noting the calling party information, waiting
a few moments, and then calling that party back. There's just
one PPP link, and no authentication (other than the telco-
supplied calling party data, if you trust that) on the
initiating dial.

- The other involves doing the authentication (and authorization)
checks (PPP or otherwise), dropping the line, waiting a couple
of seconds for the telephone link to recover, and then
initiating a regular call back to the user.

- Windows proprietary callback involves doing the same, but then
running CBCP negotiation after authenticating but before dropping
the link. After doing CBCP, you hang up, wait a while, and then
call the user back. I think you're supposed to avoid doing CBCP
on the callback itself.

In any case, you should redo the authentication on the callback, so
that if the telephone link is compromised, you don't accidentally
allow an attacker in without authentication.
--
James Carlson, KISS Network <***@sun.com>
Sun Microsystems / 1 Network Drive 71.232W Vox +1 781 442 2084
MS UBUR02-212 / Burlington MA 01803-2757 42.496N Fax +1 781 442 1677
Chris Nelson
2006-06-05 15:28:50 UTC
Permalink
Post by James Carlson
Post by Chris Nelson
Thanks. :-/
Is there some reason pppd doesn't use stdbool.h?
It's historical: pppd greatly predates that file being part of any
standard (as well as Linux and a number of other things). It's still
that way as a portability issue, but if someone wanted to work through
those issues and contribute well-tested fixes, I'm sure we'd be happy
to have them.
Not this week.
Post by James Carlson
Post by Chris Nelson
Another question: certain users should be called back. I've got a
...
Post by Chris Nelson
It seems that even if I'm going to call back, the user is
authenticated. I can use system() to invoke another program to call
back but I don't quite see how to make pppd drop the line. I don't
think the idle hook would come into play but maybe I don't understand
it yet.
No, none of that will work. pppd just isn't currently designed to do
the server side of callback.
There are at least two ways this can be done.
- One involves just noting the calling party information, waiting
a few moments, and then calling that party back. There's just
one PPP link, and no authentication (other than the telco-
supplied calling party data, if you trust that) on the
initiating dial.
- The other involves doing the authentication (and authorization)
checks (PPP or otherwise), dropping the line, waiting a couple
of seconds for the telephone link to recover, and then
initiating a regular call back to the user.
...
I don't understand "none of that will work" unless you mean that the
idle hook isn't relevant.

I was thinking along the lines of your second suggestion above. My
problem is in dropping the line. If I return AUTHENTICATED (1) from my
ppp_auth_hook, pppd isn't going to drop the line and if I return
NOT_AUTHENTICATED (0), then pppd's going to lie to the caller and say
authentication failed, no? Or is pppd going to send *msgp to the
caller so I can do something like

strcpy(*msgp, "Authorization succeeded. Stand-by for callback");
return 0; // Pretend authenication failed so pppd hangs up.

?
Post by James Carlson
In any case, you should redo the authentication on the callback, so
that if the telephone link is compromised, you don't accidentally
allow an attacker in without authentication.
Yes, of course. Which leaves me with the problem -- with a symetric
protocol like PAP -- of determining whether this all of pap_auth_hook
is for an incoming or outgoing call.
James Carlson
2006-06-05 15:47:10 UTC
Permalink
Post by Chris Nelson
I don't understand "none of that will work" unless you mean that the
idle hook isn't relevant.
Right; that's what I mean.
Post by Chris Nelson
I was thinking along the lines of your second suggestion above. My
problem is in dropping the line. If I return AUTHENTICATED (1) from my
ppp_auth_hook, pppd isn't going to drop the line and if I return
NOT_AUTHENTICATED (0), then pppd's going to lie to the caller and say
authentication failed, no? Or is pppd going to send *msgp to the
caller so I can do something like
strcpy(*msgp, "Authorization succeeded. Stand-by for callback");
return 0; // Pretend authenication failed so pppd hangs up.
Ick!

No, I was suggesting modifying pppd itself because the plugin doesn't
quite have the right scope to do this correctly.

You should be sending auth_peer_success() to note the success, and
then terminating using lcp_close().

One plausible alternative here would be to return 1 for success, but
call lcp_close(unit, "Stand by for callback") before returning. That
should cause pppd to shut down the link without providing any real
authentication reply to the peer. You'll also need to set up a timer
that kicks you back into gear to generate the callback. It may be
possible to do this entirely from within the plugin, but I'd worry a
bit about the resulting code quality.

The big issue is with interoperability. You'll have quite a road
ahead of you working with client implementations on various timing and
operational scenarios. It's not something that anyone has done yet
with pppd, and when I worked on similar issues with a commercial
dial-in platform (I used to work at Xylogics/Bay), I recall it being
"hard" to get right.
Post by Chris Nelson
Post by James Carlson
In any case, you should redo the authentication on the callback, so
that if the telephone link is compromised, you don't accidentally
allow an attacker in without authentication.
Yes, of course. Which leaves me with the problem -- with a symetric
protocol like PAP -- of determining whether this all of pap_auth_hook
is for an incoming or outgoing call.
PAP isn't symmetric. It's asymmetric -- one side (the authenticatee)
sends PAP Authenticate-Request messages, and the other side (the
authenticator) sends Authenticate-Ack or -Nak messages.

The symmetric part is PPP itself, which allows each side to
authenticate the other, if desired. Typical deployments of PPP,
though, don't do this, because this isn't what Windows does.

When doing a call back, it's the caller that usually needs to demand
authentication.

Note that pap_auth_hook() is called _ONLY_ on the authenticator's
side. The other side -- if the peer is authenticating us and we're
the authenticatee (i.e., the typical call-to-your-ISP case) -- goes
through pap_passwd_hook.
--
James Carlson, KISS Network <***@sun.com>
Sun Microsystems / 1 Network Drive 71.232W Vox +1 781 442 2084
MS UBUR02-212 / Burlington MA 01803-2757 42.496N Fax +1 781 442 1677
Chris Nelson
2006-06-06 11:57:32 UTC
Permalink
Post by James Carlson
Post by Chris Nelson
I was thinking along the lines of your second suggestion above. My
problem is in dropping the line. If I return AUTHENTICATED (1) from my
ppp_auth_hook, pppd isn't going to drop the line and if I return
NOT_AUTHENTICATED (0), then pppd's going to lie to the caller and say
authentication failed, no? Or is pppd going to send *msgp to the
caller so I can do something like
strcpy(*msgp, "Authorization succeeded. Stand-by for callback");
return 0; // Pretend authenication failed so pppd hangs up.
Ick!
No, I was suggesting modifying pppd itself because the plugin doesn't
quite have the right scope to do this correctly.
Ick back at ya! I can't get into modifying the daemon at this point.
Post by James Carlson
You should be sending auth_peer_success() to note the success, and
then terminating using lcp_close().
auth_peer_success()? Is that what pppd do that if ppp_auth_hook
returns 1?
Post by James Carlson
One plausible alternative here would be to return 1 for success, but
call lcp_close(unit, "Stand by for callback") before returning. That
should cause pppd to shut down the link without providing any real
authentication reply to the peer. You'll also need to set up a timer
that kicks you back into gear to generate the callback. It may be
possible to do this entirely from within the plugin, but I'd worry a
bit about the resulting code quality.
Or -- and I realize I'm looking at timing issues here -- spawn a thread
to call lcp_close() a couple of seconds after ppp_auth_hook returns?
Post by James Carlson
The big issue is with interoperability. You'll have quite a road
ahead of you working with client implementations on various timing and
operational scenarios. It's not something that anyone has done yet
with pppd, and when I worked on similar issues with a commercial
dial-in platform (I used to work at Xylogics/Bay), I recall it being
"hard" to get right.
Just to be sure I understand, the interoperability is with my ppp
server on one platform and the various clients that may call in (not
with my implementation moved to other platforms).
Post by James Carlson
Post by Chris Nelson
Post by James Carlson
In any case, you should redo the authentication on the callback, so
that if the telephone link is compromised, you don't accidentally
allow an attacker in without authentication.
Yes, of course. Which leaves me with the problem -- with a symetric
protocol like PAP -- of determining whether this all of pap_auth_hook
is for an incoming or outgoing call.
PAP isn't symmetric. It's asymmetric -- one side (the authenticatee)
sends PAP Authenticate-Request messages, and the other side (the
authenticator) sends Authenticate-Ack or -Nak messages.
Yes. What I meant is that (at least potentially), both sides
authenticate each other without a clear (overall) client and server
role.
Post by James Carlson
The symmetric part is PPP itself, which allows each side to
authenticate the other, if desired. Typical deployments of PPP,
though, don't do this, because this isn't what Windows does.
Sorry. You kinda lost me there. Do you mean that 'Windows doesn't
authenticate the called system so most PPP installations don't either;
only the called system validates the peer (the calling system)?
Post by James Carlson
When doing a call back, it's the caller that usually needs to demand
authentication.
Note that pap_auth_hook() is called _ONLY_ on the authenticator's
side. The other side -- if the peer is authenticating us and we're
the authenticatee (i.e., the typical call-to-your-ISP case) -- goes
through pap_passwd_hook.
But if both authenticate then ppp_auth_hoo() gets called on the
callback, too. Right?
James Carlson
2006-06-06 13:57:09 UTC
Permalink
Post by Chris Nelson
Post by James Carlson
Ick!
No, I was suggesting modifying pppd itself because the plugin doesn't
quite have the right scope to do this correctly.
Ick back at ya! I can't get into modifying the daemon at this point.
;-}

It's really not _that_ bad.
Post by Chris Nelson
Post by James Carlson
You should be sending auth_peer_success() to note the success, and
then terminating using lcp_close().
auth_peer_success()? Is that what pppd do that if ppp_auth_hook
returns 1?
Yes. auth.c:check_passwd() calls pap_auth_hook(). If that returns
-1 (plugin uninterested), it continues with normal PAP processing. If
it returns 0, then that function returns UPAP_AUTHNAK to its caller,
otherwise, if greater than zero, it returns UPAP_AUTHACK.

check_passwd is called by upap.c:upap_rauthreq(). For UPAP_AUTHACK,
it calls auth_peer_success() to tell the state machine that we've
passed authentication and can continue. For UPAP_AUTHNAK, it calls
auth_peer_fail() to tell the state machine that we've hit the end of
the road.

Note that you may want to set remote_number[] and *permitted_numbers
from within your plugin, depending on what you're trying to do. (Or
perhaps they should be set by the command line options.)
Post by Chris Nelson
Post by James Carlson
One plausible alternative here would be to return 1 for success, but
call lcp_close(unit, "Stand by for callback") before returning. That
should cause pppd to shut down the link without providing any real
authentication reply to the peer. You'll also need to set up a timer
that kicks you back into gear to generate the callback. It may be
possible to do this entirely from within the plugin, but I'd worry a
bit about the resulting code quality.
Or -- and I realize I'm looking at timing issues here -- spawn a thread
to call lcp_close() a couple of seconds after ppp_auth_hook returns?
pppd is intentionally a single-threaded design with a event loop. If
you spawn a separate thread, you're on your own. ;-}

There's no internal locking on any of the data structures.
Post by Chris Nelson
Post by James Carlson
The big issue is with interoperability. You'll have quite a road
ahead of you working with client implementations on various timing and
operational scenarios. It's not something that anyone has done yet
with pppd, and when I worked on similar issues with a commercial
dial-in platform (I used to work at Xylogics/Bay), I recall it being
"hard" to get right.
Just to be sure I understand, the interoperability is with my ppp
server on one platform and the various clients that may call in (not
with my implementation moved to other platforms).
Yes, exactly.
Post by Chris Nelson
Post by James Carlson
PAP isn't symmetric. It's asymmetric -- one side (the authenticatee)
sends PAP Authenticate-Request messages, and the other side (the
authenticator) sends Authenticate-Ack or -Nak messages.
Yes. What I meant is that (at least potentially), both sides
authenticate each other without a clear (overall) client and server
role.
That's correct, at least from the protocol point of view.

In actual deployment, it's different.
Post by Chris Nelson
Post by James Carlson
The symmetric part is PPP itself, which allows each side to
authenticate the other, if desired. Typical deployments of PPP,
though, don't do this, because this isn't what Windows does.
Sorry. You kinda lost me there. Do you mean that 'Windows doesn't
authenticate the called system so most PPP installations don't either;
only the called system validates the peer (the calling system)?
Windows (as best I can tell) operates in only two modes: "server" or
"client." In "server" mode, the peer must be authenticated. In
"client" mode, the system must offer credentials to the peer. As best
I can tell, there's no way to tell it to do both.
Post by Chris Nelson
Post by James Carlson
When doing a call back, it's the caller that usually needs to demand
authentication.
Note that pap_auth_hook() is called _ONLY_ on the authenticator's
side. The other side -- if the peer is authenticating us and we're
the authenticatee (i.e., the typical call-to-your-ISP case) -- goes
through pap_passwd_hook.
But if both authenticate then ppp_auth_hoo() gets called on the
callback, too. Right?
Yes.

It's more a question of options than of hooks. On the callback, you
may need to _disable_ authentication via the equivalent of 'noauth'
(programmatically: setting auth_required to 0) and asserting the known
peer's identity via the equivalent of 'remotename' (filling in the
remote_name[] array).

"May." As I said, I don't think anyone's seriously tried to do what
you're doing with pppd.
--
James Carlson, KISS Network <***@sun.com>
Sun Microsystems / 1 Network Drive 71.232W Vox +1 781 442 2084
MS UBUR02-212 / Burlington MA 01803-2757 42.496N Fax +1 781 442 1677
Chris Nelson
2006-06-08 19:11:13 UTC
Permalink
First, thanks, James, for your patient and detailed feedback. I think
I'm getting somewhere.
Post by James Carlson
Note that you may want to set remote_number[] and *permitted_numbers
from within your plugin, depending on what you're trying to do. (Or
perhaps they should be set by the command line options.)
OK. I'll keep that in mind.
Post by James Carlson
...
Post by Chris Nelson
Or -- and I realize I'm looking at timing issues here -- spawn a thread
to call lcp_close() a couple of seconds after ppp_auth_hook returns?
pppd is intentionally a single-threaded design with a event loop. If
you spawn a separate thread, you're on your own. ;-}
There's no internal locking on any of the data structures.
Not to mention that my hook is in a .so and I'd have to find the thread
library somehow and ... I've given up on that route.
Post by James Carlson
...
Post by Chris Nelson
Post by James Carlson
The symmetric part is PPP itself, which allows each side to
authenticate the other, if desired. Typical deployments of PPP,
though, don't do this, because this isn't what Windows does.
Sorry. You kinda lost me there. Do you mean that 'Windows doesn't
authenticate the called system so most PPP installations don't either;
only the called system validates the peer (the calling system)?
Windows (as best I can tell) operates in only two modes: "server" or
"client." In "server" mode, the peer must be authenticated. In
"client" mode, the system must offer credentials to the peer. As best
I can tell, there's no way to tell it to do both.
So my callback mechanism is unlikely to be usable with 'Windows systems
because if a 'Windows system is set up to dial into my server, it won't
be prepared to answer my call back. I kinda like that. It simplifies
my life because I only can/have to implement call back for non-Windows
callers.
Post by James Carlson
Post by Chris Nelson
Post by James Carlson
When doing a call back, it's the caller that usually needs to demand
authentication.
Note that pap_auth_hook() is called _ONLY_ on the authenticator's
side. The other side -- if the peer is authenticating us and we're
the authenticatee (i.e., the typical call-to-your-ISP case) -- goes
through pap_passwd_hook.
But if both authenticate then ppp_auth_hoo() gets called on the
callback, too. Right?
Yes.
It's more a question of options than of hooks. On the callback, you
may need to _disable_ authentication via the equivalent of 'noauth'
(programmatically: setting auth_required to 0) and asserting the known
peer's identity via the equivalent of 'remotename' (filling in the
remote_name[] array).
"May." As I said, I don't think anyone's seriously tried to do what
you're doing with pppd.
OK. I've played with this some more, decided threads aren't happening,
and this is what I'm going forward with -- until you tell me I'm nuts
or I hit a roadblock:

- I set up a pap-auth-hook and a phase change notifier proc.

- If my pap-auth-hook determines that this user should be called back,
it sets a module static with some information about who to call back

- When the phase change notifier gets called with PHASE_NETWORK _and_
the module static is set, it calls lcp_close() and spawns a new process
to do the callback after a suitable delay.

What do you think?
Chris Nelson
2006-06-09 14:20:40 UTC
Permalink
Post by Chris Nelson
...
- When the phase change notifier gets called with PHASE_NETWORK _and_
the module static is set, it calls lcp_close() and spawns a new process
to do the callback after a suitable delay.
...
This technique seems to be bolstered by RFC 1570 which says:

When Callback is successfully negotiated, and authentication is
complete, the Authentication phase proceeds directly to the
Termination phase, and the link is disconnected.

Or am I missing something?
Chris Nelson
2006-06-09 14:24:53 UTC
Permalink
Post by Chris Nelson
Post by Chris Nelson
...
- When the phase change notifier gets called with PHASE_NETWORK _and_
the module static is set, it calls lcp_close() and spawns a new process
to do the callback after a suitable delay.
...
When Callback is successfully negotiated, and authentication is
complete, the Authentication phase proceeds directly to the
Termination phase, and the link is disconnected.
Or am I missing something?
Arg, I posted too quickly. I meant to add that maybe my notifier proc
should react to auth_up, not phase change. I see code in auth.c that
says the optional CBCP support goes to phase CALLBACK right after
notifying AUTH_UP.
James Carlson
2006-06-15 12:55:42 UTC
Permalink
Post by Chris Nelson
Arg, I posted too quickly. I meant to add that maybe my notifier proc
should react to auth_up, not phase change. I see code in auth.c that
says the optional CBCP support goes to phase CALLBACK right after
notifying AUTH_UP.
You're not referring to identifiers that are in the current code base,
so that makes it a bit difficult to determine exactly what you're
doing.

If you're using new_phase_hook, you should be checking for
PHASE_NETWORK. This is the point where we know that all of the
necessary authentication has been performed, but before any network
layer protocols have started running.

Something like this:

static bool callback_required;

static void
my_phase_change(int phase)
{
if (phase == PHASE_NETWORK && callback_required) {
lcp_close(0, "Calling you back, %s", peer_authname);
spawn_off_new_pppd();
}
}

Note, though, that start_networks() just plows on after calling the
phase change function. This means that you'll have a bit of a mess on
your hands, as the state machine fur flies. Choices here include
brutal hacks like this:

/* we're calling back, so shut the rest down */
for (protpp = protocols; (protp = *protpp++) != NULL; ) {
protp->enabled_flag = 0;
}

... or modifiying start_networks() so that it notices when the phase
doesn't end up as expected.
--
James Carlson, KISS Network <***@sun.com>
Sun Microsystems / 1 Network Drive 71.232W Vox +1 781 442 2084
MS UBUR02-212 / Burlington MA 01803-2757 42.496N Fax +1 781 442 1677
James Carlson
2006-06-15 12:44:05 UTC
Permalink
Post by Chris Nelson
Post by Chris Nelson
...
- When the phase change notifier gets called with PHASE_NETWORK _and_
the module static is set, it calls lcp_close() and spawns a new process
to do the callback after a suitable delay.
...
When Callback is successfully negotiated, and authentication is
complete, the Authentication phase proceeds directly to the
Termination phase, and the link is disconnected.
Or am I missing something?
Only that RFC 1570 describes a particular kind of callback. There are
many.

But, yes, that's essentially what's required.
--
James Carlson, KISS Network <***@sun.com>
Sun Microsystems / 1 Network Drive 71.232W Vox +1 781 442 2084
MS UBUR02-212 / Burlington MA 01803-2757 42.496N Fax +1 781 442 1677
James Carlson
2006-06-15 12:43:10 UTC
Permalink
Post by Chris Nelson
Post by James Carlson
Windows (as best I can tell) operates in only two modes: "server" or
"client." In "server" mode, the peer must be authenticated. In
"client" mode, the system must offer credentials to the peer. As best
I can tell, there's no way to tell it to do both.
So my callback mechanism is unlikely to be usable with 'Windows systems
because if a 'Windows system is set up to dial into my server, it won't
be prepared to answer my call back. I kinda like that. It simplifies
my life because I only can/have to implement call back for non-Windows
callers.
I don't follow.

Windows does indeed support both server and client side callback.

What it doesn't support (as best I can tell; I'm no Windows user) is
negotiating authentication in both directions of a PPP link. It
negotiates in one direction only. pppd (like most other
implementations) does not have that limitation.
Post by Chris Nelson
OK. I've played with this some more, decided threads aren't happening,
and this is what I'm going forward with -- until you tell me I'm nuts
- I set up a pap-auth-hook and a phase change notifier proc.
- If my pap-auth-hook determines that this user should be called back,
it sets a module static with some information about who to call back
- When the phase change notifier gets called with PHASE_NETWORK _and_
the module static is set, it calls lcp_close() and spawns a new process
to do the callback after a suitable delay.
What do you think?
That sounds good, provided that you're able to get this process to
exit in a timely way so that the next one can get access to the serial
port.
--
James Carlson, KISS Network <***@sun.com>
Sun Microsystems / 1 Network Drive 71.232W Vox +1 781 442 2084
MS UBUR02-212 / Burlington MA 01803-2757 42.496N Fax +1 781 442 1677
Chris Nelson
2006-06-16 11:10:52 UTC
Permalink
Post by James Carlson
Post by Chris Nelson
Post by James Carlson
Windows (as best I can tell) operates in only two modes: "server" or
"client." In "server" mode, the peer must be authenticated. In
"client" mode, the system must offer credentials to the peer. As best
I can tell, there's no way to tell it to do both.
So my callback mechanism is unlikely to be usable with 'Windows systems
because if a 'Windows system is set up to dial into my server, it won't
be prepared to answer my call back. I kinda like that. It simplifies
my life because I only can/have to implement call back for non-Windows
callers.
I don't follow.
Windows does indeed support both server and client side callback.
Duh! What I was missing was that callback isn't two sessions, it's a
dial out that knows enough to wait for the return call. I was thinking
that I'd have to set 'Windows up with a dialout connection _and_ a
dialin connection and somehow have them coordinated. And I would with
my home-grown drop-the-line-and-call-back mechanism. Ultimately, I got
pppd 2.4.4b1 built which seems to have a workable CBCP implementation
so I have my Linus system acting as a callback client (if that makes
any sense :-/). There's a CBCP server patch for pppd but it's based on
2.4.0 and I couldn't find a 2.4.0 base to compare against to merge into
2.4.4b1 so I gave up on that avenue. (I'd still like to pursue that
but there's no tag in pppd's CVS repository that looks like "V2_4_0" or
anything.)
Post by James Carlson
...
Post by Chris Nelson
OK. I've played with this some more, decided threads aren't happening,
and this is what I'm going forward with -- until you tell me I'm nuts
- I set up a pap-auth-hook and a phase change notifier proc.
- If my pap-auth-hook determines that this user should be called back,
it sets a module static with some information about who to call back
- When the phase change notifier gets called with PHASE_NETWORK _and_
the module static is set, it calls lcp_close() and spawns a new process
to do the callback after a suitable delay.
What do you think?
That sounds good, provided that you're able to get this process to
exit in a timely way so that the next one can get access to the serial
port.
I got the timing to pretty much work but since this approach didn't use
1570 *or* CBCP, it seems completely incompatible with every other
system so I abandoned it.
James Carlson
2006-06-18 14:37:54 UTC
Permalink
Post by Chris Nelson
Post by James Carlson
Windows does indeed support both server and client side callback.
Duh! What I was missing was that callback isn't two sessions, it's a
dial out that knows enough to wait for the return call. I was thinking
that I'd have to set 'Windows up with a dialout connection _and_ a
dialin connection and somehow have them coordinated. And I would with
my home-grown drop-the-line-and-call-back mechanism. Ultimately, I got
That's another wrinkle to dial-back.

On big commercial servers, it's not unusual to have one or two dial-in
lines and a large number of dial-out lines. This is a helpful thing
as it avoids glare.

On smaller systems, using the same line for both dial-in and the
call-back is common.
Post by Chris Nelson
pppd 2.4.4b1 built which seems to have a workable CBCP implementation
so I have my Linus system acting as a callback client (if that makes
any sense :-/). There's a CBCP server patch for pppd but it's based on
2.4.0 and I couldn't find a 2.4.0 base to compare against to merge into
2.4.4b1 so I gave up on that avenue. (I'd still like to pursue that
but there's no tag in pppd's CVS repository that looks like "V2_4_0" or
anything.)
I haven't heard of any interest in maintaining the server side of
CBCP.
Post by Chris Nelson
Post by James Carlson
That sounds good, provided that you're able to get this process to
exit in a timely way so that the next one can get access to the serial
port.
I got the timing to pretty much work but since this approach didn't use
1570 *or* CBCP, it seems completely incompatible with every other
system so I abandoned it.
They're pretty much all incompatible. It's the nature of the beast. :-/
--
James Carlson, KISS Network <***@sun.com>
Sun Microsystems / 1 Network Drive 71.232W Vox +1 781 442 2084
MS UBUR02-212 / Burlington MA 01803-2757 42.496N Fax +1 781 442 1677
Loading...