1/* 2 * $Id: sendserver.c,v 1.1.1.1 2008/10/15 03:30:39 james26_jang Exp $ 3 * 4 * Copyright (C) 1995,1996,1997 Lars Fenneberg 5 * 6 * Copyright 1992 Livingston Enterprises, Inc. 7 * 8 * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan 9 * and Merit Network, Inc. All Rights Reserved 10 * 11 * See the file COPYRIGHT for the respective terms and conditions. 12 * If the file is missing contact me at lf@elemental.net 13 * and I'll send you a copy. 14 * 15 */ 16 17#include <config.h> 18#include <includes.h> 19#include <radiusclient.h> 20#include <pathnames.h> 21 22static void rc_random_vector (unsigned char *); 23static int rc_check_reply (AUTH_HDR *, int, char *, unsigned char *, unsigned char); 24 25/* 26 * Function: rc_pack_list 27 * 28 * Purpose: Packs an attribute value pair list into a buffer. 29 * 30 * Returns: Number of octets packed. 31 * 32 */ 33 34static int rc_pack_list (VALUE_PAIR *vp, char *secret, AUTH_HDR *auth) 35{ 36 int length, i, pc, secretlen, padded_length; 37 int total_length = 0; 38 UINT4 lvalue; 39 unsigned char passbuf[MAX(AUTH_PASS_LEN, CHAP_VALUE_LENGTH)]; 40 unsigned char md5buf[256]; 41 unsigned char *buf, *vector, *lenptr; 42 43 buf = auth->data; 44 45 while (vp != (VALUE_PAIR *) NULL) 46 { 47 48 if (vp->vendorcode != VENDOR_NONE) { 49 *buf++ = PW_VENDOR_SPECIFIC; 50 51 /* Place-holder for where to put length */ 52 lenptr = buf++; 53 54 /* Insert vendor code */ 55 *buf++ = 0; 56 *buf++ = (((unsigned int) vp->vendorcode) >> 16) & 255; 57 *buf++ = (((unsigned int) vp->vendorcode) >> 8) & 255; 58 *buf++ = ((unsigned int) vp->vendorcode) & 255; 59 60 /* Insert vendor-type */ 61 *buf++ = vp->attribute; 62 63 /* Insert value */ 64 switch(vp->type) { 65 case PW_TYPE_STRING: 66 length = vp->lvalue; 67 *lenptr = length + 8; 68 *buf++ = length+2; 69 memcpy(buf, vp->strvalue, (size_t) length); 70 buf += length; 71 total_length += length+8; 72 break; 73 case PW_TYPE_INTEGER: 74 case PW_TYPE_IPADDR: 75 length = sizeof(UINT4); 76 *lenptr = length + 8; 77 *buf++ = length+2; 78 lvalue = htonl(vp->lvalue); 79 memcpy(buf, (char *) &lvalue, sizeof(UINT4)); 80 buf += length; 81 total_length += length+8; 82 break; 83 default: 84 break; 85 } 86 } else { 87 *buf++ = vp->attribute; 88 switch (vp->attribute) { 89 case PW_USER_PASSWORD: 90 91 /* Encrypt the password */ 92 93 /* Chop off password at AUTH_PASS_LEN */ 94 length = vp->lvalue; 95 if (length > AUTH_PASS_LEN) length = AUTH_PASS_LEN; 96 97 /* Calculate the padded length */ 98 padded_length = (length+(AUTH_VECTOR_LEN-1)) & ~(AUTH_VECTOR_LEN-1); 99 100 /* Record the attribute length */ 101 *buf++ = padded_length + 2; 102 103 /* Pad the password with zeros */ 104 memset ((char *) passbuf, '\0', AUTH_PASS_LEN); 105 memcpy ((char *) passbuf, vp->strvalue, (size_t) length); 106 107 secretlen = strlen (secret); 108 vector = (char *)auth->vector; 109 for(i = 0; i < padded_length; i += AUTH_VECTOR_LEN) { 110 /* Calculate the MD5 digest*/ 111 strcpy ((char *) md5buf, secret); 112 memcpy ((char *) md5buf + secretlen, vector, 113 AUTH_VECTOR_LEN); 114 rc_md5_calc (buf, md5buf, secretlen + AUTH_VECTOR_LEN); 115 116 /* Remeber the start of the digest */ 117 vector = buf; 118 119 /* Xor the password into the MD5 digest */ 120 for (pc = i; pc < (i + AUTH_VECTOR_LEN); pc++) { 121 *buf++ ^= passbuf[pc]; 122 } 123 } 124 125 total_length += padded_length + 2; 126 127 break; 128#if 0 129 case PW_CHAP_PASSWORD: 130 131 *buf++ = CHAP_VALUE_LENGTH + 2; 132 133 /* Encrypt the Password */ 134 length = vp->lvalue; 135 if (length > CHAP_VALUE_LENGTH) { 136 length = CHAP_VALUE_LENGTH; 137 } 138 memset ((char *) passbuf, '\0', CHAP_VALUE_LENGTH); 139 memcpy ((char *) passbuf, vp->strvalue, (size_t) length); 140 141 /* Calculate the MD5 Digest */ 142 secretlen = strlen (secret); 143 strcpy ((char *) md5buf, secret); 144 memcpy ((char *) md5buf + secretlen, (char *) auth->vector, 145 AUTH_VECTOR_LEN); 146 rc_md5_calc (buf, md5buf, secretlen + AUTH_VECTOR_LEN); 147 148 /* Xor the password into the MD5 digest */ 149 for (i = 0; i < CHAP_VALUE_LENGTH; i++) { 150 *buf++ ^= passbuf[i]; 151 } 152 total_length += CHAP_VALUE_LENGTH + 2; 153 154 break; 155#endif 156 default: 157 switch (vp->type) { 158 case PW_TYPE_STRING: 159 length = vp->lvalue; 160 *buf++ = length + 2; 161 memcpy (buf, vp->strvalue, (size_t) length); 162 buf += length; 163 total_length += length + 2; 164 break; 165 166 case PW_TYPE_INTEGER: 167 case PW_TYPE_IPADDR: 168 *buf++ = sizeof (UINT4) + 2; 169 lvalue = htonl (vp->lvalue); 170 memcpy (buf, (char *) &lvalue, sizeof (UINT4)); 171 buf += sizeof (UINT4); 172 total_length += sizeof (UINT4) + 2; 173 break; 174 175 default: 176 break; 177 } 178 break; 179 } 180 } 181 vp = vp->next; 182 } 183 return total_length; 184} 185 186/* 187 * Function: rc_send_server 188 * 189 * Purpose: send a request to a RADIUS server and wait for the reply 190 * 191 */ 192 193int rc_send_server (SEND_DATA *data, char *msg, REQUEST_INFO *info) 194{ 195 int sockfd; 196 struct sockaddr salocal; 197 struct sockaddr saremote; 198 struct sockaddr_in *sin; 199 struct timeval authtime; 200 fd_set readfds; 201 AUTH_HDR *auth, *recv_auth; 202 UINT4 auth_ipaddr; 203 char *server_name; /* Name of server to query */ 204 int salen; 205 int result; 206 int total_length; 207 int length; 208 int retry_max; 209 int secretlen; 210 char secret[MAX_SECRET_LENGTH + 1]; 211 unsigned char vector[AUTH_VECTOR_LEN]; 212 char recv_buffer[BUFFER_LEN]; 213 char send_buffer[BUFFER_LEN]; 214 int retries; 215 VALUE_PAIR *vp; 216 217 server_name = data->server; 218 if (server_name == (char *) NULL || server_name[0] == '\0') 219 return (ERROR_RC); 220 221 if ((vp = rc_avpair_get(data->send_pairs, PW_SERVICE_TYPE)) && \ 222 (vp->lvalue == PW_ADMINISTRATIVE)) 223 { 224 strcpy(secret, MGMT_POLL_SECRET); 225 if ((auth_ipaddr = rc_get_ipaddr(server_name)) == 0) 226 return (ERROR_RC); 227 } 228 else 229 { 230 if (rc_find_server (server_name, &auth_ipaddr, secret) != 0) 231 { 232 return (ERROR_RC); 233 } 234 } 235 236 sockfd = socket (AF_INET, SOCK_DGRAM, 0); 237 if (sockfd < 0) 238 { 239 memset (secret, '\0', sizeof (secret)); 240 rc_log(LOG_ERR, "rc_send_server: socket: %s", strerror(errno)); 241 return (ERROR_RC); 242 } 243 244 length = sizeof (salocal); 245 sin = (struct sockaddr_in *) & salocal; 246 memset ((char *) sin, '\0', (size_t) length); 247 sin->sin_family = AF_INET; 248 sin->sin_addr.s_addr = htonl(INADDR_ANY); 249 sin->sin_port = htons ((unsigned short) 0); 250 if (bind (sockfd, (struct sockaddr *) sin, length) < 0 || 251 getsockname (sockfd, (struct sockaddr *) sin, &length) < 0) 252 { 253 close (sockfd); 254 memset (secret, '\0', sizeof (secret)); 255 rc_log(LOG_ERR, "rc_send_server: bind: %s: %s", server_name, strerror(errno)); 256 return (ERROR_RC); 257 } 258 259 retry_max = data->retries; /* Max. numbers to try for reply */ 260 retries = 0; /* Init retry cnt for blocking call */ 261 262 /* Build a request */ 263 auth = (AUTH_HDR *) send_buffer; 264 auth->code = data->code; 265 auth->id = data->seq_nbr; 266 267 if (data->code == PW_ACCOUNTING_REQUEST) 268 { 269 total_length = rc_pack_list(data->send_pairs, secret, auth) + AUTH_HDR_LEN; 270 271 auth->length = htons ((unsigned short) total_length); 272 273 memset((char *) auth->vector, 0, AUTH_VECTOR_LEN); 274 secretlen = strlen (secret); 275 memcpy ((char *) auth + total_length, secret, secretlen); 276 rc_md5_calc (vector, (char *) auth, total_length + secretlen); 277 memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN); 278 } 279 else 280 { 281 rc_random_vector (vector); 282 memcpy (auth->vector, vector, AUTH_VECTOR_LEN); 283 284 total_length = rc_pack_list(data->send_pairs, secret, auth) + AUTH_HDR_LEN; 285 286 auth->length = htons ((unsigned short) total_length); 287 } 288 289 sin = (struct sockaddr_in *) & saremote; 290 memset ((char *) sin, '\0', sizeof (saremote)); 291 sin->sin_family = AF_INET; 292 sin->sin_addr.s_addr = htonl (auth_ipaddr); 293 sin->sin_port = htons ((unsigned short) data->svc_port); 294 295 for (;;) 296 { 297 sendto (sockfd, (char *) auth, (unsigned int) total_length, (int) 0, 298 (struct sockaddr *) sin, sizeof (struct sockaddr_in)); 299 300 authtime.tv_usec = 0L; 301 authtime.tv_sec = (long) data->timeout; 302 FD_ZERO (&readfds); 303 FD_SET (sockfd, &readfds); 304 if (select (sockfd + 1, &readfds, NULL, NULL, &authtime) < 0) 305 { 306 if (errno == EINTR) 307 continue; 308 rc_log(LOG_ERR, "rc_send_server: select: %s", strerror(errno)); 309 memset (secret, '\0', sizeof (secret)); 310 close (sockfd); 311 return (ERROR_RC); 312 } 313 if (FD_ISSET (sockfd, &readfds)) 314 break; 315 316 /* 317 * Timed out waiting for response. Retry "retry_max" times 318 * before giving up. If retry_max = 0, don't retry at all. 319 */ 320 if (++retries >= retry_max) 321 { 322 rc_log(LOG_ERR, 323 "rc_send_server: no reply from RADIUS server %s:%u", 324 rc_ip_hostname (auth_ipaddr), data->svc_port); 325 close (sockfd); 326 memset (secret, '\0', sizeof (secret)); 327 return (TIMEOUT_RC); 328 } 329 } 330 salen = sizeof (saremote); 331 length = recvfrom (sockfd, (char *) recv_buffer, 332 (int) sizeof (recv_buffer), 333 (int) 0, &saremote, &salen); 334 335 if (length <= 0) 336 { 337 rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: %s", server_name,\ 338 data->svc_port, strerror(errno)); 339 close (sockfd); 340 memset (secret, '\0', sizeof (secret)); 341 return (ERROR_RC); 342 } 343 344 recv_auth = (AUTH_HDR *)recv_buffer; 345 346 result = rc_check_reply (recv_auth, BUFFER_LEN, secret, vector, data->seq_nbr); 347 348 data->receive_pairs = rc_avpair_gen(recv_auth); 349 350 close (sockfd); 351 if (info) 352 { 353 memcpy(info->secret, secret, sizeof(info->secret)); 354 memcpy(info->request_vector, vector, 355 sizeof(info->request_vector)); 356 } 357 memset (secret, '\0', sizeof (secret)); 358 359 if (result != OK_RC) return (result); 360 361 *msg = '\0'; 362 vp = data->receive_pairs; 363 while (vp) 364 { 365 if ((vp = rc_avpair_get(vp, PW_REPLY_MESSAGE))) 366 { 367 strcat(msg, vp->strvalue); 368 strcat(msg, "\n"); 369 vp = vp->next; 370 } 371 } 372 373 if ((recv_auth->code == PW_ACCESS_ACCEPT) || 374 (recv_auth->code == PW_PASSWORD_ACK) || 375 (recv_auth->code == PW_ACCOUNTING_RESPONSE)) 376 { 377 result = OK_RC; 378 } 379 else 380 { 381 result = BADRESP_RC; 382 } 383 384 return (result); 385} 386 387/* 388 * Function: rc_check_reply 389 * 390 * Purpose: verify items in returned packet. 391 * 392 * Returns: OK_RC -- upon success, 393 * BADRESP_RC -- if anything looks funny. 394 * 395 */ 396 397static int rc_check_reply (AUTH_HDR *auth, int bufferlen, char *secret, 398 unsigned char *vector, unsigned char seq_nbr) 399{ 400 int secretlen; 401 int totallen; 402 unsigned char calc_digest[AUTH_VECTOR_LEN]; 403 unsigned char reply_digest[AUTH_VECTOR_LEN]; 404 405 totallen = ntohs (auth->length); 406 407 secretlen = strlen (secret); 408 409 /* Do sanity checks on packet length */ 410 if ((totallen < 20) || (totallen > 4096)) 411 { 412 rc_log(LOG_ERR, "rc_check_reply: received RADIUS server response with invalid length"); 413 return (BADRESP_RC); 414 } 415 416 /* Verify buffer space, should never trigger with current buffer size and check above */ 417 if ((totallen + secretlen) > bufferlen) 418 { 419 rc_log(LOG_ERR, "rc_check_reply: not enough buffer space to verify RADIUS server response"); 420 return (BADRESP_RC); 421 } 422 /* Verify that id (seq. number) matches what we sent */ 423 if (auth->id != seq_nbr) 424 { 425 rc_log(LOG_ERR, "rc_check_reply: received non-matching id in RADIUS server response"); 426 return (BADRESP_RC); 427 } 428 429 /* Verify the reply digest */ 430 memcpy ((char *) reply_digest, (char *) auth->vector, AUTH_VECTOR_LEN); 431 memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN); 432 memcpy ((char *) auth + totallen, secret, secretlen); 433 rc_md5_calc (calc_digest, (char *) auth, totallen + secretlen); 434 435#ifdef DIGEST_DEBUG 436 { 437 int i; 438 439 fputs("reply_digest: ", stderr); 440 for (i = 0; i < AUTH_VECTOR_LEN; i++) 441 { 442 fprintf(stderr,"%.2x ", (int) reply_digest[i]); 443 } 444 fputs("\ncalc_digest: ", stderr); 445 for (i = 0; i < AUTH_VECTOR_LEN; i++) 446 { 447 fprintf(stderr,"%.2x ", (int) calc_digest[i]); 448 } 449 fputs("\n", stderr); 450 } 451#endif 452 453 if (memcmp ((char *) reply_digest, (char *) calc_digest, 454 AUTH_VECTOR_LEN) != 0) 455 { 456#ifdef RADIUS_116 457 /* the original Livingston radiusd v1.16 seems to have 458 a bug in digest calculation with accounting requests, 459 authentication request are ok. i looked at the code 460 but couldn't find any bugs. any help to get this 461 kludge out are welcome. preferably i want to 462 reproduce the calculation bug here to be compatible 463 to stock Livingston radiusd v1.16. -lf, 03/14/96 464 */ 465 if (auth->code == PW_ACCOUNTING_RESPONSE) 466 return (OK_RC); 467#endif 468 rc_log(LOG_ERR, "rc_check_reply: received invalid reply digest from RADIUS server"); 469 return (BADRESP_RC); 470 } 471 472 return (OK_RC); 473 474} 475 476/* 477 * Function: rc_random_vector 478 * 479 * Purpose: generates a random vector of AUTH_VECTOR_LEN octets. 480 * 481 * Returns: the vector (call by reference) 482 * 483 */ 484 485static void rc_random_vector (unsigned char *vector) 486{ 487 int randno; 488 int i; 489#if defined(HAVE_DEV_URANDOM) 490 int fd; 491 492/* well, I added this to increase the security for user passwords. 493 we use /dev/urandom here, as /dev/random might block and we don't 494 need that much randomness. BTW, great idea, Ted! -lf, 03/18/95 */ 495 496 if ((fd = open(_PATH_DEV_URANDOM, O_RDONLY)) >= 0) 497 { 498 unsigned char *pos; 499 int readcount; 500 501 i = AUTH_VECTOR_LEN; 502 pos = vector; 503 while (i > 0) 504 { 505 readcount = read(fd, (char *)pos, i); 506 pos += readcount; 507 i -= readcount; 508 } 509 510 close(fd); 511 return; 512 } /* else fall through */ 513#endif 514 srand (time (0) + getppid() + getpid()); /* random enough :) */ 515 for (i = 0; i < AUTH_VECTOR_LEN;) 516 { 517 randno = rand (); 518 memcpy ((char *) vector, (char *) &randno, sizeof (int)); 519 vector += sizeof (int); 520 i += sizeof (int); 521 } 522 523 return; 524} 525