Re: How to handle SLIP, PPP, and shell accounts

Joel M Snyder, 1000 lines a day (Joel_M_Snyder@Opus1.COM)
Wed, 06 Dec 1995 14:18:46 -0700 (MST)

> I have many people do the following for users who wish multiple service
> types:
>
> Joe User
>
> shell = joeuser
> PPP = Pjoeuser
> SLIP = Sjoeuser
> ISDN = Ijoeuser

We handled that by making simple changes to RADIUS. Basically,
we use what Radius calls "unix password," although we are really
reading from the OpenVMS password file. The little piece which
goes from Radius to Password is smart enough to pull out the
first piece of the username and only send the rest down to
the authorization file. Then, it "fakes" up a profile for that
user and sends that back.

It's really a very simple strategy.

A couple of things we learned, in hindsight:

- case sensitivity is not acceptable. This is the real world, not some
Unix-inspired utopia, so everything is case un-sensitized before being
sent to the authorization file.

- your example of the "non-case" for shell users won't work because of
the previous constraint. We chose to require Tuser (Telnet user).
However, in retrospect, that was a mistake because we want to use
IP-based authentication + r-services, which means that the "telnet" user
cannot have any extra characters in their username.

- thus, if we had to do it over again, we'd do something more like:

joeuser
joeuser.P (PPP)
joeuser.S (SLIP)
joeuser.C (C/SLIP)

which is unambiguous, even in the case of a non-case-sensitive environment.

Here's a new copy of user_find(), which handles the hard part. The VMS
version of unix_password() is probably not interesting to any of you out
there...

jms

Joel M Snyder, 1404 East Lind Road, Tucson, AZ, 85719
Phone: +1 520 324 0494 (voice) +1 520 324 0495 (FAX)
jms@Opus1.COM http://www.opus1.com/jms Opus One

int
user_find(name, check_pairs, reply_pairs)
char *name;
VALUE_PAIR **check_pairs;
VALUE_PAIR **reply_pairs;
/*************************************************************************
*
* Pretend to find the named user in the database. Create the
* set of attribute-value pairs to check and reply with
* relevant values for this user.
*
*************************************************************************/
{
FILE *userfd;
char msg[128];
char *ptr;
char **ptrptr;
int namelen;
VALUE_PAIR *check_first;
VALUE_PAIR *reply_first;

/*
* User names must begin with one of the magic characters
* for them to be valid. We define them as:
* PPP_USER
* SLIP_USER
* CSLIP_USER
* TELNET_USER
* RLOGIN_USER
*/
#define PPP_USER 'P'
#define SLIP_USER 'S'
#define CSLIP_USER 'C'
#define TELNET_USER 'T'
#define RLOGIN_USER 'R'

char *password_string = "Password = \"UNIX\"";

char *ppp_vals[] = {
"User-Service-Type = Framed-User",
"Framed-Protocol = PPP",
"Framed-Address = 255.255.255.254",
"Framed-Netmask = 255.255.255.0",
"Framed-Routing = None",
"Framed-MTU = 1500",
"Framed-Compression = Van-Jacobsen-TCP-IP",
"" };

char *slip_vals[] = {
"User-Service-Type = Framed-User",
"Framed-Protocol = SLIP",
"Framed-Address = 255.255.255.254",
"Framed-Netmask = 255.255.255.0",
"Framed-Routing = None",
"Framed-MTU = 1500",
"" };

char *cslip_vals[] = {
"User-Service-Type = Framed-User",
"Framed-Protocol = SLIP",
"Framed-Address = 255.255.255.254",
"Framed-Netmask = 255.255.255.0",
"Framed-Routing = None",
"Framed-MTU = 1500",
"Framed-Compression = Van-Jacobsen-TCP-IP",
"" };

char *telnet_vals[] = {
"User-Service-Type = Login-User",
"Login-Host = 255.255.255.255",
"Login-Service = Telnet",
"Login-TCP-Port = 23",
"" };

char *rlogin_vals[] = {
"User-Service-Type = Login-User",
"Login-Service = Rlogin",
"" };

/*
* Check for valid input, zero length names not permitted
*/

ptr=name;
while (*ptr != '\0') {
if (*ptr == ' ' || *ptr == '\t') {
*ptr = '\0';
} else {
ptr++;
}
}

namelen=strlen(name);

if (namelen < 1) {
fprintf(stderr, "%s: zero length username not permitted\n",progname);
return(-1);
}

msg[0] = _toupper(name[0]);
switch (msg[0]) {
case PPP_USER:
ptrptr = ppp_vals;
break;
case SLIP_USER:
ptrptr = slip_vals;
break;
case CSLIP_USER:
ptrptr = cslip_vals;
break;
case TELNET_USER:
ptrptr = telnet_vals;
break;
case RLOGIN_USER:
ptrptr = rlogin_vals;
break;
default:
return(-1);
break;
}

check_first = (VALUE_PAIR *)NULL;
reply_first = (VALUE_PAIR *)NULL;

if(userparse(password_string, &check_first) != 0) {
sprintf(msg,"%s: Parse error for user %s\n",progname, name);
fprintf(stderr,msg);
log_err(msg);
pairfree(check_first);
return(-1);
}

while (*ptrptr[0] != '\000') {
if(userparse(*ptrptr, &reply_first) != 0) {
fprintf(stderr,"%s: Parse error for user %s\n",
progname, name);
pairfree(check_first);
pairfree(reply_first);
return(-1);
}
ptrptr++;
}

*check_pairs = check_first;
*reply_pairs = reply_first;
return(0);

}