Exemplo n.º 1
0
static int status_process(REQUEST *request)
{
	int rcode = RLM_MODULE_OK;
	DICT_VALUE *dval;

	dval = dict_valbyname(PW_AUTZ_TYPE, "Status-Server");
	if (dval) {
		rcode = module_authorize(dval->value, request);
	} else {
		rcode = RLM_MODULE_OK;
	}
	
	switch (rcode) {
	case RLM_MODULE_OK:
	case RLM_MODULE_UPDATED:
		request->reply->code = PW_AUTHENTICATION_ACK;

		/*
		 *	Stats only go in the Access-Accept
		 */
		request_stats_reply(request);
		break;
		
	case RLM_MODULE_FAIL:
	case RLM_MODULE_HANDLED:
		request->reply->code = 0; /* don't reply */
		break;
		
	default:
	case RLM_MODULE_REJECT:
		request->reply->code = PW_AUTHENTICATION_REJECT;
		break;
	}

	return 0;
}
Exemplo n.º 2
0
Arquivo: auth.c Projeto: ebichu/dd-wrt
/*
 *	Process and reply to an authentication request
 *
 *	The return value of this function isn't actually used right now, so
 *	it's not entirely clear if it is returning the right things. --Pac.
 */
int rad_authenticate(REQUEST *request)
{
	VALUE_PAIR	*namepair;
#ifdef WITH_SESSION_MGMT
	VALUE_PAIR	*check_item;
#endif
	VALUE_PAIR	*auth_item = NULL;
	VALUE_PAIR	*module_msg;
	VALUE_PAIR	*tmp = NULL;
	int		result;
	const char	*password;
	char		autz_retry = 0;
	int		autz_type = 0;

	password = "";

#ifdef WITH_PROXY
	/*
	 *	If this request got proxied to another server, we need
	 *	to check whether it authenticated the request or not.
	 */
	if (request->proxy_reply) {
		switch (request->proxy_reply->code) {
		/*
		 *	Reply of ACCEPT means accept, thus set Auth-Type
		 *	accordingly.
		 */
		case PW_AUTHENTICATION_ACK:
			tmp = radius_paircreate(request,
						&request->config_items,
						PW_AUTH_TYPE, PW_TYPE_INTEGER);
			if (tmp) tmp->vp_integer = PW_AUTHTYPE_ACCEPT;
#ifdef WITH_POST_PROXY_AUTHORIZE
			if (mainconfig.post_proxy_authorize) break;
#endif
			goto authenticate;

		/*
		 *	Challenges are punted back to the NAS without any
		 *	further processing.
		 */
		case PW_ACCESS_CHALLENGE:
			request->reply->code = PW_ACCESS_CHALLENGE;
			return RLM_MODULE_OK;
		/*
		 *	ALL other replies mean reject. (this is fail-safe)
		 *
		 *	Do NOT do any authorization or authentication. They
		 *	are being rejected, so we minimize the amount of work
		 *	done by the server, by rejecting them here.
		 */
		case PW_AUTHENTICATION_REJECT:
			rad_authlog("Login incorrect (Home Server says so)",
				    request, 0);
			request->reply->code = PW_AUTHENTICATION_REJECT;
			return RLM_MODULE_REJECT;

		default:
			rad_authlog("Login incorrect (Home Server failed to respond)",
				    request, 0);
			return RLM_MODULE_REJECT;
		}
	}
#endif

	/*
	 *	Get the username from the request.
	 *
	 *	Note that namepair MAY be NULL, in which case there
	 *	is no User-Name attribute in the request.
	 */
	namepair = request->username;

	/*
	 *	Look for, and cache, passwords.
	 */
	if (!request->password) {
		request->password = pairfind(request->packet->vps,
					     PW_USER_PASSWORD);
	}

	/*
	 *	Discover which password we want to use.
	 */
	auth_item = request->password;
	if (auth_item) {
		password = (const char *)auth_item->vp_strvalue;

	} else {
		/*
		 *	Maybe there's a CHAP-Password?
		 */
		if ((auth_item = pairfind(request->packet->vps,
					  PW_CHAP_PASSWORD)) != NULL) {
			password = "******";

		} else {
			/*
			 *	No password we recognize.
			 */
			password = "******";
		}
	}
	request->password = auth_item;

	/*
	 *	Get the user's authorization information from the database
	 */
autz_redo:
	result = module_authorize(autz_type, request);
	switch (result) {
		case RLM_MODULE_NOOP:
		case RLM_MODULE_NOTFOUND:
		case RLM_MODULE_OK:
		case RLM_MODULE_UPDATED:
			break;
		case RLM_MODULE_HANDLED:
			return result;
		case RLM_MODULE_FAIL:
		case RLM_MODULE_INVALID:
		case RLM_MODULE_REJECT:
		case RLM_MODULE_USERLOCK:
		default:
			if ((module_msg = pairfind(request->packet->vps,
					PW_MODULE_FAILURE_MESSAGE)) != NULL) {
				char msg[MAX_STRING_LEN + 16];
				snprintf(msg, sizeof(msg), "Invalid user (%s)",
					 module_msg->vp_strvalue);
				rad_authlog(msg,request,0);
			} else {
				rad_authlog("Invalid user", request, 0);
			}
			request->reply->code = PW_AUTHENTICATION_REJECT;
			return result;
	}
	if (!autz_retry) {
		tmp = pairfind(request->config_items, PW_AUTZ_TYPE);
		if (tmp) {
			autz_type = tmp->vp_integer;
			RDEBUG2("Using Autz-Type %s",
				dict_valnamebyattr(PW_AUTZ_TYPE, autz_type));
			autz_retry = 1;
			goto autz_redo;
		}
	}

	/*
	 *	If we haven't already proxied the packet, then check
	 *	to see if we should.  Maybe one of the authorize
	 *	modules has decided that a proxy should be used. If
	 *	so, get out of here and send the packet.
	 */
	if (
#ifdef WITH_PROXY
	    (request->proxy == NULL) &&
#endif
	    ((tmp = pairfind(request->config_items, PW_PROXY_TO_REALM)) != NULL)) {
		REALM *realm;

		realm = realm_find2(tmp->vp_strvalue);

		/*
		 *	Don't authenticate, as the request is going to
		 *	be proxied.
		 */
		if (realm && realm->auth_pool) {
			return RLM_MODULE_OK;
		}

		/*
		 *	Catch users who set Proxy-To-Realm to a LOCAL
		 *	realm (sigh).  But don't complain if it is
		 *	*the* LOCAL realm.
		 */
		if (realm &&(strcmp(realm->name, "LOCAL") != 0)) {
			RDEBUG2("WARNING: You set Proxy-To-Realm = %s, but it is a LOCAL realm!  Cancelling proxy request.", realm->name);
		}

		if (!realm) {
			RDEBUG2("WARNING: You set Proxy-To-Realm = %s, but the realm does not exist!  Cancelling invalid proxy request.", tmp->vp_strvalue);
		}
	}

#ifdef WITH_PROXY
 authenticate:
#endif

	/*
	 *	Perhaps there is a Stripped-User-Name now.
	 */
	namepair = request->username;

	/*
	 *	Validate the user
	 */
	do {
		result = rad_check_password(request);
		if (result > 0) {
			/* don't reply! */
			return RLM_MODULE_HANDLED;
		}
	} while(0);

	/*
	 *	Failed to validate the user.
	 *
	 *	We PRESUME that the code which failed will clean up
	 *	request->reply->vps, to be ONLY the reply items it
	 *	wants to send back.
	 */
	if (result < 0) {
		RDEBUG2("Failed to authenticate the user.");
		request->reply->code = PW_AUTHENTICATION_REJECT;

		if ((module_msg = pairfind(request->packet->vps,PW_MODULE_FAILURE_MESSAGE)) != NULL){
			char msg[MAX_STRING_LEN+19];

			snprintf(msg, sizeof(msg), "Login incorrect (%s)",
				 module_msg->vp_strvalue);
			rad_authlog(msg, request, 0);
		} else {
			rad_authlog("Login incorrect", request, 0);
		}

		/* double check: maybe the secret is wrong? */
		if ((debug_flag > 1) && (auth_item != NULL) &&
				(auth_item->attribute == PW_USER_PASSWORD)) {
			uint8_t *p;

			p = (uint8_t *) auth_item->vp_strvalue;
			while (*p) {
				int size;

				size = fr_utf8_char(p);
				if (!size) {
					log_debug("  WARNING: Unprintable characters in the password.  Double-check the shared secret on the server and the NAS!");
					break;
				}
				p += size;
			}
		}
	}

#ifdef WITH_SESSION_MGMT
	if (result >= 0 &&
	    (check_item = pairfind(request->config_items, PW_SIMULTANEOUS_USE)) != NULL) {
		int r, session_type = 0;
		char		logstr[1024];
		char		umsg[MAX_STRING_LEN + 1];
		const char	*user_msg = NULL;

		tmp = pairfind(request->config_items, PW_SESSION_TYPE);
		if (tmp) {
			session_type = tmp->vp_integer;
			RDEBUG2("Using Session-Type %s",
				dict_valnamebyattr(PW_SESSION_TYPE, session_type));
		}

		/*
		 *	User authenticated O.K. Now we have to check
		 *	for the Simultaneous-Use parameter.
		 */
		if (namepair &&
		    (r = module_checksimul(session_type, request, check_item->vp_integer)) != 0) {
			char mpp_ok = 0;

			if (r == 2){
				/* Multilink attempt. Check if port-limit > simultaneous-use */
				VALUE_PAIR *port_limit;

				if ((port_limit = pairfind(request->reply->vps, PW_PORT_LIMIT)) != NULL &&
					port_limit->vp_integer > check_item->vp_integer){
					RDEBUG2("MPP is OK");
					mpp_ok = 1;
				}
			}
			if (!mpp_ok){
				if (check_item->vp_integer > 1) {
		  		snprintf(umsg, sizeof(umsg),
							"\r\nYou are already logged in %d times  - access denied\r\n\n",
							(int)check_item->vp_integer);
					user_msg = umsg;
				} else {
					user_msg = "\r\nYou are already logged in - access denied\r\n\n";
				}

				request->reply->code = PW_AUTHENTICATION_REJECT;

				/*
				 *	They're trying to log in too many times.
				 *	Remove ALL reply attributes.
				 */
				pairfree(&request->reply->vps);
				radius_pairmake(request, &request->reply->vps,
						"Reply-Message",
						user_msg, T_OP_SET);

				snprintf(logstr, sizeof(logstr), "Multiple logins (max %d) %s",
					check_item->vp_integer,
					r == 2 ? "[MPP attempt]" : "");
				rad_authlog(logstr, request, 1);

				result = -1;
			}
		}
	}
#endif

	/*
	 *	Result should be >= 0 here - if not, it means the user
	 *	is rejected, so we just process post-auth and return.
	 */
	if (result < 0) {
		return RLM_MODULE_REJECT;
	}

	/*
	 *	Add the port number to the Framed-IP-Address if
	 *	vp->addport is set.
	 */
	if (((tmp = pairfind(request->reply->vps,
			     PW_FRAMED_IP_ADDRESS)) != NULL) &&
	    (tmp->flags.addport != 0)) {
		VALUE_PAIR *vpPortId;

		/*
		 *  Find the NAS port ID.
		 */
		if ((vpPortId = pairfind(request->packet->vps,
					 PW_NAS_PORT)) != NULL) {
		  unsigned long tvalue = ntohl(tmp->vp_integer);
		  tmp->vp_integer = htonl(tvalue + vpPortId->vp_integer);
		  tmp->flags.addport = 0;
		  ip_ntoa(tmp->vp_strvalue, tmp->vp_integer);
		} else {
			RDEBUG2("WARNING: No NAS-Port attribute in request.  CANNOT return a Framed-IP-Address + NAS-Port.\n");
			pairdelete(&request->reply->vps, PW_FRAMED_IP_ADDRESS);
		}
	}

	/*
	 *	Set the reply to Access-Accept, if it hasn't already
	 *	been set to something.  (i.e. Access-Challenge)
	 */
	if (request->reply->code == 0)
	  request->reply->code = PW_AUTHENTICATION_ACK;

	if ((module_msg = pairfind(request->packet->vps,PW_MODULE_SUCCESS_MESSAGE)) != NULL){
		char msg[MAX_STRING_LEN+12];

		snprintf(msg, sizeof(msg), "Login OK (%s)",
			 module_msg->vp_strvalue);
		rad_authlog(msg, request, 1);
	} else {
		rad_authlog("Login OK", request, 1);
	}

	/*
	 *	Run the modules in the 'post-auth' section.
	 */
	result = rad_postauth(request);

	return result;
}
Exemplo n.º 3
0
static int
eap_pwd_authenticate (void *arg, EAP_HANDLER *handler)
{
    pwd_session_t *pwd_session;
    pwd_hdr *hdr;
    pwd_id_packet *id;
    EAP_PACKET *response;
    REQUEST *request, *fake;
    VALUE_PAIR *pw, **outvps, *vp;
    EAP_DS *eap_ds;
    int len, ret = 0;
    eap_pwd_t *inst = (eap_pwd_t *)arg;
    uint16_t offset;
    uint8_t exch, *buf, *ptr, msk[MSK_EMSK_LEN], emsk[MSK_EMSK_LEN];
    uint8_t peer_confirm[SHA256_DIGEST_LENGTH];
    BIGNUM *x = NULL, *y = NULL;

    if ((handler == NULL) ||
            ((eap_ds = handler->eap_ds) == NULL) ||
            (inst == NULL)) {
        return 0;
    }
    pwd_session = (pwd_session_t *)handler->opaque;
    request = handler->request;
    response = handler->eap_ds->response;
    hdr = (pwd_hdr *)response->type.data;

    buf = hdr->data;
    len = response->type.length - sizeof(pwd_hdr);

    /*
     * see if we're fragmenting, if so continue until we're done
     */
    if (pwd_session->out_buf_pos) {
        if (len) {
            RDEBUG2("pwd got something more than an ACK for a fragment");
        }
        return send_pwd_request(pwd_session, eap_ds);
    }

    /*
     * the first fragment will have a total length, make a
     * buffer to hold all the fragments
     */
    if (EAP_PWD_GET_LENGTH_BIT(hdr)) {
        if (pwd_session->in_buf) {
            RDEBUG2("pwd already alloced buffer for fragments");
            return 0;
        }
        pwd_session->in_buf_len = ntohs(buf[0] * 256 | buf[1]);
        if ((pwd_session->in_buf = malloc(pwd_session->in_buf_len)) == NULL) {
            RDEBUG2("pwd cannot malloc %d buffer to hold fragments",
                    pwd_session->in_buf_len);
            return 0;
        }
        memset(pwd_session->in_buf, 0, pwd_session->in_buf_len);
        pwd_session->in_buf_pos = 0;
        buf += sizeof(uint16_t);
        len -= sizeof(uint16_t);
    }

    /*
     * all fragments, including the 1st will have the M(ore) bit set,
     * buffer those fragments!
     */
    if (EAP_PWD_GET_MORE_BIT(hdr)) {
        rad_assert(pwd_session->in_buf != NULL);
        if ((pwd_session->in_buf_pos + len) > pwd_session->in_buf_len) {
            RDEBUG2("pwd will not overflow a fragment buffer. Nope, not prudent.");
            return 0;
        }
        memcpy(pwd_session->in_buf + pwd_session->in_buf_pos, buf, len);
        pwd_session->in_buf_pos += len;

        /*
         * send back an ACK for this fragment
         */
        exch = EAP_PWD_GET_EXCHANGE(hdr);
        eap_ds->request->code = PW_EAP_REQUEST;
        eap_ds->request->type.type = PW_EAP_PWD;
        eap_ds->request->type.length = sizeof(pwd_hdr);
        if ((eap_ds->request->type.data = malloc(sizeof(pwd_hdr))) == NULL) {
            radlog(L_ERR, "rlm_eap_pwd: fragment ACK, out of memory");
            return 0;
        }
        hdr = (pwd_hdr *)eap_ds->request->type.data;
        EAP_PWD_SET_EXCHANGE(hdr, exch);
        return 1;

    }

    if (pwd_session->in_buf) {
        /*
         * the last fragment...
         */
        if ((pwd_session->in_buf_pos + len) > pwd_session->in_buf_len) {
            RDEBUG2("pwd will not overflow a fragment buffer. Nope, not prudent.");
            return 0;
        }
        memcpy(pwd_session->in_buf + pwd_session->in_buf_pos, buf, len);
        buf = pwd_session->in_buf;
        len = pwd_session->in_buf_len;
    }

    switch (pwd_session->state) {
    case PWD_STATE_ID_REQ:
        if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_ID) {
            RDEBUG2("pwd exchange is incorrect: not ID");
            return 0;
        }
        id = (pwd_id_packet *)buf;
        if ((id->prf != EAP_PWD_DEF_PRF) ||
                (id->random_function != EAP_PWD_DEF_RAND_FUN) ||
                (id->prep != EAP_PWD_PREP_NONE) ||
                (memcmp(id->token, (char *)&pwd_session->token, 4)) ||
                (id->group_num != ntohs(pwd_session->group_num))) {
            RDEBUG2("pwd id response is invalid");
            return 0;
        }
        /*
         * we've agreed on the ciphersuite, record it...
         */
        ptr = (uint8_t *)&pwd_session->ciphersuite;
        memcpy(ptr, (char *)&id->group_num, sizeof(uint16_t));
        ptr += sizeof(uint16_t);
        *ptr = EAP_PWD_DEF_RAND_FUN;
        ptr += sizeof(uint8_t);
        *ptr = EAP_PWD_DEF_PRF;

        pwd_session->peer_id_len = len - sizeof(pwd_id_packet);
        if (pwd_session->peer_id_len >= sizeof(pwd_session->peer_id)) {
            RDEBUG2("pwd id response is malformed");
            return 0;
        }
        memcpy(pwd_session->peer_id, id->identity,
               pwd_session->peer_id_len);
        pwd_session->peer_id[pwd_session->peer_id_len] = '\0';

        /*
         * make fake request to get the password for the usable ID
         */
        if ((fake = request_alloc_fake(handler->request)) == NULL) {
            RDEBUG("pwd unable to create fake request!");
            return 0;
        }
        if ((fake->username = pairmake("User-Name", "", T_OP_EQ)) == NULL) {
            RDEBUG("pwd unanable to create value pair for username!");
            request_free(&fake);
            return 0;
        }
        memcpy(fake->username->vp_strvalue, pwd_session->peer_id,
               pwd_session->peer_id_len);
        fake->username->length = pwd_session->peer_id_len;
        fake->username->vp_strvalue[fake->username->length] = 0;

        if ((vp = pairfind(request->config_items, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) {
            fake->server = vp->vp_strvalue;

        } else if (inst->conf->virtual_server) {
            fake->server = inst->conf->virtual_server;

        } /* else fake->server == request->server */

        if ((debug_flag > 0) && fr_log_fp) {
            RDEBUG("Sending tunneled request");

            debug_pair_list(fake->packet->vps);

            fprintf(fr_log_fp, "server %s {\n",
                    (fake->server == NULL) ? "" : fake->server);
        }

        /*
         *	Call authorization recursively, which will
         *	get the password.
         */
        module_authorize(0, fake);

        /*
         *	Note that we don't do *anything* with the reply
         *	attributes.
         */
        if ((debug_flag > 0) && fr_log_fp) {
            fprintf(fr_log_fp, "} # server %s\n",
                    (fake->server == NULL) ? "" : fake->server);

            RDEBUG("Got tunneled reply code %d", fake->reply->code);

            debug_pair_list(fake->reply->vps);
        }

        if ((pw = pairfind(fake->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) == NULL) {
            DEBUG2("failed to find password for %s to do pwd authentication",
                   pwd_session->peer_id);
            request_free(&fake);
            return 0;
        }

        if (compute_password_element(pwd_session, pwd_session->group_num,
                                     pw->data.strvalue, strlen(pw->data.strvalue),
                                     inst->conf->server_id, strlen(inst->conf->server_id),
                                     pwd_session->peer_id, strlen(pwd_session->peer_id),
                                     &pwd_session->token)) {
            DEBUG2("failed to obtain password element :-(");
            request_free(&fake);
            return 0;
        }
        request_free(&fake);

        /*
         * compute our scalar and element
         */
        if (compute_scalar_element(pwd_session, inst->bnctx)) {
            DEBUG2("failed to compute server's scalar and element");
            return 0;
        }
        if (((x = BN_new()) == NULL) ||
                ((y = BN_new()) == NULL)) {
            DEBUG2("server point allocation failed");
            return 0;
        }
        /*
         * element is a point, get both coordinates: x and y
         */
        if (!EC_POINT_get_affine_coordinates_GFp(pwd_session->group,
                pwd_session->my_element, x, y,
                inst->bnctx)) {
            DEBUG2("server point assignment failed");
            BN_free(x);
            BN_free(y);
            return 0;
        }
        /*
         * construct request
         */
        pwd_session->out_buf_len = BN_num_bytes(pwd_session->order) +
                                   (2 * BN_num_bytes(pwd_session->prime));
        if ((pwd_session->out_buf = malloc(pwd_session->out_buf_len)) == NULL) {
            radlog(L_ERR, "rlm_eap_pwd: out of memory to send commit");
            return 0;
        }
        memset(pwd_session->out_buf, 0, pwd_session->out_buf_len);

        ptr = pwd_session->out_buf;
        offset = BN_num_bytes(pwd_session->prime) - BN_num_bytes(x);
        BN_bn2bin(x, ptr + offset);

        ptr += BN_num_bytes(pwd_session->prime);
        offset = BN_num_bytes(pwd_session->prime) - BN_num_bytes(y);
        BN_bn2bin(y, ptr + offset);

        ptr += BN_num_bytes(pwd_session->prime);
        offset = BN_num_bytes(pwd_session->order) - BN_num_bytes(pwd_session->my_scalar);
        BN_bn2bin(pwd_session->my_scalar, ptr + offset);

        pwd_session->state = PWD_STATE_COMMIT;
        ret = send_pwd_request(pwd_session, eap_ds);
        break;
    case PWD_STATE_COMMIT:
        if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_COMMIT) {
            RDEBUG2("pwd exchange is incorrect: not commit!");
            return 0;
        }
        /*
         * process the peer's commit and generate the shared key, k
         */
        if (process_peer_commit(pwd_session, buf, inst->bnctx)) {
            RDEBUG2("failed to process peer's commit");
            return 0;
        }

        /*
         * compute our confirm blob
         */
        if (compute_server_confirm(pwd_session, pwd_session->my_confirm, inst->bnctx)) {
            radlog(L_ERR, "rlm_eap_pwd: failed to compute confirm!");
            return 0;
        }
        /*
         * construct a response...which is just our confirm blob
         */
        pwd_session->out_buf_len = SHA256_DIGEST_LENGTH;
        if ((pwd_session->out_buf = malloc(pwd_session->out_buf_len)) == NULL) {
            radlog(L_ERR, "rlm_eap_pwd: out of memory to send confirm");
            return 0;
        }
        memset(pwd_session->out_buf, 0, pwd_session->out_buf_len);
        memcpy(pwd_session->out_buf, pwd_session->my_confirm, SHA256_DIGEST_LENGTH);

        pwd_session->state = PWD_STATE_CONFIRM;
        ret = send_pwd_request(pwd_session, eap_ds);
        break;
    case PWD_STATE_CONFIRM:
        if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_CONFIRM) {
            RDEBUG2("pwd exchange is incorrect: not commit!");
            return 0;
        }
        if (compute_peer_confirm(pwd_session, peer_confirm, inst->bnctx)) {
            RDEBUG2("pwd exchange cannot compute peer's confirm");
            return 0;
        }
        if (memcmp(peer_confirm, buf, SHA256_DIGEST_LENGTH)) {
            RDEBUG2("pwd exchange fails: peer confirm is incorrect!");
            return 0;
        }
        if (compute_keys(pwd_session, peer_confirm, msk, emsk)) {
            RDEBUG2("pwd exchange cannot generate (E)MSK!");
            return 0;
        }
        eap_ds->request->code = PW_EAP_SUCCESS;
        /*
         * return the MSK (in halves)
         */
        outvps = &handler->request->reply->vps;
        add_reply(outvps, "MS-MPPE-Recv-Key", msk, MPPE_KEY_LEN);
        add_reply(outvps, "MS-MPPE-Send-Key", msk+MPPE_KEY_LEN, MPPE_KEY_LEN);
        ret = 1;
        break;
    default:
        RDEBUG2("unknown PWD state");
        return 0;
    }

    /*
     * we processed the buffered fragments, get rid of them
     */
    if (pwd_session->in_buf) {
        free(pwd_session->in_buf);
        pwd_session->in_buf = NULL;
    }

    return ret;
}
Exemplo n.º 4
0
/*
 *	Find a per-socket client.
 */
RADCLIENT *client_listener_find(const rad_listen_t *listener,
				const fr_ipaddr_t *ipaddr, int src_port)
{
#ifdef WITH_DYNAMIC_CLIENTS
	int rcode;
	REQUEST *request;
	RADCLIENT *created;
#endif
	time_t now;
	RADCLIENT *client;
	RADCLIENT_LIST *clients;
	listen_socket_t *sock;

	rad_assert(listener != NULL);
	rad_assert(ipaddr != NULL);

	sock = listener->data;
	clients = sock->clients;

	/*
	 *	This HAS to have been initialized previously.
	 */
	rad_assert(clients != NULL);

	client = client_find(clients, ipaddr,sock->proto);
	if (!client) {
		char name[256], buffer[128];
					
#ifdef WITH_DYNAMIC_CLIENTS
	unknown:		/* used only for dynamic clients */
#endif

		/*
		 *	DoS attack quenching, but only in daemon mode.
		 *	If they're running in debug mode, show them
		 *	every packet.
		 */
		if (debug_flag == 0) {
			static time_t last_printed = 0;

			now = time(NULL);
			if (last_printed == now) return NULL;
			
			last_printed = now;
		}

		listener->print(listener, name, sizeof(name));

		radlog(L_ERR, "Ignoring request to %s from unknown client %s port %d"
#ifdef WITH_TCP
		       " proto %s"
#endif
		       , name, inet_ntop(ipaddr->af, &ipaddr->ipaddr,
					 buffer, sizeof(buffer)), src_port
#ifdef WITH_TCP
		       , (sock->proto == IPPROTO_UDP) ? "udp" : "tcp"
#endif
		       );
		return NULL;
	}

#ifndef WITH_DYNAMIC_CLIENTS
	return client;		/* return the found client. */
#else

	/*
	 *	No server defined, and it's not dynamic.  Return it.
	 */
	if (!client->client_server && !client->dynamic) return client;

	now = time(NULL);
	
	/*
	 *	It's a dynamically generated client, check it.
	 */
	if (client->dynamic && (src_port != 0)) {
		/*
		 *	Lives forever.  Return it.
		 */
		if (client->lifetime == 0) return client;
		
		/*
		 *	Rate-limit the deletion of known clients.
		 *	This makes them last a little longer, but
		 *	prevents the server from melting down if (say)
		 *	10k clients all expire at once.
		 */
		if (now == client->last_new_client) return client;

		/*
		 *	It's not dead yet.  Return it.
		 */
		if ((client->created + client->lifetime) > now) return client;
		
		/*
		 *	This really puts them onto a queue for later
		 *	deletion.
		 */
		client_delete(clients, client);

		/*
		 *	Go find the enclosing network again.
		 */
		client = client_find(clients, ipaddr, sock->proto);

		/*
		 *	WTF?
		 */
		if (!client) goto unknown;
		if (!client->client_server) goto unknown;

		/*
		 *	At this point, 'client' is the enclosing
		 *	network that configures where dynamic clients
		 *	can be defined.
		 */
		rad_assert(client->dynamic == 0);
	} else {
		/*
		 *	The IP is unknown, so we've found an enclosing
		 *	network.  Enable DoS protection.  We only
		 *	allow one new client per second.  Known
		 *	clients aren't subject to this restriction.
		 */
		if (now == client->last_new_client) goto unknown;
	}

	client->last_new_client = now;

	request = request_alloc();
	if (!request) goto unknown;

	request->listener = listener;
	request->client = client;
	request->packet = rad_recv(listener->fd, 0x02); /* MSG_PEEK */
	if (!request->packet) {				/* badly formed, etc */
		request_free(&request);
		goto unknown;
	}
	request->reply = rad_alloc_reply(request->packet);
	if (!request->reply) {
		request_free(&request);
		goto unknown;
	}
	request->packet->timestamp = request->timestamp;
	request->number = 0;
	request->priority = listener->type;
	request->server = client->client_server;
	request->root = &mainconfig;

	/*
	 *	Run a fake request through the given virtual server.
	 *	Look for FreeRADIUS-Client-IP-Address
	 *	         FreeRADIUS-Client-Secret
	 *		...
	 *
	 *	and create the RADCLIENT structure from that.
	 */
	DEBUG("server %s {", request->server);

	rcode = module_authorize(0, request);

	DEBUG("} # server %s", request->server);

	if (rcode != RLM_MODULE_OK) {
		request_free(&request);
		goto unknown;
	}

	/*
	 *	If the client was updated by rlm_dynamic_clients,
	 *	don't create the client from attribute-value pairs.
	 */
	if (request->client == client) {
		created = client_create(clients, request);
	} else {
		created = request->client;

		/*
		 *	This frees the client if it isn't valid.
		 */
		if (!client_validate(clients, client, created)) goto unknown;
	}
	request_free(&request);

	if (!created) goto unknown;

	return created;
#endif
}
Exemplo n.º 5
0
/*
 *	Process and reply to an authentication request
 *
 *	The return value of this function isn't actually used right now, so
 *	it's not entirely clear if it is returning the right things. --Pac.
 */
int rad_authenticate(REQUEST *request)
{
	VALUE_PAIR	*namepair;
	VALUE_PAIR	*check_item;
	VALUE_PAIR	*auth_item;
	VALUE_PAIR	*module_msg;
	VALUE_PAIR	*tmp = NULL;
	int		result, r;
	char		umsg[MAX_STRING_LEN + 1];
	const char	*user_msg = NULL;
	const char	*password;
	char		logstr[1024];
	char		autz_retry = 0;
	int		autz_type = 0;

	password = "";

	/*
	 *	If this request got proxied to another server,
	 *	AND it was an authentication request, then we need
	 *	to add an initial Auth-Type: Auth-Accept for success,
	 *	Auth-Reject for fail. We also need to add the reply
	 *	pairs from the server to the initial reply.
	 *
	 *	Huh?  If the request wasn't an authentication request,
	 *	WTF are we doing here?
	 */
	if ((request->proxy_reply) &&
	    (request->packet->code == PW_AUTHENTICATION_REQUEST)) {
		tmp = paircreate(PW_AUTH_TYPE, PW_TYPE_INTEGER);
		if (tmp == NULL) {
			radlog(L_ERR|L_CONS, "no memory");
			exit(1);
		}

		/*
		 *	Challenges are punted back to the NAS
		 *	without any further processing.
		 */
		if (request->proxy_reply->code == PW_ACCESS_CHALLENGE) {
			request->reply->code = PW_ACCESS_CHALLENGE;
			return RLM_MODULE_HANDLED;
		}

		/*
		 *	Reply of ACCEPT means accept, ALL other
		 *	replies mean reject.  This is fail-safe.
		 */
		if (request->proxy_reply->code == PW_AUTHENTICATION_ACK)
			tmp->lvalue = PW_AUTHTYPE_ACCEPT;
		else
			tmp->lvalue = PW_AUTHTYPE_REJECT;
		pairadd(&request->config_items, tmp);

		/*
		 *	If it's an Access-Reject, then do NOT do any
		 *	authorization or authentication.  They're being
		 *	rejected, so we minimize the amount of work
		 *	done by the server, by rejecting them here.
		 */
		if ((request->proxy_reply->code != PW_AUTHENTICATION_ACK) &&
		    (request->proxy_reply->code != PW_ACCESS_CHALLENGE)) {
			rad_authlog("Login incorrect (Home Server says so)", request, 0);
			request->reply->code = PW_AUTHENTICATION_REJECT;
			rad_postauth_reject(request);
			return RLM_MODULE_REJECT;
		}
	}

	/*
	 *	Get the username from the request.
	 *
	 *	Note that namepair MAY be NULL, in which case there
	 *	is no User-Name attribute in the request.
	 */
	namepair = request->username;

	/*
	 *	Look for, and cache, passwords.
	 */
	if (!request->password) {
		request->password = pairfind(request->packet->vps,
					     PW_PASSWORD);
	}

	/*
	 *	Discover which password we want to use.
	 */
	auth_item = request->password;
	if (auth_item) {
		password = (const char *)auth_item->strvalue;

	} else {
		/*
		 *	Maybe there's a CHAP-Password?
		 */
		if ((auth_item = pairfind(request->packet->vps,
				PW_CHAP_PASSWORD)) != NULL) {
			password = "******";

		} else {
			/*
			 *	No password we recognize.
			 */
			password = "******";
		}
	}
	request->password = auth_item;

	/*
	 *	Get the user's authorization information from the database
	 */
autz_redo:
	r = module_authorize(autz_type, request);
	if (r != RLM_MODULE_NOTFOUND &&
	    r != RLM_MODULE_NOOP &&
	    r != RLM_MODULE_OK &&
	    r != RLM_MODULE_UPDATED) {
		if (r != RLM_MODULE_FAIL && r != RLM_MODULE_HANDLED) {
			if ((module_msg = pairfind(request->packet->vps,
					PW_MODULE_FAILURE_MESSAGE)) != NULL){
				char msg[MAX_STRING_LEN+16];
				snprintf(msg, sizeof(msg), "Invalid user (%s)",
					 module_msg->strvalue);
				rad_authlog(msg,request,0);
			} else {
				rad_authlog("Invalid user", request, 0);
			}
			request->reply->code = PW_AUTHENTICATION_REJECT;
		}
		return r;
	}
	if (!autz_retry){
		VALUE_PAIR	*autz_type_item = NULL;
		autz_type_item = pairfind(request->config_items, PW_AUTZ_TYPE);
		if (autz_type_item){
			autz_type = autz_type_item->lvalue;
			autz_retry = 1;
			goto autz_redo;
		}
	}

	/*
	 *	If we haven't already proxied the packet, then check
	 *	to see if we should.  Maybe one of the authorize
	 *	modules has decided that a proxy should be used. If
	 *	so, get out of here and send the packet.
	 */
	if ((request->proxy == NULL) &&
	    ((tmp = pairfind(request->config_items, PW_PROXY_TO_REALM)) != NULL)) {
		REALM *realm;

		/*
		 *	Catch users who set Proxy-To-Realm to a LOCAL
		 *	realm (sigh).
		 */
		realm = realm_find(tmp->strvalue, 0);
		rad_assert((realm == NULL) || (realm->ipaddr.af == AF_INET));
		if (realm && (realm->ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_NONE))) {
			DEBUG2("  WARNING: You set Proxy-To-Realm = %s, but it is a LOCAL realm!  Cancelling invalid proxy request.", realm->realm);
		} else {
			/*
			 *	Don't authenticate, as the request is
			 *	proxied.
			 */
			return RLM_MODULE_OK;
		}
	}

	/*
	 *	Perhaps there is a Stripped-User-Name now.
	 */
	namepair = request->username;

	/*
	 *	Validate the user
	 */
	do {
		result = rad_check_password(request);
		if (result > 0) {
			/* don't reply! */
			return RLM_MODULE_HANDLED;
		}
	} while(0);

	/*
	 *	Failed to validate the user.
	 *
	 *	We PRESUME that the code which failed will clean up
	 *	request->reply->vps, to be ONLY the reply items it
	 *	wants to send back.
	 */
	if (result < 0) {
		DEBUG2("auth: Failed to validate the user.");
		request->reply->code = PW_AUTHENTICATION_REJECT;

		if ((module_msg = pairfind(request->packet->vps,PW_MODULE_FAILURE_MESSAGE)) != NULL){
			char msg[MAX_STRING_LEN+19];

			snprintf(msg, sizeof(msg), "Login incorrect (%s)",
				 module_msg->strvalue);
			rad_authlog(msg, request, 0);
		} else {
			rad_authlog("Login incorrect", request, 0);
		}

		/* double check: maybe the secret is wrong? */
		if ((debug_flag > 1) && (auth_item != NULL) &&
				(auth_item->attribute == PW_PASSWORD)) {
			u_char *p;

			p = auth_item->strvalue;
			while (*p != '\0') {
				if (!isprint((int) *p)) {
					log_debug("  WARNING: Unprintable characters in the password.\n\t  Double-check the shared secret on the server and the NAS!");
					break;
				}
				p++;
			}
		}
	}

	if (result >= 0 &&
	    (check_item = pairfind(request->config_items, PW_SIMULTANEOUS_USE)) != NULL) {
		VALUE_PAIR	*session_type;
		int		sess_type = 0;

		session_type = pairfind(request->config_items, PW_SESSION_TYPE);
		if (session_type)
			sess_type = session_type->lvalue;

		/*
		 *	User authenticated O.K. Now we have to check
		 *	for the Simultaneous-Use parameter.
		 */
		if (namepair &&
		    (r = module_checksimul(sess_type,request, check_item->lvalue)) != 0) {
			char mpp_ok = 0;

			if (r == 2){
				/* Multilink attempt. Check if port-limit > simultaneous-use */
				VALUE_PAIR *port_limit;

				if ((port_limit = pairfind(request->reply->vps, PW_PORT_LIMIT)) != NULL &&
					port_limit->lvalue > check_item->lvalue){
					DEBUG2("main auth: MPP is OK");
					mpp_ok = 1;
				}
			}
			if (!mpp_ok){
				if (check_item->lvalue > 1) {
		  		snprintf(umsg, sizeof(umsg),
							"\r\nYou are already logged in %d times  - access denied\r\n\n",
							(int)check_item->lvalue);
					user_msg = umsg;
				} else {
					user_msg = "\r\nYou are already logged in - access denied\r\n\n";
				}

				request->reply->code = PW_AUTHENTICATION_REJECT;

				/*
				 *	They're trying to log in too many times.
				 *	Remove ALL reply attributes.
				 */
				pairfree(&request->reply->vps);
				tmp = pairmake("Reply-Message", user_msg, T_OP_SET);
				request->reply->vps = tmp;

				snprintf(logstr, sizeof(logstr), "Multiple logins (max %d) %s",
					check_item->lvalue,
					r == 2 ? "[MPP attempt]" : "");
				rad_authlog(logstr, request, 1);

				result = -1;
			}
		}
	}

	/*
	 *	Result should be >= 0 here - if not, it means the user
	 *	is rejected, so we just process post-auth and return.
	 */
	if (result < 0) {
		rad_postauth_reject(request);
		return RLM_MODULE_REJECT;
	}

	/*
	 *	We might need this later.  The 'password' string
	 *	is NOT used anywhere below here, except for logging,
	 *	so it should be safe...
	 */
	if ((auth_item != NULL) && (auth_item->attribute == PW_CHAP_PASSWORD)) {
		password = "******";
	}

	/*
	 *	Add the port number to the Framed-IP-Address if
	 *	vp->addport is set.
	 */
	if (((tmp = pairfind(request->reply->vps,
			     PW_FRAMED_IP_ADDRESS)) != NULL) &&
	    (tmp->flags.addport != 0)) {
		VALUE_PAIR *vpPortId;

		/*
		 *  Find the NAS port ID.
		 */
		if ((vpPortId = pairfind(request->packet->vps,
					 PW_NAS_PORT)) != NULL) {
		  unsigned long tvalue = ntohl(tmp->lvalue);
		  tmp->lvalue = htonl(tvalue + vpPortId->lvalue);
		  tmp->flags.addport = 0;
		  ip_ntoa(tmp->strvalue, tmp->lvalue);
		} else {
			DEBUG2("WARNING: No NAS-Port attribute in request.  CANNOT return a Framed-IP-Address + NAS-Port.\n");
			pairdelete(&request->reply->vps, PW_FRAMED_IP_ADDRESS);
		}
	}

	/*
	 *	Set the reply to Access-Accept, if it hasn't already
	 *	been set to something.  (i.e. Access-Challenge)
	 */
	if (request->reply->code == 0)
	  request->reply->code = PW_AUTHENTICATION_ACK;

	if ((module_msg = pairfind(request->packet->vps,PW_MODULE_SUCCESS_MESSAGE)) != NULL){
		char msg[MAX_STRING_LEN+12];

		snprintf(msg, sizeof(msg), "Login OK (%s)",
			 module_msg->strvalue);
		rad_authlog(msg, request, 1);
	} else {
		rad_authlog("Login OK", request, 1);
	}

	/*
	 *	Run the modules in the 'post-auth' section.
	 */
	result = rad_postauth(request);

	return result;
}