1 /* 2 * $Id: buildreq.c,v 1.1 2004/11/14 07:26:26 paulus Exp $ 3 * 4 * Copyright (C) 1995,1997 Lars Fenneberg 5 * 6 * See the file COPYRIGHT for the respective terms and conditions. 7 * If the file is missing contact me at lf (at) elemental.net 8 * and I'll send you a copy. 9 * 10 */ 11 12 #include <includes.h> 13 #include <radiusclient.h> 14 15 unsigned char rc_get_seqnbr(void); 16 17 /* 18 * Function: rc_get_nas_id 19 * 20 * Purpose: fills in NAS-Identifier or NAS-IP-Address in request 21 * 22 */ 23 24 int rc_get_nas_id(VALUE_PAIR **sendpairs) 25 { 26 UINT4 client_id; 27 char *nasid; 28 29 nasid = rc_conf_str("nas_identifier"); 30 if (strlen(nasid)) { 31 /* 32 * Fill in NAS-Identifier 33 */ 34 if (rc_avpair_add(sendpairs, PW_NAS_IDENTIFIER, nasid, 0, 35 VENDOR_NONE) == NULL) 36 return (ERROR_RC); 37 38 return (OK_RC); 39 40 } else { 41 /* 42 * Fill in NAS-IP-Address 43 */ 44 if ((client_id = rc_own_ipaddress()) == 0) 45 return (ERROR_RC); 46 47 if (rc_avpair_add(sendpairs, PW_NAS_IP_ADDRESS, &client_id, 48 0, VENDOR_NONE) == NULL) 49 return (ERROR_RC); 50 } 51 52 return (OK_RC); 53 } 54 55 /* 56 * Function: rc_buildreq 57 * 58 * Purpose: builds a skeleton RADIUS request using information from the 59 * config file. 60 * 61 */ 62 63 void rc_buildreq(SEND_DATA *data, int code, char *server, unsigned short port, 64 int timeout, int retries) 65 { 66 data->server = server; 67 data->svc_port = port; 68 data->seq_nbr = rc_get_seqnbr(); 69 data->timeout = timeout; 70 data->retries = retries; 71 data->code = code; 72 } 73 74 /* 75 * Function: rc_guess_seqnbr 76 * 77 * Purpose: return a random sequence number 78 * 79 */ 80 81 static unsigned char rc_guess_seqnbr(void) 82 { 83 return (unsigned char)(magic() & UCHAR_MAX); 84 } 85 86 /* 87 * Function: rc_get_seqnbr 88 * 89 * Purpose: generate a sequence number 90 * 91 */ 92 93 unsigned char rc_get_seqnbr(void) 94 { 95 FILE *sf; 96 int tries = 1; 97 int seq_nbr, pos; 98 char *seqfile = rc_conf_str("seqfile"); 99 100 if ((sf = fopen(seqfile, "a+")) == NULL) 101 { 102 error("rc_get_seqnbr: couldn't open sequence file %s: %s", seqfile, strerror(errno)); 103 /* well, so guess a sequence number */ 104 return rc_guess_seqnbr(); 105 } 106 107 while (do_lock_exclusive(fileno(sf))!= 0) 108 { 109 if (errno != EWOULDBLOCK) { 110 error("rc_get_seqnbr: flock failure: %s: %s", seqfile, strerror(errno)); 111 fclose(sf); 112 return rc_guess_seqnbr(); 113 } 114 tries++; 115 if (tries <= 10) 116 rc_mdelay(500); 117 else 118 break; 119 } 120 121 if (tries > 10) { 122 error("rc_get_seqnbr: couldn't get lock after %d tries: %s", tries-1, seqfile); 123 fclose(sf); 124 return rc_guess_seqnbr(); 125 } 126 127 pos = ftell(sf); 128 rewind(sf); 129 if (fscanf(sf, "%d", &seq_nbr) != 1) { 130 if (pos != ftell(sf)) { 131 /* file was not empty */ 132 error("rc_get_seqnbr: fscanf failure: %s", seqfile); 133 } 134 seq_nbr = rc_guess_seqnbr(); 135 } 136 137 rewind(sf); 138 ftruncate(fileno(sf),0); 139 fprintf(sf,"%d\n", (seq_nbr+1) & UCHAR_MAX); 140 141 fflush(sf); /* fflush because a process may read it between the do_unlock and fclose */ 142 143 if (do_unlock(fileno(sf)) != 0) 144 error("rc_get_seqnbr: couldn't release lock on %s: %s", seqfile, strerror(errno)); 145 146 fclose(sf); 147 148 return (unsigned char)seq_nbr; 149 } 150 151 /* 152 * Function: rc_auth 153 * 154 * Purpose: Builds an authentication request for port id client_port 155 * with the value_pairs send and submits it to a server 156 * 157 * Returns: received value_pairs in received, messages from the server in msg 158 * and 0 on success, negative on failure as return value 159 * 160 */ 161 162 int rc_auth(UINT4 client_port, VALUE_PAIR *send, VALUE_PAIR **received, 163 char *msg, REQUEST_INFO *info) 164 { 165 SERVER *authserver = rc_conf_srv("authserver"); 166 167 if (!authserver) { 168 return (ERROR_RC); 169 } 170 return rc_auth_using_server(authserver, client_port, send, received, 171 msg, info); 172 } 173 174 /* 175 * Function: rc_auth_using_server 176 * 177 * Purpose: Builds an authentication request for port id client_port 178 * with the value_pairs send and submits it to a server. You 179 * explicitly supply a server list. 180 * 181 * Returns: received value_pairs in received, messages from the server in msg 182 * and 0 on success, negative on failure as return value 183 * 184 */ 185 186 int rc_auth_using_server(SERVER *authserver, 187 UINT4 client_port, 188 VALUE_PAIR *send, 189 VALUE_PAIR **received, 190 char *msg, REQUEST_INFO *info) 191 { 192 SEND_DATA data; 193 int result; 194 int i; 195 int timeout = rc_conf_int("radius_timeout"); 196 int retries = rc_conf_int("radius_retries"); 197 198 data.send_pairs = send; 199 data.receive_pairs = NULL; 200 201 /* 202 * Fill in NAS-IP-Address or NAS-Identifier 203 */ 204 205 if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC) 206 return (ERROR_RC); 207 208 /* 209 * Fill in NAS-Port 210 */ 211 212 if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL) 213 return (ERROR_RC); 214 215 result = ERROR_RC; 216 for(i=0; (i<authserver->max) && (result != OK_RC) && (result != BADRESP_RC) 217 ; i++) 218 { 219 if (data.receive_pairs != NULL) { 220 rc_avpair_free(data.receive_pairs); 221 data.receive_pairs = NULL; 222 } 223 rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i], 224 authserver->port[i], timeout, retries); 225 226 result = rc_send_server (&data, msg, info); 227 } 228 229 *received = data.receive_pairs; 230 231 return result; 232 } 233 234 /* 235 * Function: rc_auth_proxy 236 * 237 * Purpose: Builds an authentication request 238 * with the value_pairs send and submits it to a server. 239 * Works for a proxy; does not add IP address, and does 240 * does not rely on config file. 241 * 242 * Returns: received value_pairs in received, messages from the server in msg 243 * and 0 on success, negative on failure as return value 244 * 245 */ 246 247 int rc_auth_proxy(VALUE_PAIR *send, VALUE_PAIR **received, char *msg) 248 { 249 SEND_DATA data; 250 int result; 251 int i; 252 SERVER *authserver = rc_conf_srv("authserver"); 253 int timeout = rc_conf_int("radius_timeout"); 254 int retries = rc_conf_int("radius_retries"); 255 256 data.send_pairs = send; 257 data.receive_pairs = NULL; 258 259 result = ERROR_RC; 260 for(i=0; (i<authserver->max) && (result != OK_RC) && (result != BADRESP_RC) 261 ; i++) 262 { 263 if (data.receive_pairs != NULL) { 264 rc_avpair_free(data.receive_pairs); 265 data.receive_pairs = NULL; 266 } 267 rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i], 268 authserver->port[i], timeout, retries); 269 270 result = rc_send_server (&data, msg, NULL); 271 } 272 273 *received = data.receive_pairs; 274 275 return result; 276 } 277 278 279 /* 280 * Function: rc_acct_using_server 281 * 282 * Purpose: Builds an accounting request for port id client_port 283 * with the value_pairs send. You explicitly supply server list. 284 * 285 * Remarks: NAS-Identifier/NAS-IP-Address, NAS-Port and Acct-Delay-Time get 286 * filled in by this function, the rest has to be supplied. 287 */ 288 289 int rc_acct_using_server(SERVER *acctserver, 290 UINT4 client_port, 291 VALUE_PAIR *send) 292 { 293 SEND_DATA data; 294 VALUE_PAIR *adt_vp; 295 int result; 296 time_t start_time, dtime; 297 char msg[4096]; 298 int i; 299 int timeout = rc_conf_int("radius_timeout"); 300 int retries = rc_conf_int("radius_retries"); 301 302 data.send_pairs = send; 303 data.receive_pairs = NULL; 304 305 /* 306 * Fill in NAS-IP-Address or NAS-Identifier 307 */ 308 309 if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC) 310 return (ERROR_RC); 311 312 /* 313 * Fill in NAS-Port 314 */ 315 316 if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL) 317 return (ERROR_RC); 318 319 /* 320 * Fill in Acct-Delay-Time 321 */ 322 323 dtime = 0; 324 if ((adt_vp = rc_avpair_add(&(data.send_pairs), PW_ACCT_DELAY_TIME, &dtime, 0, VENDOR_NONE)) == NULL) 325 return (ERROR_RC); 326 327 start_time = time(NULL); 328 result = ERROR_RC; 329 for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC) 330 ; i++) 331 { 332 if (data.receive_pairs != NULL) { 333 rc_avpair_free(data.receive_pairs); 334 data.receive_pairs = NULL; 335 } 336 rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i], 337 acctserver->port[i], timeout, retries); 338 339 dtime = time(NULL) - start_time; 340 rc_avpair_assign(adt_vp, &dtime, 0); 341 342 result = rc_send_server (&data, msg, NULL); 343 } 344 345 rc_avpair_free(data.receive_pairs); 346 347 return result; 348 } 349 350 /* 351 * Function: rc_acct 352 * 353 * Purpose: Builds an accounting request for port id client_port 354 * with the value_pairs send 355 * 356 * Remarks: NAS-Identifier/NAS-IP-Address, NAS-Port and Acct-Delay-Time get 357 * filled in by this function, the rest has to be supplied. 358 */ 359 360 int rc_acct(UINT4 client_port, VALUE_PAIR *send) 361 { 362 SERVER *acctserver = rc_conf_srv("acctserver"); 363 if (!acctserver) return (ERROR_RC); 364 365 return rc_acct_using_server(acctserver, client_port, send); 366 } 367 368 /* 369 * Function: rc_acct_proxy 370 * 371 * Purpose: Builds an accounting request with the value_pairs send 372 * 373 */ 374 375 int rc_acct_proxy(VALUE_PAIR *send) 376 { 377 SEND_DATA data; 378 int result; 379 char msg[4096]; 380 int i; 381 SERVER *acctserver = rc_conf_srv("authserver"); 382 int timeout = rc_conf_int("radius_timeout"); 383 int retries = rc_conf_int("radius_retries"); 384 385 data.send_pairs = send; 386 data.receive_pairs = NULL; 387 388 result = ERROR_RC; 389 for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC) 390 ; i++) 391 { 392 if (data.receive_pairs != NULL) { 393 rc_avpair_free(data.receive_pairs); 394 data.receive_pairs = NULL; 395 } 396 rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i], 397 acctserver->port[i], timeout, retries); 398 399 result = rc_send_server (&data, msg, NULL); 400 } 401 402 rc_avpair_free(data.receive_pairs); 403 404 return result; 405 } 406 407 /* 408 * Function: rc_check 409 * 410 * Purpose: ask the server hostname on the specified port for a 411 * status message 412 * 413 */ 414 415 int rc_check(char *host, unsigned short port, char *msg) 416 { 417 SEND_DATA data; 418 int result; 419 UINT4 service_type; 420 int timeout = rc_conf_int("radius_timeout"); 421 int retries = rc_conf_int("radius_retries"); 422 423 data.send_pairs = data.receive_pairs = NULL; 424 425 /* 426 * Fill in NAS-IP-Address or NAS-Identifier, 427 * although it isn't neccessary 428 */ 429 430 if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC) 431 return (ERROR_RC); 432 433 /* 434 * Fill in Service-Type 435 */ 436 437 service_type = PW_ADMINISTRATIVE; 438 rc_avpair_add(&(data.send_pairs), PW_SERVICE_TYPE, &service_type, 0, VENDOR_NONE); 439 440 rc_buildreq(&data, PW_STATUS_SERVER, host, port, timeout, retries); 441 result = rc_send_server (&data, msg, NULL); 442 443 rc_avpair_free(data.receive_pairs); 444 445 return result; 446 } 447