|
|
@@ -0,0 +1,654 @@
|
|
|
+/*
|
|
|
+ 3APA3A simpliest proxy server
|
|
|
+ (c) 2000-2016 by Vladimir Dubrovin <3proxy@3proxy.ru>
|
|
|
+
|
|
|
+ please read License Agreement
|
|
|
+
|
|
|
+*/
|
|
|
+
|
|
|
+
|
|
|
+#include <proxy.h>
|
|
|
+#include "libs/md5.h"
|
|
|
+
|
|
|
+#define AUTH_VECTOR_LEN 16
|
|
|
+#define MAX_STRING_LEN 254
|
|
|
+#define PW_AUTH_UDP_PORT 1645
|
|
|
+
|
|
|
+#define PW_TYPE_STRING 0
|
|
|
+#define PW_TYPE_INTEGER 1
|
|
|
+#define PW_TYPE_IPADDR 2
|
|
|
+#define PW_TYPE_DATE 3
|
|
|
+#define PW_TYPE_ABINARY 4
|
|
|
+#define PW_TYPE_OCTETS 5
|
|
|
+
|
|
|
+#define PW_AUTHENTICATION_REQUEST 1
|
|
|
+#define PW_AUTHENTICATION_ACK 2
|
|
|
+#define PW_AUTHENTICATION_REJECT 3
|
|
|
+#define PW_ACCOUNTING_REQUEST 4
|
|
|
+#define PW_ACCOUNTING_RESPONSE 5
|
|
|
+#define PW_ACCOUNTING_STATUS 6
|
|
|
+#define PW_PASSWORD_REQUEST 7
|
|
|
+
|
|
|
+
|
|
|
+#define PW_USER_NAME 1
|
|
|
+#define PW_PASSWORD 2
|
|
|
+#define PW_CHAP_PASSWORD 3
|
|
|
+#define PW_NAS_IP_ADDRESS 4
|
|
|
+#define PW_NAS_PORT_ID 5
|
|
|
+#define PW_SERVICE_TYPE 6
|
|
|
+#define PW_FRAMED_PROTOCOL 7
|
|
|
+#define PW_FRAMED_IP_ADDRESS 8
|
|
|
+#define PW_FRAMED_IP_NETMASK 9
|
|
|
+#define PW_FRAMED_ROUTING 10
|
|
|
+#define PW_FILTER_ID 11
|
|
|
+#define PW_FRAMED_MTU 12
|
|
|
+#define PW_FRAMED_COMPRESSION 13
|
|
|
+#define PW_LOGIN_IP_HOST 14
|
|
|
+#define PW_LOGIN_SERVICE 15
|
|
|
+#define PW_LOGIN_TCP_PORT 16
|
|
|
+#define PW_OLD_PASSWORD 17
|
|
|
+#define PW_REPLY_MESSAGE 18
|
|
|
+#define PW_CALLBACK_NUMBER 19
|
|
|
+#define PW_CALLBACK_ID 20
|
|
|
+#define PW_FRAMED_ROUTE 22
|
|
|
+#define PW_FRAMED_IPXNET 23
|
|
|
+#define PW_STATE 24
|
|
|
+#define PW_CLASS 25
|
|
|
+#define PW_VENDOR_SPECIFIC 26
|
|
|
+#define PW_SESSION_TIMEOUT 27
|
|
|
+#define PW_IDLE_TIMEOUT 28
|
|
|
+#define PW_CALLED_STATION_ID 30
|
|
|
+#define PW_CALLING_STATION_ID 31
|
|
|
+#define PW_NAS_IDENTIFIER 32
|
|
|
+#define PW_PROXY_STATE 33
|
|
|
+
|
|
|
+#define PW_ACCT_STATUS_TYPE 40
|
|
|
+#define PW_ACCT_DELAY_TIME 41
|
|
|
+#define PW_ACCT_INPUT_OCTETS 42
|
|
|
+#define PW_ACCT_OUTPUT_OCTETS 43
|
|
|
+#define PW_ACCT_SESSION_ID 44
|
|
|
+#define PW_ACCT_AUTHENTIC 45
|
|
|
+#define PW_ACCT_SESSION_TIME 46
|
|
|
+#define PW_ACCT_INPUT_PACKETS 47
|
|
|
+#define PW_ACCT_OUTPUT_PACKETS 48
|
|
|
+#define PW_ACCT_TERMINATE_CAUSE 49
|
|
|
+
|
|
|
+#define PW_EVENT_TIMESTAMP 55
|
|
|
+
|
|
|
+#define PW_CHAP_CHALLENGE 60
|
|
|
+#define PW_NAS_PORT_TYPE 61
|
|
|
+#define PW_PORT_LIMIT 62
|
|
|
+
|
|
|
+#define PW_ARAP_PASSWORD 70
|
|
|
+#define PW_ARAP_FEATURES 71
|
|
|
+#define PW_ARAP_ZONE_ACCESS 72
|
|
|
+#define PW_ARAP_SECURITY 73
|
|
|
+#define PW_ARAP_SECURITY_DATA 74
|
|
|
+#define PW_PASSWORD_RETRY 75
|
|
|
+#define PW_PROMPT 76
|
|
|
+#define PW_CONNECT_INFO 77
|
|
|
+#define PW_CONFIGURATION_TOKEN 78
|
|
|
+#define PW_EAP_MESSAGE 79
|
|
|
+#define PW_MESSAGE_AUTHENTICATOR 80
|
|
|
+
|
|
|
+#define PW_ARAP_CHALLENGE_RESPONSE 84
|
|
|
+#define PW_NAS_PORT_ID_STRING 87
|
|
|
+#define PW_FRAMED_POOL 89
|
|
|
+
|
|
|
+#define PW_FALL_THROUGH 500
|
|
|
+#define PW_ADD_PORT_TO_IP_ADDRESS 501
|
|
|
+#define PW_EXEC_PROGRAM 502
|
|
|
+#define PW_EXEC_PROGRAM_WAIT 503
|
|
|
+
|
|
|
+#define PW_AUTHTYPE 1000
|
|
|
+#define PW_PREFIX 1003
|
|
|
+#define PW_SUFFIX 1004
|
|
|
+#define PW_GROUP 1005
|
|
|
+#define PW_CRYPT_PASSWORD 1006
|
|
|
+#define PW_CONNECT_RATE 1007
|
|
|
+#define PW_ADD_PREFIX 1008
|
|
|
+#define PW_ADD_SUFFIX 1009
|
|
|
+#define PW_EXPIRATION 1010
|
|
|
+#define PW_USER_CATEGORY 1029
|
|
|
+#define PW_GROUP_NAME 1030
|
|
|
+#define PW_HUNTGROUP_NAME 1031
|
|
|
+#define PW_SIMULTANEOUS_USE 1034
|
|
|
+#define PW_STRIP_USER_NAME 1035
|
|
|
+#define PW_HINT 1040
|
|
|
+#define PAM_AUTH_ATTR 1041
|
|
|
+#define PW_LOGIN_TIME 1042
|
|
|
+#define PW_STRIPPED_USER_NAME 1043
|
|
|
+#define PW_CURRENT_TIME 1044
|
|
|
+#define PW_REALM 1045
|
|
|
+#define PW_NO_SUCH_ATTRIBUTE 1046
|
|
|
+#define PW_PACKET_TYPE 1047
|
|
|
+#define PW_PROXY_TO_REALM 1048
|
|
|
+#define PW_REPLICATE_TO_REALM 1049
|
|
|
+#define PW_ACCT_SESSION_START_TIME 1050
|
|
|
+#define PW_ACCT_UNIQUE_SESSION_ID 1051
|
|
|
+#define PW_CLIENT_IP_ADDRESS 1052
|
|
|
+#define LDAP_USERDN 1053
|
|
|
+#define PW_NS_MTA_MD5_PASSWORD 1054
|
|
|
+#define PW_SQL_USER_NAME 1055
|
|
|
+
|
|
|
+#define PW_LOGIN_USER 1
|
|
|
+#define PW_FRAMED_USER 2
|
|
|
+#define PW_CALLBACK_LOGIN_USER 3
|
|
|
+#define PW_CALLBACK_FRAMED_USER 4
|
|
|
+#define PW_OUTBOUND_USER 5
|
|
|
+#define PW_ADMINISTRATIVE_USER 6
|
|
|
+#define PW_NAS_PROMPT_USER 7
|
|
|
+#define PW_AUTHENTICATE_ONLY 8
|
|
|
+#define PW_CALLBACK_NAS_PROMPT 9
|
|
|
+
|
|
|
+#define PW_NAS_PORT_ASYNC 0
|
|
|
+#define PW_NAS_PORT_SYNC 1
|
|
|
+#define PW_NAS_PORT_ISDN 2
|
|
|
+#define PW_NAS_PORT_ISDN_V120 3
|
|
|
+#define PW_NAS_PORT_ISDN_V110 4
|
|
|
+#define PW_NAS_PORT_VIRTUAL 5
|
|
|
+
|
|
|
+#define PW_STATUS_START 1
|
|
|
+#define PW_STATUS_STOP 2
|
|
|
+#define PW_STATUS_ALIVE 3
|
|
|
+#define PW_STATUS_ACCOUNTING_ON 7
|
|
|
+#define PW_STATUS_ACCOUNTING_OFF 8
|
|
|
+
|
|
|
+void md5_calc(unsigned char *output, unsigned char *input,
|
|
|
+ unsigned int inputlen);
|
|
|
+
|
|
|
+
|
|
|
+char *strNcpy(char *dest, const char *src, int n)
|
|
|
+{
|
|
|
+ if (n > 0)
|
|
|
+ strncpy(dest, src, n);
|
|
|
+ else
|
|
|
+ n = 1;
|
|
|
+ dest[n - 1] = 0;
|
|
|
+
|
|
|
+ return dest;
|
|
|
+}
|
|
|
+
|
|
|
+void md5_calc(unsigned char *output, unsigned char *input,
|
|
|
+ unsigned int inlen)
|
|
|
+{
|
|
|
+ MD5_CTX context;
|
|
|
+
|
|
|
+ MD5Init(&context);
|
|
|
+ MD5Update(&context, input, inlen);
|
|
|
+ MD5Final(output, &context);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static uint8_t random_vector_pool[AUTH_VECTOR_LEN*2];
|
|
|
+
|
|
|
+static int calc_replydigest(char *packet, char *original, const char *secret, int len)
|
|
|
+{
|
|
|
+ int secretlen;
|
|
|
+ uint8_t calc_digest[AUTH_VECTOR_LEN];
|
|
|
+ uint8_t calc_vector[AUTH_VECTOR_LEN];
|
|
|
+
|
|
|
+ memcpy(calc_vector, packet + 4, AUTH_VECTOR_LEN);
|
|
|
+ memcpy(packet + 4, original, AUTH_VECTOR_LEN);
|
|
|
+ secretlen = strlen(secret);
|
|
|
+ memcpy(packet + len, secret, secretlen);
|
|
|
+ md5_calc(calc_digest, (u_char *)packet, len + secretlen);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Return 0 if OK, 2 if not OK.
|
|
|
+ */
|
|
|
+ return memcmp(calc_vector, calc_digest, AUTH_VECTOR_LEN) ? 2 : 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Encode password.
|
|
|
+ *
|
|
|
+ * We assume that the passwd buffer passed is big enough.
|
|
|
+ * RFC2138 says the password is max 128 chars, so the size
|
|
|
+ * of the passwd buffer must be at least 129 characters.
|
|
|
+ * Preferably it's just MAX_STRING_LEN.
|
|
|
+ *
|
|
|
+ * int *pwlen is updated to the new length of the encrypted
|
|
|
+ * password - a multiple of 16 bytes.
|
|
|
+ */
|
|
|
+#define AUTH_PASS_LEN (16)
|
|
|
+int rad_pwencode(char *passwd, int *pwlen, const char *secret, const char *vector)
|
|
|
+{
|
|
|
+ uint8_t buffer[AUTH_VECTOR_LEN + MAX_STRING_LEN + 1];
|
|
|
+ char digest[AUTH_VECTOR_LEN];
|
|
|
+ int i, n, secretlen;
|
|
|
+ int len;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Padd password to multiple of AUTH_PASS_LEN bytes.
|
|
|
+ */
|
|
|
+ len = strlen(passwd);
|
|
|
+ if (len > 128) len = 128;
|
|
|
+ *pwlen = len;
|
|
|
+ if (len % AUTH_PASS_LEN != 0) {
|
|
|
+ n = AUTH_PASS_LEN - (len % AUTH_PASS_LEN);
|
|
|
+ for (i = len; n > 0; n--, i++)
|
|
|
+ passwd[i] = 0;
|
|
|
+ len = *pwlen = i;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Use the secret to setup the decryption digest
|
|
|
+ */
|
|
|
+ secretlen = strlen(secret);
|
|
|
+ memcpy(buffer, secret, secretlen);
|
|
|
+ memcpy(buffer + secretlen, vector, AUTH_VECTOR_LEN);
|
|
|
+ md5_calc((u_char *)digest, buffer, secretlen + AUTH_VECTOR_LEN);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Now we can encode the password *in place*
|
|
|
+ */
|
|
|
+ for (i = 0; i < AUTH_PASS_LEN; i++)
|
|
|
+ passwd[i] ^= digest[i];
|
|
|
+
|
|
|
+ if (len <= AUTH_PASS_LEN) return 0;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Length > AUTH_PASS_LEN, so we need to use the extended
|
|
|
+ * algorithm.
|
|
|
+ */
|
|
|
+ for (n = 0; n < 128 && n <= (len - AUTH_PASS_LEN); n += AUTH_PASS_LEN) {
|
|
|
+ memcpy(buffer + secretlen, passwd + n, AUTH_PASS_LEN);
|
|
|
+ md5_calc((u_char *)digest, buffer, secretlen + AUTH_PASS_LEN);
|
|
|
+ for (i = 0; i < AUTH_PASS_LEN; i++)
|
|
|
+ passwd[i + n + AUTH_PASS_LEN] ^= digest[i];
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/*
|
|
|
+ * Create a random vector of AUTH_VECTOR_LEN bytes.
|
|
|
+ */
|
|
|
+void random_vector(uint8_t *vector)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ static int did_random = 0;
|
|
|
+ static int counter = 0;
|
|
|
+
|
|
|
+ if (!did_random) {
|
|
|
+
|
|
|
+ for (i = 0; i < (int)sizeof(random_vector_pool); i++) {
|
|
|
+ random_vector_pool[i] += myrand((void *) random_vector_pool+i, 1); & 0xff;
|
|
|
+ }
|
|
|
+ did_random = 1;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Modify our random pool, based on the counter,
|
|
|
+ * and put the resulting information through MD5,
|
|
|
+ * so it's all mashed together.
|
|
|
+ */
|
|
|
+ pthread_mutex_lock(&rad_mutex);
|
|
|
+ counter++;
|
|
|
+ random_vector_pool[AUTH_VECTOR_LEN] += (counter & 0xff);
|
|
|
+ md5_calc((u_char *) random_vector_pool,
|
|
|
+ (u_char *) random_vector_pool,
|
|
|
+ sizeof(random_vector_pool));
|
|
|
+
|
|
|
+ /*
|
|
|
+ * And do another MD5 hash of the result, to give
|
|
|
+ * the user a random vector. This ensures that the
|
|
|
+ * user has a random vector, without giving them
|
|
|
+ * an exact image of what's in the random pool.
|
|
|
+ */
|
|
|
+ md5_calc((u_char *) vector,
|
|
|
+ (u_char *) random_vector_pool,
|
|
|
+ sizeof(random_vector_pool));
|
|
|
+ pthread_mutex_unlock(&rad_mutex);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static float timeout = 5;
|
|
|
+
|
|
|
+static int getport(const char *name)
|
|
|
+{
|
|
|
+ struct servent *svp;
|
|
|
+
|
|
|
+ svp = getservbyname (name, "udp");
|
|
|
+ if (!svp) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ntohs(svp->s_port);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+typedef struct radius_packet_t {
|
|
|
+ uint8_t code;
|
|
|
+ uint8_t id;
|
|
|
+ uint16_t length;
|
|
|
+ uint8_t vector[AUTH_VECTOR_LEN];
|
|
|
+ uint8_t data[4096];
|
|
|
+} radius_packet_t;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+char buf[256];
|
|
|
+extern int ntry;
|
|
|
+
|
|
|
+int radauth(struct clientparam * param){
|
|
|
+{
|
|
|
+ int port = 0;
|
|
|
+ int loop;
|
|
|
+ int id;
|
|
|
+ int res=0;
|
|
|
+ SOCKET sockfd;
|
|
|
+ unsigned char *ptr;
|
|
|
+ int total_length;
|
|
|
+ int len;
|
|
|
+ unsigned dst_ipaddr;
|
|
|
+#ifdef NOIPV6
|
|
|
+ struct sockaddr_in saremote;
|
|
|
+#else
|
|
|
+ struct sockaddr_in6 saremote;
|
|
|
+#endif
|
|
|
+ struct sockaddr *sa;
|
|
|
+ struct timeval tv;
|
|
|
+ fd_set rdfdesc;
|
|
|
+ char vector[AUTH_VECTOR_LEN];
|
|
|
+ radius_packet_t packet, rpacket;
|
|
|
+ int salen;
|
|
|
+ int data_len;
|
|
|
+ uint8_t *vendor_len;
|
|
|
+ int count=0;
|
|
|
+ uint8_t *attr;
|
|
|
+ int haveerror;
|
|
|
+ int loginservice;
|
|
|
+ long vendor=0;
|
|
|
+ int vendorlen=0;
|
|
|
+ int mailservice=0;
|
|
|
+
|
|
|
+ memset(&packet, 0, sizeof(packet));
|
|
|
+
|
|
|
+ random_vector(packet.vector);
|
|
|
+
|
|
|
+ id = (((int)getpid() + ntry) & 0xff);
|
|
|
+ *errorstring = NULL;
|
|
|
+ port = getport("radius");
|
|
|
+ if (port == 0) port = PW_AUTH_UDP_PORT;
|
|
|
+ if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
|
|
+ perror("radclient: socket: ");
|
|
|
+ return 4;
|
|
|
+ }
|
|
|
+
|
|
|
+ packet.code = PW_AUTHENTICATION_REQUEST;
|
|
|
+ packet.id=id;
|
|
|
+ ptr = packet.data;
|
|
|
+ total_length = 0;
|
|
|
+
|
|
|
+ md5_calc(packet.vector, packet.vector,
|
|
|
+ sizeof(packet.vector));
|
|
|
+
|
|
|
+
|
|
|
+ /* Service Type */
|
|
|
+
|
|
|
+ *ptr++ = PW_SERVICE_TYPE;
|
|
|
+ *ptr++ = 6;
|
|
|
+ (*(uint32_t *)ptr)=htonl(PW_AUTHENTICATE_ONLY);
|
|
|
+ ptr+=4;
|
|
|
+ total_length+=6;
|
|
|
+
|
|
|
+ /* NAS-Port */
|
|
|
+
|
|
|
+ *ptr++ = PW_NAS_PORT_ID;
|
|
|
+ *ptr++ = 6;
|
|
|
+ (*(uint32_t *)ptr)=htonl((unsigned int)p->server_port);
|
|
|
+ ptr+=4;
|
|
|
+ total_length+=6;
|
|
|
+
|
|
|
+ /* NAS-Port-Type */
|
|
|
+
|
|
|
+ *ptr++ = PW_NAS_PORT_TYPE;
|
|
|
+ *ptr++ = 6;
|
|
|
+ (*(uint32_t *)ptr)=htonl(PW_NAS_PORT_VIRTUAL);
|
|
|
+ ptr+=4;
|
|
|
+ total_length+=6;
|
|
|
+
|
|
|
+ /* NAS-IP-Address */
|
|
|
+
|
|
|
+ *ptr++ = PW_NAS_IP_ADDRESS;
|
|
|
+ *ptr++ = 6;
|
|
|
+ (*(uint32_t *)ptr)=p->server_ip;
|
|
|
+
|
|
|
+ ptr+=4;
|
|
|
+ total_length+=6;
|
|
|
+
|
|
|
+ /* Username */
|
|
|
+ len = strlen(p->user);
|
|
|
+ if(len>128)len=128;
|
|
|
+ *ptr++ = PW_USER_NAME;
|
|
|
+ *ptr++ = len + 2;
|
|
|
+ memcpy(ptr, p->user, len);
|
|
|
+ ptr+=len;
|
|
|
+ total_length += (len+2);
|
|
|
+
|
|
|
+ len = strlen(password);
|
|
|
+ if(len > 128) len = 128;
|
|
|
+ *ptr++ = PW_PASSWORD;
|
|
|
+ ptr++;
|
|
|
+ memcpy(ptr, password, len);
|
|
|
+ rad_pwencode(ptr,
|
|
|
+ &len,
|
|
|
+ p->radiussecret,
|
|
|
+ (char *)packet.vector);
|
|
|
+ *(ptr-1) = len + 2;
|
|
|
+ ptr+=len;
|
|
|
+ total_length+= (len+2);
|
|
|
+
|
|
|
+ total_length+=(4+AUTH_VECTOR_LEN);
|
|
|
+ packet.length = htons(total_length);
|
|
|
+ memcpy(vector, packet.vector, AUTH_VECTOR_LEN);
|
|
|
+
|
|
|
+ for (loop = 0; p->radiuslist[loop] && loop < MAXRADIUS; loop++) {
|
|
|
+ *errorstring = 0;
|
|
|
+ haveerror = 0;
|
|
|
+ loginservice = 0;
|
|
|
+ packet.id++;
|
|
|
+ dst_ipaddr = ip_getaddr(p->radiuslist[loop]);
|
|
|
+
|
|
|
+ sa = (struct sockaddr_in *) &saremote;
|
|
|
+ memset ((char *) sa, '\0', sizeof (saremote));
|
|
|
+ sa->sin_family = AF_INET;
|
|
|
+ sa->sin_addr.s_addr = dst_ipaddr;
|
|
|
+/*
|
|
|
+ sa->sin_port = htons(port);
|
|
|
+*/
|
|
|
+ sa->sin_port = htons(1812);
|
|
|
+ res = sendto(sockfd, &packet, ntohs(packet.length), 0,
|
|
|
+ (struct sockaddr *)&saremote, sizeof(struct sockaddr_in));
|
|
|
+ if(res != ntohs(packet.length)){
|
|
|
+ res = 1;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ /* And wait for reply, timing out as necessary */
|
|
|
+ FD_ZERO(&rdfdesc);
|
|
|
+ FD_SET(sockfd, &rdfdesc);
|
|
|
+
|
|
|
+ tv.tv_sec = (int)timeout;
|
|
|
+ tv.tv_usec = 1000000 * (timeout - (int)timeout);
|
|
|
+
|
|
|
+ /* Something's wrong if we don't get exactly one fd. */
|
|
|
+ if (select(sockfd + 1, &rdfdesc, NULL, NULL, &tv) != 1) {
|
|
|
+ res = 2;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ memset(&saremote, 0, sizeof(saremote));
|
|
|
+ salen = sizeof(struct sockaddr_in);
|
|
|
+
|
|
|
+ data_len = recvfrom(sockfd, &rpacket, sizeof(packet)-strlen(p->radiussecret),
|
|
|
+ 0, (struct sockaddr *)&saremote, &salen);
|
|
|
+
|
|
|
+ if (data_len < 0) {
|
|
|
+ res = 3;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (data_len < 20) {
|
|
|
+ res = 4;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if( rpacket.code != PW_AUTHENTICATION_ACK &&
|
|
|
+ rpacket.code != PW_AUTHENTICATION_REJECT ){
|
|
|
+ res = 5;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (calc_replydigest((char *)&rpacket, packet.vector, p->radiussecret,
|
|
|
+ data_len) ){
|
|
|
+ res = 5;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Check for packets with mismatched size.
|
|
|
+ * i.e. We've received 128 bytes, and the packet header
|
|
|
+ * says it's 256 bytes long.
|
|
|
+ */
|
|
|
+ total_length = ntohs(rpacket.length);
|
|
|
+ if (data_len != total_length) {
|
|
|
+ res = 6;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Walk through the packet's attributes, ensuring that
|
|
|
+ * they add up EXACTLY to the size of the packet.
|
|
|
+ *
|
|
|
+ * If they don't, then the attributes either under-fill
|
|
|
+ * or over-fill the packet. Any parsing of the packet
|
|
|
+ * is impossible, and will result in unknown side effects.
|
|
|
+ *
|
|
|
+ * This would ONLY happen with buggy RADIUS implementations,
|
|
|
+ * or with an intentional attack. Either way, we do NOT want
|
|
|
+ * to be vulnerable to this problem.
|
|
|
+ */
|
|
|
+ attr = rpacket.data;
|
|
|
+ count = total_length - 20;
|
|
|
+ vendor_len = 0;
|
|
|
+
|
|
|
+ while (count >= 2) {
|
|
|
+ /*
|
|
|
+ * Attribute number zero is NOT defined.
|
|
|
+ */
|
|
|
+ if (!vendor && attr[0] == 0) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Attributes are at LEAST as long as the ID & length
|
|
|
+ * fields. Anything shorter is an invalid attribute.
|
|
|
+ */
|
|
|
+ if (attr[1] < 2) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Sanity check the attributes for length.
|
|
|
+ */
|
|
|
+ if(!vendor && attr[0] == PW_VENDOR_SPECIFIC) {
|
|
|
+ if (attr[1] < 6 || count < 6) return 9;
|
|
|
+ vendorlen = attr[1]-6;
|
|
|
+ vendor = htonl(*((int*)(attr +2)));
|
|
|
+ count -= 6;
|
|
|
+ attr += 6;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!vendor && attr[0] == PW_REPLY_MESSAGE) {
|
|
|
+ memcpy(buf, attr+2, attr[1]-2);
|
|
|
+ buf[attr[1]-2]=0;
|
|
|
+ haveerror = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ else if (vendor == SANDY && attr[0] == SANDY_MAIL_MAILBOX) {
|
|
|
+ memcpy (p->drop_name, attr + 2, attr[1] - 2);
|
|
|
+ }
|
|
|
+ else if (vendor == SANDY && attr[0] == SANDY_MAIL_MBOXCONTROL) {
|
|
|
+ if (ntohl(*(int *)(attr+2)) & 1) p->dodeletes = 1;
|
|
|
+ }
|
|
|
+ else if (vendor == SANDY && attr[0] == SANDY_MAIL_SERVICE) {
|
|
|
+ mailservice = ntohl(*(int *)(attr+2)) ;
|
|
|
+ }
|
|
|
+
|
|
|
+ count -= attr[1]; /* grab the attribute length */
|
|
|
+ if(vendorlen) {
|
|
|
+ vendorlen -= attr[1];
|
|
|
+ if (!vendorlen) vendor = 0;
|
|
|
+ else if (vendorlen < 0) return 10;
|
|
|
+ }
|
|
|
+ attr += attr[1];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (count !=0 || vendorlen!=0) {
|
|
|
+ res = 20;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ /*
|
|
|
+ * If the attributes add up to a packet, it's allowed.
|
|
|
+ *
|
|
|
+ * If not, we complain, and throw the packet away.
|
|
|
+ */
|
|
|
+
|
|
|
+ if(haveerror){
|
|
|
+ *errorstring=buf;
|
|
|
+ }
|
|
|
+ if(rpacket.code != PW_AUTHENTICATION_ACK){
|
|
|
+ res = 0;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if(mailservice != 3){
|
|
|
+ *errorstring = "This account is not valid for mailbox access, check your settings";
|
|
|
+ return 130;
|
|
|
+ }
|
|
|
+ p->auth = at;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return 100+res;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+#ifdef WITH_MAIN
|
|
|
+
|
|
|
+extern int librad_debug;
|
|
|
+
|
|
|
+
|
|
|
+int main(int argc, char*argv[]){
|
|
|
+
|
|
|
+ char *radiuslist[] = {"195.122.226.5", NULL};
|
|
|
+ int dodeletes;
|
|
|
+ char * errorstring;
|
|
|
+ int result;
|
|
|
+/*
|
|
|
+librad_debug = 1;
|
|
|
+*/
|
|
|
+
|
|
|
+ if(argc!=3)return 1;
|
|
|
+
|
|
|
+ result = radius_pass(PLAIN, argv[1], argv[2], NULL, radiuslist, "test", &dodeletes, &errorstring);
|
|
|
+
|
|
|
+ printf("Login: %s/%d, Dodeletes: %s, Errorstring: %s\n",
|
|
|
+ (result)?"FAILED":"SUCCEED",
|
|
|
+ result,
|
|
|
+ (dodeletes)?"YES":"NO",
|
|
|
+ (errorstring)?errorstring:"NONE"
|
|
|
+ );
|
|
|
+ fflush(stdout);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|