Add lcp_renegotiation option
To support proxy LCP negotiation. Note: we *have* to take the auth id from the proxy answer, otherwise we would replay previous ids, for which the client might cache the answer and thus ignore our new challenge and just repeat their outdated answer.
This commit is contained in:
parent
817ce35748
commit
e7db528544
6 changed files with 388 additions and 31 deletions
268
ppp.c
268
ppp.c
|
|
@ -719,6 +719,274 @@ static void processreceivedlcpconfreq(sessionidt s, tunnelidt t, uint8_t *p, uin
|
|||
}
|
||||
}
|
||||
|
||||
// Process sent LCP options from o
|
||||
// Set changed to 1 if we changed configuration that should be sent to cluster slaves
|
||||
static int processsentlcpconfreq(sessionidt s, tunnelidt t, uint8_t *p, uint8_t *o, uint16_t x, int *changed)
|
||||
{
|
||||
int auth = 0;
|
||||
int ok = 1;
|
||||
|
||||
while (x > 2)
|
||||
{
|
||||
int type = o[0];
|
||||
int length = o[1];
|
||||
|
||||
if (length == 0 || length == 1 || type == 0 || x < length) break;
|
||||
switch (type)
|
||||
{
|
||||
case 1: // Maximum-Receive-Unit
|
||||
{
|
||||
uint16_t mru = ntohs(*(uint16_t *)(o + 2));
|
||||
if (mru >= MINMTU)
|
||||
{
|
||||
sess_local[s].ppp_mru = mru;
|
||||
break;
|
||||
}
|
||||
|
||||
ok = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: // Async-Control-Character-Map
|
||||
if (ntohl(*(uint32_t *)(o + 2)))
|
||||
ok = 0;
|
||||
break;
|
||||
|
||||
case 3: // Authentication-Protocol
|
||||
{
|
||||
int proto = ntohs(*(uint16_t *)(o + 2));
|
||||
|
||||
if (proto == PPPPAP)
|
||||
{
|
||||
if (config->radius_authtypes & AUTHPAP)
|
||||
{
|
||||
auth = sess_local[s].lcp_authtype = AUTHPAP;
|
||||
break;
|
||||
}
|
||||
ok = 0;
|
||||
}
|
||||
else if (proto == PPPCHAP)
|
||||
{
|
||||
if (config->radius_authtypes & AUTHCHAP
|
||||
&& *(o + 4) == 5) // MD5
|
||||
{
|
||||
auth = sess_local[s].lcp_authtype = AUTHCHAP;
|
||||
break;
|
||||
}
|
||||
ok = 0;
|
||||
}
|
||||
else
|
||||
ok = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // Quality-Protocol
|
||||
break;
|
||||
|
||||
case 5: // Magic-Number
|
||||
if (length < 6) break;
|
||||
session[s].magic = ntohl(*(uint32_t *)(o + 2));
|
||||
*changed = 1;
|
||||
break;
|
||||
|
||||
case 7: // Protocol-Field-Compression
|
||||
session[s].flags |= SESSION_PFC;
|
||||
*changed = 1;
|
||||
break;
|
||||
case 8: // Address-And-Control-Field-Compression
|
||||
session[s].flags |= SESSION_ACFC;
|
||||
*changed = 1;
|
||||
break;
|
||||
|
||||
case 17: // Multilink Max-Receive-Reconstructed-Unit
|
||||
sess_local[s].mp_mrru = ntohs(*(uint16_t *)(o + 2));
|
||||
break;
|
||||
|
||||
case 18: // Multilink Short Sequence Number Header Format
|
||||
sess_local[s].mp_mssf = 1;
|
||||
break;
|
||||
|
||||
case 19: // Multilink Endpoint Discriminator
|
||||
ok = 0;
|
||||
break;
|
||||
|
||||
default: // Reject any unknown options
|
||||
ok = 0;
|
||||
break;
|
||||
}
|
||||
x -= length;
|
||||
o += length;
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
// Return after taking note of magic and flags
|
||||
return 0;
|
||||
|
||||
if (sess_local[s].lcp_authtype && !auth)
|
||||
// We do want authentication, we have to check with client
|
||||
return 0;
|
||||
|
||||
if (sess_local[s].mp_epdis)
|
||||
// We do want Endpoint Discriminator
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Try to use LCP proxy to avoid renegotiating it (in case the LAC doesn't support passing LCP through)
|
||||
int processlcpproxy(sessionidt s, tunnelidt t, uint8_t *sent_lcp, uint16_t sent_lcp_n, uint8_t *received_lcp, uint16_t received_lcp_n)
|
||||
{
|
||||
uint8_t *response = 0;
|
||||
int changed = 0;
|
||||
|
||||
if (!strcmp(config->lcp_renegotiation, "always"))
|
||||
/* We always renegotiate */
|
||||
return 0;
|
||||
|
||||
LOG(3, s, t, "Trying to reuse the LAC sent and received LCP configuration:\n");
|
||||
if (config->debug >= 3)
|
||||
{
|
||||
dumplcp(sent_lcp, sent_lcp_n);
|
||||
dumplcp(received_lcp, received_lcp_n);
|
||||
}
|
||||
|
||||
/* Check what configuration the LAC sent */
|
||||
if (!processsentlcpconfreq(s, t, NULL, sent_lcp, sent_lcp_n, &changed))
|
||||
{
|
||||
LOG(3, s, t, "Sent LCP conf does not match\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check what configuration the LAC received */
|
||||
processreceivedlcpconfreq(s, t, NULL, received_lcp, received_lcp_n, &changed, &response);
|
||||
if (response)
|
||||
{
|
||||
LOG(3, s, t, "Received LCP conf does not match\n");
|
||||
/* Mismatch, renegotiate */
|
||||
return 0;
|
||||
}
|
||||
LOG(3, s, t, "LCP conf match\n");
|
||||
|
||||
if (changed)
|
||||
cluster_send_session(s);
|
||||
|
||||
// Ok!
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Try to use auth proxy to avoid renegotiating it (in case the LAC forces PAP)
|
||||
int processauthproxy(sessionidt s, tunnelidt t,
|
||||
uint16_t authtype, const char *authname,
|
||||
size_t authchalln, const char authchall[authchalln],
|
||||
size_t authrespn, const char authresp[authrespn])
|
||||
{
|
||||
uint16_t r;
|
||||
|
||||
if ((sess_local[s].lcp_authtype == 0 && authtype != 0)
|
||||
|| (sess_local[s].lcp_authtype == AUTHPAP && authtype != 3) // PAP
|
||||
|| (sess_local[s].lcp_authtype == AUTHCHAP && authtype != 2)) // CHAP
|
||||
{
|
||||
LOG(3, s, t, "Authentication proxy mismatch: got %u (%s) while expecting %u\n",
|
||||
authtype, ppp_auth_type(authtype), sess_local[s].lcp_authtype);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (session[s].ppp.phase != Authenticate)
|
||||
{
|
||||
LOG(3, s, t, "Already authenticated\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (sess_local[s].lcp_authtype == 0)
|
||||
{
|
||||
LOG(4, s, t, "No auth needed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((!config->disable_lac_func) && lac_conf_forwardtoremotelns(s, authname))
|
||||
{
|
||||
// Creating a tunnel/session has been started
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(r = radiusnew(s)))
|
||||
{
|
||||
LOG(1, s, t, "No RADIUS session available to authenticate session...\n");
|
||||
sessionshutdown(s, "No free RADIUS sessions.", CDN_UNAVAILABLE, TERM_SERVICE_UNAVAILABLE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Run PRE_AUTH plugins
|
||||
struct param_pre_auth packet = { &tunnel[t], &session[s], strdup(authname), NULL, 0, 1 };
|
||||
|
||||
if (sess_local[s].lcp_authtype == AUTHPAP)
|
||||
{
|
||||
packet.password = strndup(authresp, authrespn);
|
||||
packet.protocol = PPPPAP;
|
||||
}
|
||||
else if (sess_local[s].lcp_authtype == AUTHCHAP)
|
||||
{
|
||||
if (authchalln != 16)
|
||||
{
|
||||
LOG(1, s, t, "CHAP challenge size different from 16: %zu\n", authchalln);
|
||||
return 0;
|
||||
}
|
||||
if (authrespn != 16)
|
||||
{
|
||||
LOG(1, s, t, "CHAP response size different from 16: %zu\n", authrespn);
|
||||
return 0;
|
||||
}
|
||||
packet.password = calloc(17, 1);
|
||||
memcpy(packet.password, authresp, 16);
|
||||
packet.protocol = PPPCHAP;
|
||||
}
|
||||
else
|
||||
// Not PAP or CHAP??
|
||||
return 0;
|
||||
|
||||
run_plugins(PLUGIN_PRE_AUTH, &packet);
|
||||
if (!packet.continue_auth)
|
||||
{
|
||||
LOG(3, s, t, "A plugin rejected PRE_AUTH\n");
|
||||
if (packet.username) free(packet.username);
|
||||
if (packet.password) free(packet.password);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Take all authentication information from proxy, and record for possibly proxying ourself
|
||||
strncpy(session[s].user, packet.username, sizeof(session[s].user) - 1);
|
||||
strncpy((char *) sess_local[s].auth_name, packet.username, sizeof(sess_local[s].auth_name) - 1);
|
||||
|
||||
if (sess_local[s].lcp_authtype == AUTHPAP)
|
||||
{
|
||||
strncpy(radius[r].pass, packet.password, sizeof(radius[r].pass) - 1);
|
||||
strncpy((char *) sess_local[s].auth_resp, packet.password, sizeof(sess_local[s].auth_resp) - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(radius[r].auth, authchall, 16);
|
||||
memcpy(sess_local[s].auth_chall, authchall, 16);
|
||||
|
||||
memcpy(radius[r].pass, packet.password, 16);
|
||||
memcpy(sess_local[s].auth_resp, packet.password, 16);
|
||||
|
||||
radius[r].chap = 1;
|
||||
}
|
||||
radius[r].id = sess_local[s].auth_id;
|
||||
|
||||
LOG(3, s, t, "Sending login for %s to RADIUS\n", packet.username);
|
||||
|
||||
free(packet.username);
|
||||
free(packet.password);
|
||||
|
||||
if ((session[s].mrru) && (!first_session_in_bundle(s)))
|
||||
radiussend(r, RADIUSJUSTAUTH);
|
||||
else
|
||||
radiussend(r, RADIUSAUTH);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Process LCP messages
|
||||
void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue