| /* |
| * $Id: buildreq.c,v 1.1 2004/11/14 07:26:26 paulus Exp $ |
| * |
| * Copyright (C) 1995,1997 Lars Fenneberg |
| * |
| * See the file COPYRIGHT for the respective terms and conditions. |
| * If the file is missing contact me at lf@elemental.net |
| * and I'll send you a copy. |
| * |
| */ |
| |
| #include <includes.h> |
| #include <radiusclient.h> |
| |
| unsigned char rc_get_seqnbr(void); |
| |
| /* |
| * Function: rc_get_nas_id |
| * |
| * Purpose: fills in NAS-Identifier or NAS-IP-Address in request |
| * |
| */ |
| |
| int rc_get_nas_id(VALUE_PAIR **sendpairs) |
| { |
| UINT4 client_id; |
| char *nasid; |
| |
| nasid = rc_conf_str("nas_identifier"); |
| if (strlen(nasid)) { |
| /* |
| * Fill in NAS-Identifier |
| */ |
| if (rc_avpair_add(sendpairs, PW_NAS_IDENTIFIER, nasid, 0, |
| VENDOR_NONE) == NULL) |
| return (ERROR_RC); |
| |
| return (OK_RC); |
| |
| } else { |
| /* |
| * Fill in NAS-IP-Address |
| */ |
| if ((client_id = rc_own_ipaddress()) == 0) |
| return (ERROR_RC); |
| |
| if (rc_avpair_add(sendpairs, PW_NAS_IP_ADDRESS, &client_id, |
| 0, VENDOR_NONE) == NULL) |
| return (ERROR_RC); |
| } |
| |
| return (OK_RC); |
| } |
| |
| /* |
| * Function: rc_buildreq |
| * |
| * Purpose: builds a skeleton RADIUS request using information from the |
| * config file. |
| * |
| */ |
| |
| void rc_buildreq(SEND_DATA *data, int code, char *server, unsigned short port, |
| int timeout, int retries) |
| { |
| data->server = server; |
| data->svc_port = port; |
| data->seq_nbr = rc_get_seqnbr(); |
| data->timeout = timeout; |
| data->retries = retries; |
| data->code = code; |
| } |
| |
| /* |
| * Function: rc_guess_seqnbr |
| * |
| * Purpose: return a random sequence number |
| * |
| */ |
| |
| static unsigned char rc_guess_seqnbr(void) |
| { |
| return (unsigned char)(magic() & UCHAR_MAX); |
| } |
| |
| /* |
| * Function: rc_get_seqnbr |
| * |
| * Purpose: generate a sequence number |
| * |
| */ |
| |
| unsigned char rc_get_seqnbr(void) |
| { |
| FILE *sf; |
| int tries = 1; |
| int seq_nbr, pos; |
| char *seqfile = rc_conf_str("seqfile"); |
| |
| if ((sf = fopen(seqfile, "a+")) == NULL) |
| { |
| error("rc_get_seqnbr: couldn't open sequence file %s: %s", seqfile, strerror(errno)); |
| /* well, so guess a sequence number */ |
| return rc_guess_seqnbr(); |
| } |
| |
| while (do_lock_exclusive(fileno(sf))!= 0) |
| { |
| if (errno != EWOULDBLOCK) { |
| error("rc_get_seqnbr: flock failure: %s: %s", seqfile, strerror(errno)); |
| fclose(sf); |
| return rc_guess_seqnbr(); |
| } |
| tries++; |
| if (tries <= 10) |
| rc_mdelay(500); |
| else |
| break; |
| } |
| |
| if (tries > 10) { |
| error("rc_get_seqnbr: couldn't get lock after %d tries: %s", tries-1, seqfile); |
| fclose(sf); |
| return rc_guess_seqnbr(); |
| } |
| |
| pos = ftell(sf); |
| rewind(sf); |
| if (fscanf(sf, "%d", &seq_nbr) != 1) { |
| if (pos != ftell(sf)) { |
| /* file was not empty */ |
| error("rc_get_seqnbr: fscanf failure: %s", seqfile); |
| } |
| seq_nbr = rc_guess_seqnbr(); |
| } |
| |
| rewind(sf); |
| ftruncate(fileno(sf),0); |
| fprintf(sf,"%d\n", (seq_nbr+1) & UCHAR_MAX); |
| |
| fflush(sf); /* fflush because a process may read it between the do_unlock and fclose */ |
| |
| if (do_unlock(fileno(sf)) != 0) |
| error("rc_get_seqnbr: couldn't release lock on %s: %s", seqfile, strerror(errno)); |
| |
| fclose(sf); |
| |
| return (unsigned char)seq_nbr; |
| } |
| |
| /* |
| * Function: rc_auth |
| * |
| * Purpose: Builds an authentication request for port id client_port |
| * with the value_pairs send and submits it to a server |
| * |
| * Returns: received value_pairs in received, messages from the server in msg |
| * and 0 on success, negative on failure as return value |
| * |
| */ |
| |
| int rc_auth(UINT4 client_port, VALUE_PAIR *send, VALUE_PAIR **received, |
| char *msg, REQUEST_INFO *info) |
| { |
| SERVER *authserver = rc_conf_srv("authserver"); |
| |
| if (!authserver) { |
| return (ERROR_RC); |
| } |
| return rc_auth_using_server(authserver, client_port, send, received, |
| msg, info); |
| } |
| |
| /* |
| * Function: rc_auth_using_server |
| * |
| * Purpose: Builds an authentication request for port id client_port |
| * with the value_pairs send and submits it to a server. You |
| * explicitly supply a server list. |
| * |
| * Returns: received value_pairs in received, messages from the server in msg |
| * and 0 on success, negative on failure as return value |
| * |
| */ |
| |
| int rc_auth_using_server(SERVER *authserver, |
| UINT4 client_port, |
| VALUE_PAIR *send, |
| VALUE_PAIR **received, |
| char *msg, REQUEST_INFO *info) |
| { |
| SEND_DATA data; |
| int result; |
| int i; |
| int timeout = rc_conf_int("radius_timeout"); |
| int retries = rc_conf_int("radius_retries"); |
| |
| data.send_pairs = send; |
| data.receive_pairs = NULL; |
| |
| /* |
| * Fill in NAS-IP-Address or NAS-Identifier |
| */ |
| |
| if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC) |
| return (ERROR_RC); |
| |
| /* |
| * Fill in NAS-Port |
| */ |
| |
| if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL) |
| return (ERROR_RC); |
| |
| result = ERROR_RC; |
| for(i=0; (i<authserver->max) && (result != OK_RC) && (result != BADRESP_RC) |
| ; i++) |
| { |
| if (data.receive_pairs != NULL) { |
| rc_avpair_free(data.receive_pairs); |
| data.receive_pairs = NULL; |
| } |
| rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i], |
| authserver->port[i], timeout, retries); |
| |
| result = rc_send_server (&data, msg, info); |
| } |
| |
| *received = data.receive_pairs; |
| |
| return result; |
| } |
| |
| /* |
| * Function: rc_auth_proxy |
| * |
| * Purpose: Builds an authentication request |
| * with the value_pairs send and submits it to a server. |
| * Works for a proxy; does not add IP address, and does |
| * does not rely on config file. |
| * |
| * Returns: received value_pairs in received, messages from the server in msg |
| * and 0 on success, negative on failure as return value |
| * |
| */ |
| |
| int rc_auth_proxy(VALUE_PAIR *send, VALUE_PAIR **received, char *msg) |
| { |
| SEND_DATA data; |
| int result; |
| int i; |
| SERVER *authserver = rc_conf_srv("authserver"); |
| int timeout = rc_conf_int("radius_timeout"); |
| int retries = rc_conf_int("radius_retries"); |
| |
| data.send_pairs = send; |
| data.receive_pairs = NULL; |
| |
| result = ERROR_RC; |
| for(i=0; (i<authserver->max) && (result != OK_RC) && (result != BADRESP_RC) |
| ; i++) |
| { |
| if (data.receive_pairs != NULL) { |
| rc_avpair_free(data.receive_pairs); |
| data.receive_pairs = NULL; |
| } |
| rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i], |
| authserver->port[i], timeout, retries); |
| |
| result = rc_send_server (&data, msg, NULL); |
| } |
| |
| *received = data.receive_pairs; |
| |
| return result; |
| } |
| |
| |
| /* |
| * Function: rc_acct_using_server |
| * |
| * Purpose: Builds an accounting request for port id client_port |
| * with the value_pairs send. You explicitly supply server list. |
| * |
| * Remarks: NAS-Identifier/NAS-IP-Address, NAS-Port and Acct-Delay-Time get |
| * filled in by this function, the rest has to be supplied. |
| */ |
| |
| int rc_acct_using_server(SERVER *acctserver, |
| UINT4 client_port, |
| VALUE_PAIR *send) |
| { |
| SEND_DATA data; |
| VALUE_PAIR *adt_vp; |
| int result; |
| time_t start_time, dtime; |
| char msg[4096]; |
| int i; |
| int timeout = rc_conf_int("radius_timeout"); |
| int retries = rc_conf_int("radius_retries"); |
| |
| data.send_pairs = send; |
| data.receive_pairs = NULL; |
| |
| /* |
| * Fill in NAS-IP-Address or NAS-Identifier |
| */ |
| |
| if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC) |
| return (ERROR_RC); |
| |
| /* |
| * Fill in NAS-Port |
| */ |
| |
| if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL) |
| return (ERROR_RC); |
| |
| /* |
| * Fill in Acct-Delay-Time |
| */ |
| |
| dtime = 0; |
| if ((adt_vp = rc_avpair_add(&(data.send_pairs), PW_ACCT_DELAY_TIME, &dtime, 0, VENDOR_NONE)) == NULL) |
| return (ERROR_RC); |
| |
| start_time = time(NULL); |
| result = ERROR_RC; |
| for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC) |
| ; i++) |
| { |
| if (data.receive_pairs != NULL) { |
| rc_avpair_free(data.receive_pairs); |
| data.receive_pairs = NULL; |
| } |
| rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i], |
| acctserver->port[i], timeout, retries); |
| |
| dtime = time(NULL) - start_time; |
| rc_avpair_assign(adt_vp, &dtime, 0); |
| |
| result = rc_send_server (&data, msg, NULL); |
| } |
| |
| rc_avpair_free(data.receive_pairs); |
| |
| return result; |
| } |
| |
| /* |
| * Function: rc_acct |
| * |
| * Purpose: Builds an accounting request for port id client_port |
| * with the value_pairs send |
| * |
| * Remarks: NAS-Identifier/NAS-IP-Address, NAS-Port and Acct-Delay-Time get |
| * filled in by this function, the rest has to be supplied. |
| */ |
| |
| int rc_acct(UINT4 client_port, VALUE_PAIR *send) |
| { |
| SERVER *acctserver = rc_conf_srv("acctserver"); |
| if (!acctserver) return (ERROR_RC); |
| |
| return rc_acct_using_server(acctserver, client_port, send); |
| } |
| |
| /* |
| * Function: rc_acct_proxy |
| * |
| * Purpose: Builds an accounting request with the value_pairs send |
| * |
| */ |
| |
| int rc_acct_proxy(VALUE_PAIR *send) |
| { |
| SEND_DATA data; |
| int result; |
| char msg[4096]; |
| int i; |
| SERVER *acctserver = rc_conf_srv("authserver"); |
| int timeout = rc_conf_int("radius_timeout"); |
| int retries = rc_conf_int("radius_retries"); |
| |
| data.send_pairs = send; |
| data.receive_pairs = NULL; |
| |
| result = ERROR_RC; |
| for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC) |
| ; i++) |
| { |
| if (data.receive_pairs != NULL) { |
| rc_avpair_free(data.receive_pairs); |
| data.receive_pairs = NULL; |
| } |
| rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i], |
| acctserver->port[i], timeout, retries); |
| |
| result = rc_send_server (&data, msg, NULL); |
| } |
| |
| rc_avpair_free(data.receive_pairs); |
| |
| return result; |
| } |
| |
| /* |
| * Function: rc_check |
| * |
| * Purpose: ask the server hostname on the specified port for a |
| * status message |
| * |
| */ |
| |
| int rc_check(char *host, unsigned short port, char *msg) |
| { |
| SEND_DATA data; |
| int result; |
| UINT4 service_type; |
| int timeout = rc_conf_int("radius_timeout"); |
| int retries = rc_conf_int("radius_retries"); |
| |
| data.send_pairs = data.receive_pairs = NULL; |
| |
| /* |
| * Fill in NAS-IP-Address or NAS-Identifier, |
| * although it isn't neccessary |
| */ |
| |
| if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC) |
| return (ERROR_RC); |
| |
| /* |
| * Fill in Service-Type |
| */ |
| |
| service_type = PW_ADMINISTRATIVE; |
| rc_avpair_add(&(data.send_pairs), PW_SERVICE_TYPE, &service_type, 0, VENDOR_NONE); |
| |
| rc_buildreq(&data, PW_STATUS_SERVER, host, port, timeout, retries); |
| result = rc_send_server (&data, msg, NULL); |
| |
| rc_avpair_free(data.receive_pairs); |
| |
| return result; |
| } |