PageRenderTime 157ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/external/ppp/pppd/plugins/radius/sendserver.c

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