Example #1
0
/*
 *	Store logins in the RADIUS utmp file.
 */
static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
{
	rlm_rcode_t	rcode = RLM_MODULE_OK;
	struct radutmp	ut, u;
	vp_cursor_t	cursor;
	VALUE_PAIR	*vp;
	int		status = -1;
	int		protocol = -1;
	time_t		t;
	int		fd = -1;
	int		port_seen = 0;
	int		off;
	rlm_radutmp_t	*inst = instance;
	char		ip_name[32]; /* 255.255.255.255 */
	char const	*nas;
	NAS_PORT	*cache;
	int		r;
	
	char		*filename = NULL;
	char		*expanded = NULL;

	if (request->packet->src_ipaddr.af != AF_INET) {
		DEBUG("rlm_radutmp: IPv6 not supported!");
		return RLM_MODULE_NOOP;
	}

	/*
	 *	Which type is this.
	 */
	if ((vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY)) == NULL) {
		RDEBUG("No Accounting-Status-Type record.");
		return RLM_MODULE_NOOP;
	}
	status = vp->vp_integer;

	/*
	 *	Look for weird reboot packets.
	 *
	 *	ComOS (up to and including 3.5.1b20) does not send
	 *	standard PW_STATUS_ACCOUNTING_XXX messages.
	 *
	 *	Check for:  o no Acct-Session-Time, or time of 0
	 *		    o Acct-Session-Id of "00000000".
	 *
	 *	We could also check for NAS-Port, that attribute
	 *	should NOT be present (but we don't right now).
	 */
	if ((status != PW_STATUS_ACCOUNTING_ON) &&
	    (status != PW_STATUS_ACCOUNTING_OFF)) do {
		int check1 = 0;
		int check2 = 0;

		if ((vp = pairfind(request->packet->vps, PW_ACCT_SESSION_TIME, 0, TAG_ANY))
		     == NULL || vp->vp_date == 0)
			check1 = 1;
		if ((vp = pairfind(request->packet->vps, PW_ACCT_SESSION_ID, 0, TAG_ANY))
		     != NULL && vp->length == 8 &&
		     memcmp(vp->vp_strvalue, "00000000", 8) == 0)
			check2 = 1;
		if (check1 == 0 || check2 == 0) {
			break;
		}
		INFO("rlm_radutmp: converting reboot records.");
		if (status == PW_STATUS_STOP)
			status = PW_STATUS_ACCOUNTING_OFF;
		if (status == PW_STATUS_START)
			status = PW_STATUS_ACCOUNTING_ON;
	} while(0);

	time(&t);
	memset(&ut, 0, sizeof(ut));
	ut.porttype = 'A';
	ut.nas_address = htonl(INADDR_NONE);

	/*
	 *	First, find the interesting attributes.
	 */
	for (vp = paircursor(&cursor, &request->packet->vps);
	     vp;
	     vp = pairnext(&cursor)) {
		if (!vp->da->vendor) switch (vp->da->attr) {
			case PW_LOGIN_IP_HOST:
			case PW_FRAMED_IP_ADDRESS:
				ut.framed_address = vp->vp_ipaddr;
				break;
			case PW_FRAMED_PROTOCOL:
				protocol = vp->vp_integer;
				break;
			case PW_NAS_IP_ADDRESS:
				ut.nas_address = vp->vp_ipaddr;
				break;
			case PW_NAS_PORT:
				ut.nas_port = vp->vp_integer;
				port_seen = 1;
				break;
			case PW_ACCT_DELAY_TIME:
				ut.delay = vp->vp_integer;
				break;
			case PW_ACCT_SESSION_ID:
				/*
				 *	If length > 8, only store the
				 *	last 8 bytes.
				 */
				off = vp->length - sizeof(ut.session_id);
				/*
				 * 	Ascend is br0ken - it adds a \0
				 * 	to the end of any string.
				 * 	Compensate.
				 */
				if (vp->length > 0 &&
				    vp->vp_strvalue[vp->length - 1] == 0)
					off--;
				if (off < 0) off = 0;
				memcpy(ut.session_id, vp->vp_strvalue + off,
					sizeof(ut.session_id));
				break;
			case PW_NAS_PORT_TYPE:
				if (vp->vp_integer <= 4)
					ut.porttype = porttypes[vp->vp_integer];
				break;
			case PW_CALLING_STATION_ID:
				if(inst->caller_id_ok)
					strlcpy(ut.caller_id,
						vp->vp_strvalue,
						sizeof(ut.caller_id));
				break;
		}
	}

	/*
	 *	If we didn't find out the NAS address, use the
	 *	originator's IP address.
	 */
	if (ut.nas_address == htonl(INADDR_NONE)) {
		ut.nas_address = request->packet->src_ipaddr.ipaddr.ip4addr.s_addr;
		nas = request->client->shortname;

	} else if (request->packet->src_ipaddr.ipaddr.ip4addr.s_addr == ut.nas_address) {		/* might be a client, might not be. */
		nas = request->client->shortname;

	} else {
		/*
		 *	The NAS isn't a client, it's behind
		 *	a proxy server.  In that case, just
		 *	get the IP address.
		 */
		nas = ip_ntoa(ip_name, ut.nas_address);
	}

	/*
	 *	Set the protocol field.
	 */
	if (protocol == PW_PPP) {
		ut.proto = 'P';
	} else if (protocol == PW_SLIP) {
		ut.proto = 'S';
	} else {
		ut.proto = 'T';
	}
	
	ut.time = t - ut.delay;

	/*
	 *	Get the utmp filename, via xlat.
	 */
	filename = NULL;
	if (radius_axlat(&filename, request, inst->filename, NULL, NULL) < 0) {
		return RLM_MODULE_FAIL;
	}

	/*
	 *	See if this was a reboot.
	 *
	 *	Hmm... we may not want to zap all of the users when the NAS comes up, because of issues with receiving
	 *	UDP packets out of order.
	 */
	if (status == PW_STATUS_ACCOUNTING_ON && (ut.nas_address != htonl(INADDR_NONE))) {
		RIDEBUG("NAS %s restarted (Accounting-On packet seen)", nas);
		rcode = radutmp_zap(request, filename, ut.nas_address, ut.time);
		
		goto finish;
	}

	if (status == PW_STATUS_ACCOUNTING_OFF && (ut.nas_address != htonl(INADDR_NONE))) {
		RIDEBUG("NAS %s rebooted (Accounting-Off packet seen)", nas);	
		rcode = radutmp_zap(request, filename, ut.nas_address, ut.time);
		
		goto finish;
	}

	/*
	 *	If we don't know this type of entry pretend we succeeded.
	 */
	if (status != PW_STATUS_START && status != PW_STATUS_STOP && status != PW_STATUS_ALIVE) {
		REDEBUG("NAS %s port %u unknown packet type %d)", nas, ut.nas_port, status);
		rcode = RLM_MODULE_NOOP;
		
		goto finish;
	}

	/*
	 *	Translate the User-Name attribute, or whatever else they told us to use.
	 */
	if (radius_axlat(&expanded, request, inst->username, NULL, NULL) < 0) {
		rcode = RLM_MODULE_FAIL;
		
		goto finish;
	}
	strlcpy(ut.login, expanded, RUT_NAMESIZE);
	TALLOC_FREE(expanded);

	/*
	 *	Perhaps we don't want to store this record into
	 *	radutmp. We skip records:
	 *
	 *	- without a NAS-Port (telnet / tcp access)
	 *	- with the username "!root" (console admin login)
	 */
	if (!port_seen) {
		RWDEBUG2("No NAS-Port seen.  Cannot do anything. Checkrad will probably not work!");
		rcode = RLM_MODULE_NOOP;
		
		goto finish;
	}

	if (strncmp(ut.login, "!root", RUT_NAMESIZE) == 0) {
		RDEBUG2("Not recording administrative user");
		rcode = RLM_MODULE_NOOP;
		
		goto finish;
	}

	/*
	 *	Enter into the radutmp file.
	 */
	fd = open(filename, O_RDWR|O_CREAT, inst->permission);
	if (fd < 0) {
		REDEBUG("Error accessing file %s: %s", filename, strerror(errno));
		rcode = RLM_MODULE_FAIL;
	
		goto finish;
	}

	/*
	 *	Lock the utmp file, prefer lockf() over flock().
	 */
	rad_lockfd(fd, LOCK_LEN);

	/*
	 *	Find the entry for this NAS / portno combination.
	 */
	if ((cache = nas_port_find(inst->nas_port_list, ut.nas_address, ut.nas_port)) != NULL) {
		lseek(fd, (off_t)cache->offset, SEEK_SET);
	}

	r = 0;
	off = 0;
	while (read(fd, &u, sizeof(u)) == sizeof(u)) {
		off += sizeof(u);
		if ((u.nas_address != ut.nas_address) || (u.nas_port != ut.nas_port)) {
			continue;
		}

		/*
		 *	Don't compare stop records to unused entries.
		 */
		if (status == PW_STATUS_STOP && u.type == P_IDLE) {
			continue;
		}

		if ((status == PW_STATUS_STOP) && strncmp(ut.session_id, u.session_id, sizeof(u.session_id)) != 0) {
			/*
			 *	Don't complain if this is not a
			 *	login record (some clients can
			 *	send _only_ logout records).
			 */
			if (u.type == P_LOGIN) {
				RWDEBUG("Logout entry for NAS %s port %u has wrong ID", nas, u.nas_port);
			}
			
			r = -1;
			break;
		}

		if ((status == PW_STATUS_START) && strncmp(ut.session_id, u.session_id, sizeof(u.session_id)) == 0  &&
		    u.time >= ut.time) {
			if (u.type == P_LOGIN) {
				INFO("rlm_radutmp: Login entry for NAS %s port %u duplicate",
				       nas, u.nas_port);
				r = -1;
				break;
			}
			
			RWDEBUG("Login entry for NAS %s port %u wrong order", nas, u.nas_port);
			r = -1;
			break;
		}

		/*
		 *	FIXME: the ALIVE record could need some more checking, but anyway I'd
		 *	rather rewrite this mess -- miquels.
		 */
		if ((status == PW_STATUS_ALIVE) && strncmp(ut.session_id, u.session_id, sizeof(u.session_id)) == 0  &&
		    u.type == P_LOGIN) {
			/*
			 *	Keep the original login time.
			 */
			ut.time = u.time;
		}

		if (lseek(fd, -(off_t)sizeof(u), SEEK_CUR) < 0) {
			RWDEBUG("negative lseek!");
			lseek(fd, (off_t)0, SEEK_SET);
			off = 0;
		} else {
			off -= sizeof(u);
		}
		
		r = 1;
		break;
	} /* read the file until we find a match */

	/*
	 *	Found the entry, do start/update it with
	 *	the information from the packet.
	 */
	if ((r >= 0) && (status == PW_STATUS_START || status == PW_STATUS_ALIVE)) {
		/*
		 *	Remember where the entry was, because it's
		 *	easier than searching through the entire file.
		 */
		if (!cache) {
			cache = talloc_zero(inst, NAS_PORT);
			if (cache) {
				cache->nasaddr = ut.nas_address;
				cache->port = ut.nas_port;
				cache->offset = off;
				cache->next = inst->nas_port_list;
				inst->nas_port_list = cache;
			}
		}

		ut.type = P_LOGIN;
		if (write(fd, &ut, sizeof(u)) < 0) {
			REDEBUG("Failed writing: %s", strerror(errno));
			
			rcode = RLM_MODULE_FAIL;
			goto finish;
		}
	}

	/*
	 *	The user has logged off, delete the entry by
	 *	re-writing it in place.
	 */
	if (status == PW_STATUS_STOP) {
		if (r > 0) {
			u.type = P_IDLE;
			u.time = ut.time;
			u.delay = ut.delay;
			if (write(fd, &u, sizeof(u)) < 0) {
				REDEBUG("Failed writing: %s", strerror(errno));
			
				rcode = RLM_MODULE_FAIL;
				goto finish;
			}
		} else if (r == 0) {
			RWDEBUG("Logout for NAS %s port %u, but no Login record", nas, ut.nas_port);
		}
	}

	finish:
	
	talloc_free(filename);
	
	if (fd > -1) {
		close(fd);	/* and implicitely release the locks */
	}
	
	return rcode;
}
Example #2
0
/**
 * @brief Parses the MS-SOH type/value (note: NOT type/length/value) data and
 * 	update the sohvp list
 *
 * See section 2.2.4 of MS-SOH. Because there's no "length" field we CANNOT just skip
 * unknown types; we need to know their length ahead of time. Therefore, we abort
 * if we find an unknown type. Note that sohvp may still have been modified in the
 * failure case.
 *
 * @param request Current request
 * @param p binary blob
 * @param data_len length of blob
 * @return 1 on success, 0 on failure
 */
static int eapsoh_mstlv(REQUEST *request, uint8_t const *p, unsigned int data_len)
{
	VALUE_PAIR *vp;
	uint8_t c;
	int t;
	char *q;

	while (data_len > 0) {
		c = *p++;
		data_len--;

		switch (c) {
			case 1:
				/* MS-Machine-Inventory-Packet
				 * MS-SOH section 2.2.4.1
				 */
				if (data_len < 18) {
					RDEBUG("insufficient data for MS-Machine-Inventory-Packet");
					return 0;
				}
				data_len -= 18;

				vp = pairmake_packet("SoH-MS-Machine-OS-vendor", "Microsoft", T_OP_EQ);
				if (!vp) return 0;

				vp = pairmake_packet("SoH-MS-Machine-OS-version", NULL, T_OP_EQ);
				if (!vp) return 0;

				vp->vp_integer = soh_pull_be_32(p); p+=4;

				vp = pairmake_packet("SoH-MS-Machine-OS-release", NULL, T_OP_EQ);
				if (!vp) return 0;

				vp->vp_integer = soh_pull_be_32(p); p+=4;

				vp = pairmake_packet("SoH-MS-Machine-OS-build", NULL, T_OP_EQ);
				if (!vp) return 0;

				vp->vp_integer = soh_pull_be_32(p); p+=4;

				vp = pairmake_packet("SoH-MS-Machine-SP-version", NULL, T_OP_EQ);
				if (!vp) return 0;

				vp->vp_integer = soh_pull_be_16(p); p+=2;

				vp = pairmake_packet("SoH-MS-Machine-SP-release", NULL, T_OP_EQ);
				if (!vp) return 0;

				vp->vp_integer = soh_pull_be_16(p); p+=2;

				vp = pairmake_packet("SoH-MS-Machine-Processor", NULL, T_OP_EQ);
				if (!vp) return 0;

				vp->vp_integer = soh_pull_be_16(p); p+=2;
				break;

			case 2:
				/* MS-Quarantine-State - FIXME: currently unhandled
				 * MS-SOH 2.2.4.1
				 *
				 * 1 byte reserved
				 * 1 byte flags
				 * 8 bytes NT Time field (100-nanosec since 1 Jan 1601)
				 * 2 byte urilen
				 * N bytes uri
				 */
				p += 10;
				t = soh_pull_be_16(p);	/* t == uri len */
				p += 2;
				p += t;
				data_len -= 12 + t;
				break;

			case 3:
				/* MS-Packet-Info
				 * MS-SOH 2.2.4.3
				 */
				RDEBUG3("SoH MS-Packet-Info %s vers=%i", *p & 0x10 ? "request" : "response", *p & 0xf);
				p++;
				data_len--;
				break;

			case 4:
				/* MS-SystemGenerated-Ids - FIXME: currently unhandled
				 * MS-SOH 2.2.4.4
				 *
				 * 2 byte length
				 * N bytes (3 bytes IANA enterprise# + 1 byte component id#)
				 */
				t = soh_pull_be_16(p);
				p += 2;
				p += t;
				data_len -= 2 + t;
				break;

			case 5:
				/* MS-MachineName
				 * MS-SOH 2.2.4.5
				 *
				 * 1 byte namelen
				 * N bytes name
				 */
				t = soh_pull_be_16(p);
				p += 2;

				vp = pairmake_packet("SoH-MS-Machine-Name", NULL, T_OP_EQ);
				if (!vp) return 0;

				vp->vp_strvalue = q = talloc_array(vp, char, t);
				vp->type = VT_DATA;

				memcpy(q, p, t);
				q[t] = 0;

				p += t;
				data_len -= 2 + t;
				break;

			case 6:
				/* MS-CorrelationId
				 * MS-SOH 2.2.4.6
				 *
				 * 24 bytes opaque binary which we might, in future, have
				 * to echo back to the client in a final SoHR
				 */
				vp = pairmake_packet("SoH-MS-Correlation-Id", NULL, T_OP_EQ);
				if (!vp) return 0;

				pairmemcpy(vp, p, 24);
				p += 24;
				data_len -= 24;
				break;

			case 7:
				/* MS-Installed-Shvs - FIXME: currently unhandled
				 * MS-SOH 2.2.4.7
				 *
				 * 2 bytes length
				 * N bytes (3 bytes IANA enterprise# + 1 byte component id#)
				 */
				t = soh_pull_be_16(p);
				p += 2;
				p += t;
				data_len -= 2 + t;
				break;

			case 8:
				/* MS-Machine-Inventory-Ex
				 * MS-SOH 2.2.4.8
				 *
				 * 4 bytes reserved
				 * 1 byte product type (client=1 domain_controller=2 server=3)
				 */
				p += 4;
				vp = pairmake_packet("SoH-MS-Machine-Role", NULL, T_OP_EQ);
				if (!vp) return 0;

				vp->vp_integer = *p;
				p++;
				data_len -= 5;
				break;

			default:
				RDEBUG("SoH Unknown MS TV %i stopping", c);
				return 0;
		}
	}
	return 1;
}
Example #3
0
/*
 *	Authenticate the user with the given password.
 */
static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
{
	rlm_smsotp_t *inst = instance;
	VALUE_PAIR *state;
	int bufsize;
	int *fdp;
	rlm_rcode_t rcode = RLM_MODULE_FAIL;
	char buffer[1000];
	char output[1000];

	fdp = fr_connection_get(inst->pool);
	if (!fdp) return RLM_MODULE_FAIL;

	/* Get greeting */
	bufsize = read_all(fdp, buffer, sizeof(buffer));
	if (bufsize <= 0) {
		REDEBUG("Failed reading from socket");
		goto done;
	}

	/*
	 *  Look for the 'state' attribute.
	 */
#define WRITE_ALL(_a,_b,_c) if (write_all(_a,_b,_c) < 0) goto done;
	state = fr_pair_find_by_num(request->packet->vps, PW_STATE, 0, TAG_ANY);
	if (state) {
		RDEBUG("Found reply to access challenge");

		/* send username */
		snprintf(output, sizeof(output), "check otp for %s\n",
			 request->username->vp_strvalue);
		WRITE_ALL(fdp, output, strlen(output));

		(void) read_all(fdp, buffer, sizeof(buffer));

		/* send password */
		snprintf(output, sizeof(output), "user otp is %s\n",
			 request->password->vp_strvalue);
		WRITE_ALL(fdp, output, strlen(output));

		(void) read_all(fdp, buffer, sizeof(buffer));

		/* set uuid */
		snprintf(output, sizeof(output), "otp id is %s\n",
			 state->vp_strvalue);
		WRITE_ALL(fdp, output, strlen(output));

		(void) read_all(fdp, buffer, sizeof(buffer));

		/* now check the otp */
		WRITE_ALL(fdp, "get check result\n", 17);

		(void) read_all(fdp, buffer, sizeof(buffer));

		/* end the sesssion */
		WRITE_ALL(fdp, "quit\n", 5);

		RDEBUG("answer is %s", buffer);
		if (strcmp(buffer,"OK") == 0) {
			rcode = RLM_MODULE_OK;
		}

		goto done;
	}

	RDEBUG("Generating OTP");

	/* set username */
	snprintf(output, sizeof(output), "generate otp for %s\n",
		 request->username->vp_strvalue);
	WRITE_ALL(fdp, output, strlen(output));

	(void) read_all(fdp, buffer, sizeof(buffer));

	/* end the sesssion */
	WRITE_ALL(fdp, "quit\n", 5);

	RDEBUG("Unique ID is %s", buffer);

	/* check the return string */
	if (strcmp(buffer,"FAILED") == 0) { /* smsotp script returns a error */
		goto done;
	}

	/*
	 *	Create the challenge, and add it to the reply.
	 */

	pair_make_reply("Reply-Message", inst->challenge, T_OP_EQ);
	pair_make_reply("State", buffer, T_OP_EQ);

	/*
	 *  Mark the packet as an Access-Challenge packet.
	 *
	 *  The server will take care of sending it to the user.
	 */
	request->reply->code = PW_CODE_ACCESS_CHALLENGE;
	DEBUG("rlm_smsotp: Sending Access-Challenge");

	rcode = RLM_MODULE_HANDLED;

done:
	fr_connection_release(inst->pool, fdp);
	return rcode;
}
/*
 *	Allocate an IP number from the pool.
 */
static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
{
	rlm_sqlippool_t *inst = (rlm_sqlippool_t *) instance;
	char allocation[MAX_STRING_LEN];
	int allocation_len;
	uint32_t ip_allocation;
	VALUE_PAIR *vp;
	rlm_sql_handle_t *handle;
	fr_ipaddr_t ipaddr;
	time_t now;

	/*
	 *	If there is a Framed-IP-Address attribute in the reply do nothing
	 */
	if (pairfind(request->reply->vps, PW_FRAMED_IP_ADDRESS, 0, TAG_ANY) != NULL) {
		RDEBUG("Framed-IP-Address already exists");

		return do_logging(request, inst->log_exists, RLM_MODULE_NOOP);
	}

	if (pairfind(request->config_items, PW_POOL_NAME, 0, TAG_ANY) == NULL) {
		RDEBUG("No Pool-Name defined");

		return do_logging(request, inst->log_nopool, RLM_MODULE_NOOP);
	}

	handle = inst->sql_inst->sql_get_socket(inst->sql_inst);
	if (!handle) {
		REDEBUG("cannot get sql connection");
		return RLM_MODULE_FAIL;
	}

	if (inst->sql_inst->sql_set_user(inst->sql_inst, request, NULL) < 0) {
		return RLM_MODULE_FAIL;
	}

	/*
	 *	Limit the number of clears we do.  There are minor
	 *	race conditions for the check, but so what.  The
	 *	actual work is protected by a transaction.  The idea
	 *	here is that if we're allocating 100 IPs a second,
	 *	we're only do 1 CLEAR per second.
	 */
	now = time(NULL);
	if (inst->last_clear < now) {
		inst->last_clear = now;

		DO(allocate_begin);
		DO(allocate_clear);
		DO(allocate_commit);
	}

	DO(allocate_begin);

	allocation_len = sqlippool_query1(allocation, sizeof(allocation),
					  inst->allocate_find, handle,
					  inst, request, (char *) NULL, 0);

	/*
	 *	Nothing found...
	 */
	if (allocation_len == 0) {
		DO(allocate_commit);

		/*
		 *Should we perform pool-check ?
		 */
		if (inst->pool_check && *inst->pool_check) {

			/*
			 *Ok, so the allocate-find query found nothing ...
			 *Let's check if the pool exists at all
			 */
			allocation_len = sqlippool_query1(allocation, sizeof(allocation),
							  inst->pool_check, handle, inst, request,
							  (char *) NULL, 0);

			inst->sql_inst->sql_release_socket(inst->sql_inst, handle);

			if (allocation_len) {

				/*
				 *	Pool exists after all... So,
				 *	the failure to allocate the IP
				 *	address was most likely due to
				 *	the depletion of the pool. In
				 *	that case, we should return
				 *	NOTFOUND
				 */
				RDEBUG("pool appears to be full");
				return do_logging(request, inst->log_failed, RLM_MODULE_NOTFOUND);

			}

			/*
			 *	Pool doesn't exist in the table. It
			 *	may be handled by some other instance of
			 *	sqlippool, so we should just ignore this
			 *	allocation failure and return NOOP
			 */
			RDEBUG("IP address could not be allocated as no pool exists with that name");
			return RLM_MODULE_NOOP;

		}

		inst->sql_inst->sql_release_socket(inst->sql_inst, handle);

		RDEBUG("IP address could not be allocated");
		return do_logging(request, inst->log_failed, RLM_MODULE_NOOP);
	}

	/*
	 *	FIXME: Make it work with the ipv6 addresses
	 */
	if ((ip_hton(&ipaddr, AF_INET, allocation, false) < 0) ||
	    ((ip_allocation = ipaddr.ipaddr.ip4addr.s_addr) == INADDR_NONE)) {
		DO(allocate_commit);

		RDEBUG("Invalid IP number [%s] returned from instbase query.", allocation);
		inst->sql_inst->sql_release_socket(inst->sql_inst, handle);
		return do_logging(request, inst->log_failed, RLM_MODULE_NOOP);
	}

	/*
	 *	UPDATE
	 */
	sqlippool_command(inst->allocate_update, handle, inst, request,
			  allocation, allocation_len);

	RDEBUG("Allocated IP %s [%08x]", allocation, ip_allocation);

	vp = radius_paircreate(request->reply, &request->reply->vps,
			       PW_FRAMED_IP_ADDRESS, 0);
	vp->vp_ipaddr = ip_allocation;
	vp->length = 4;

	DO(allocate_commit);

	inst->sql_inst->sql_release_socket(inst->sql_inst, handle);

	return do_logging(request, inst->log_success, RLM_MODULE_OK);
}
Example #5
0
/** Compares check and vp by value.
 *
 * Does not call any per-attribute comparison function, but does honour
 * check.operator. Basically does "vp.value check.op check.value".
 *
 * @param request Current request.
 * @param check rvalue, and operator.
 * @param vp lvalue.
 * @return 0 if check and vp are equal, -1 if vp value is less than check value, 1 is vp value is more than check
 *	value, -2 on error.
 */
int radius_compare_vps(REQUEST *request, VALUE_PAIR *check, VALUE_PAIR *vp)
{
	int ret = 0;

	/*
	 *      Check for =* and !* and return appropriately
	 */
	if (check->op == T_OP_CMP_TRUE)  return 0;
	if (check->op == T_OP_CMP_FALSE) return 1;

#ifdef HAVE_REGEX_H
	if (check->op == T_OP_REG_EQ) {
		int compare;
		regex_t reg;
		char value[1024];
		regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];

		vp_prints_value(value, sizeof(value), vp, -1);

		/*
		 *	Include substring matches.
		 */
		compare = regcomp(&reg, check->vp_strvalue, REG_EXTENDED);
		if (compare != 0) {
			char buffer[256];
			regerror(compare, &reg, buffer, sizeof(buffer));

			RDEBUG("Invalid regular expression %s: %s", check->vp_strvalue, buffer);
			return -2;
		}

		memset(&rxmatch, 0, sizeof(rxmatch));	/* regexec does not seem to initialise unused elements */
		compare = regexec(&reg, value, REQUEST_MAX_REGEX + 1, rxmatch, 0);
		regfree(&reg);
		rad_regcapture(request, compare, value, rxmatch);

		ret = (compare == 0) ? 0 : -1;
		goto finish;
	}

	if (check->op == T_OP_REG_NE) {
		int compare;
		regex_t reg;
		char value[1024];
		regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];

		vp_prints_value(value, sizeof(value), vp, -1);

		/*
		 *	Include substring matches.
		 */
		compare = regcomp(&reg, check->vp_strvalue, REG_EXTENDED);
		if (compare != 0) {
			char buffer[256];
			regerror(compare, &reg, buffer, sizeof(buffer));

			RDEBUG("Invalid regular expression %s: %s", check->vp_strvalue, buffer);
			return -2;
		}
		compare = regexec(&reg, value,  REQUEST_MAX_REGEX + 1, rxmatch, 0);
		regfree(&reg);

		ret = (compare != 0) ? 0 : -1;
	}
#endif

	/*
	 *	Attributes must be of the same type.
	 *
	 *	FIXME: deal with type mismatch properly if one side contain
	 *	ABINARY, OCTETS or STRING by converting the other side to
	 *	a string
	 *
	 */
	if (vp->da->type != check->da->type) return -1;

	/*
	 *	Tagged attributes are equal if and only if both the
	 *	tag AND value match.
	 */
	if (check->da->flags.has_tag) {
		ret = ((int) vp->tag) - ((int) check->tag);
		goto finish;
	}

	/*
	 *	Not a regular expression, compare the types.
	 */
	switch(check->da->type) {
#ifdef WITH_ASCEND_BINARY
		/*
		 *	Ascend binary attributes can be treated
		 *	as opaque objects, I guess...
		 */
		case PW_TYPE_ABINARY:
#endif
		case PW_TYPE_OCTETS:
			if (vp->length != check->length) {
				ret = 1; /* NOT equal */
				break;
			}
			ret = memcmp(vp->vp_strvalue, check->vp_strvalue,
				     vp->length);
			break;

		case PW_TYPE_STRING:
			ret = strcmp(vp->vp_strvalue,
				     check->vp_strvalue);
			break;

		case PW_TYPE_BYTE:
		case PW_TYPE_SHORT:
		case PW_TYPE_INTEGER:
			ret = vp->vp_integer - check->vp_integer;
			break;

		case PW_TYPE_INTEGER64:
			/*
			 *	Don't want integer overflow!
			 */
			if (vp->vp_integer64 < check->vp_integer64) {
				ret = -1;
			} else if (vp->vp_integer64 > check->vp_integer64) {
				ret = +1;
			} else {
				ret = 0;
			}
			break;

		case PW_TYPE_SIGNED:
			if (vp->vp_signed < check->vp_signed) {
				ret = -1;
			} else if (vp->vp_signed > check->vp_signed) {
				ret = +1;
			} else {
				ret = 0;
			}
			break;

		case PW_TYPE_DATE:
			ret = vp->vp_date - check->vp_date;
			break;

		case PW_TYPE_IPADDR:
			ret = ntohl(vp->vp_ipaddr) - ntohl(check->vp_ipaddr);
			break;

		case PW_TYPE_IPV6ADDR:
			ret = memcmp(&vp->vp_ipv6addr, &check->vp_ipv6addr,
				     sizeof(vp->vp_ipv6addr));
			break;

		case PW_TYPE_IPV6PREFIX:
			ret = memcmp(&vp->vp_ipv6prefix, &check->vp_ipv6prefix,
				     sizeof(vp->vp_ipv6prefix));
			break;

		case PW_TYPE_IFID:
			ret = memcmp(&vp->vp_ifid, &check->vp_ifid,
				     sizeof(vp->vp_ifid));
			break;

		default:
			break;
	}

	finish:
	if (ret > 0) {
		return 1;
	}
	if (ret < 0) {
		return -1;
	}
	return 0;
}
Example #6
0
static int redisn_groupcmp(void *instance, REQUEST *request, VALUE_PAIR *request_vp, VALUE_PAIR *check,
			VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
{
	REDISSOCK *redis_socket;
	REDIS_INST *inst = instance;
	char redisnusername[MAX_STRING_LEN];
	REDISN_GROUPLIST *group_list, *group_list_tmp;

	check_pairs = check_pairs;
	reply_pairs = reply_pairs;
	request_vp = request_vp;

	RDEBUG("redisn_groupcmp");
	if (!check || !check->vp_strvalue || !check->length){
		RDEBUG("redisn_groupcmp: Illegal group name");
		return 1;
	}
	if (!request){
		RDEBUG("redisn_groupcmp: NULL request");
		return 1;
	}
	/*
	 * Set, escape, and check the user attr here
	 */
	if (redisn_set_user(inst, request, redisnusername, NULL) < 0)
		return 1;

	/*
	 *	Get a socket for this lookup
	 */
	redis_socket = redisn_get_socket(inst);
	if (redis_socket == NULL) {
		/* Remove the username we (maybe) added above */
		pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY);
		return 1;
	}

	/*
	 *	Get the list of groups this user is a member of
	 */
	if (redisn_get_grouplist(inst, redis_socket, request, &group_list) < 0) {
		radlog_request(L_ERR, 0, request,
			       "Error getting group membership");
		/* Remove the username we (maybe) added above */
		pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY);
		redisn_release_socket(inst, redis_socket);
		return 1;
	}

	for (group_list_tmp = group_list; group_list_tmp != NULL; group_list_tmp = group_list_tmp->next) {
		if (strcmp(group_list_tmp->groupname, check->vp_strvalue) == 0){
			RDEBUG("redisn_groupcmp finished: User is a member of group %s",
			       check->vp_strvalue);
			/* Free the grouplist */
			redisn_grouplist_free(&group_list);
			/* Remove the username we (maybe) added above */
			pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY);
			redisn_release_socket(inst, redis_socket);
			return 0;
		}
	}

	/* Free the grouplist */
	redisn_grouplist_free(&group_list);
	/* Remove the username we (maybe) added above */
	pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY);
	redisn_release_socket(inst,redis_socket);

	RDEBUG("redisn_groupcmp finished: User is NOT a member of group %s",
	       check->vp_strvalue);

	return 1;
}
Example #7
0
/** Start a process
 *
 * @param cmd Command to execute. This is parsed into argv[] parts,
 * 	then each individual argv part is xlat'ed.
 * @param request Current reuqest
 * @param exec_wait set to 1 if you want to read from or write to child
 * @param[in,out] input_fd pointer to int, receives the stdin file.
 * 	descriptor. Set to NULL and the child will have /dev/null on stdin
 * @param[in,out] output_fd pinter to int, receives the stdout file
 * 	descriptor. Set to NULL and child will have /dev/null on stdout.
 * @param input_pairs list of value pairs - these will be put into
 * 	the environment variables of the child.
 * @param shell_escape values before passing them as arguments.
 * @return PID of the child process, -1 on error.
 */
pid_t radius_start_program(char const *cmd, REQUEST *request, bool exec_wait,
			   int *input_fd, int *output_fd,
			   VALUE_PAIR *input_pairs, bool shell_escape)
{
#ifndef __MINGW32__
	char *p;
	VALUE_PAIR *vp;
	int n;
	int to_child[2] = {-1, -1};
	int from_child[2] = {-1, -1};
	pid_t pid;
#endif
	int argc;
	int i;
	char *argv[MAX_ARGV];
	char argv_buf[4096];
#define MAX_ENVP 1024
	char *envp[MAX_ENVP];
	int envlen = 0;

	argc = rad_expand_xlat(request, cmd, MAX_ARGV, argv, true, sizeof(argv_buf), argv_buf);
	if (argc <= 0) {
		RDEBUG("invalid command line '%s'.", cmd);
		return -1;
	}


#ifndef NDEBUG
	if (debug_flag > 2) {
		RDEBUG3("executing cmd %s", cmd);
		for (i = 0; i < argc; i++) {
			RDEBUG3("\t[%d] %s", i, argv[i]);
		}
	}
#endif

#ifndef __MINGW32__
	/*
	 *	Open a pipe for child/parent communication, if necessary.
	 */
	if (exec_wait) {
		if (input_fd) {
			if (pipe(to_child) != 0) {
				RDEBUG("Couldn't open pipe to child: %s", fr_syserror(errno));
				return -1;
			}
		}
		if (output_fd) {
			if (pipe(from_child) != 0) {
				RDEBUG("Couldn't open pipe from child: %s", fr_syserror(errno));
				/* safe because these either need closing or are == -1 */
				close(to_child[0]);
				close(to_child[1]);
				return -1;
			}
		}
	}

	envp[0] = NULL;

	if (input_pairs) {
		vp_cursor_t cursor;
		char buffer[1024];

		/*
		 *	Set up the environment variables in the
		 *	parent, so we don't call libc functions that
		 *	hold mutexes.  They might be locked when we fork,
		 *	and will remain locked in the child.
		 */
		for (vp = fr_cursor_init(&cursor, &input_pairs); vp; vp = fr_cursor_next(&cursor)) {
			/*
			 *	Hmm... maybe we shouldn't pass the
			 *	user's password in an environment
			 *	variable...
			 */
			snprintf(buffer, sizeof(buffer), "%s=", vp->da->name);
			if (shell_escape) {
				for (p = buffer; *p != '='; p++) {
					if (*p == '-') {
						*p = '_';
					} else if (isalpha((int) *p)) {
						*p = toupper(*p);
					}
				}
			}

			n = strlen(buffer);
			vp_prints_value(buffer + n, sizeof(buffer) - n, vp, shell_escape ? '"' : 0);

			envp[envlen++] = strdup(buffer);

			/*
			 *	Don't add too many attributes.
			 */
			if (envlen == (MAX_ENVP - 1)) break;

			/*
			 *	NULL terminate for execve
			 */
			envp[envlen] = NULL;
		}
	}

	if (exec_wait) {
		pid = rad_fork();	/* remember PID */
	} else {
		pid = fork();		/* don't wait */
	}

	if (pid == 0) {
		int devnull;

		/*
		 *	Child process.
		 *
		 *	We try to be fail-safe here. So if ANYTHING
		 *	goes wrong, we exit with status 1.
		 */

		/*
		 *	Open STDIN to /dev/null
		 */
		devnull = open("/dev/null", O_RDWR);
		if (devnull < 0) {
			RDEBUG("Failed opening /dev/null: %s\n", fr_syserror(errno));

			/*
			 *	Where the status code is interpreted as a module rcode
			 * 	one is subtracted from it, to allow 0 to equal success
			 *
			 *	2 is RLM_MODULE_FAIL + 1
			 */
			exit(2);
		}

		/*
		 *	Only massage the pipe handles if the parent
		 *	has created them.
		 */
		if (exec_wait) {
			if (input_fd) {
				close(to_child[1]);
				dup2(to_child[0], STDIN_FILENO);
			} else {
				dup2(devnull, STDIN_FILENO);
			}

			if (output_fd) {
				close(from_child[0]);
				dup2(from_child[1], STDOUT_FILENO);
			} else {
				dup2(devnull, STDOUT_FILENO);
			}

		} else {	/* no pipe, STDOUT should be /dev/null */
			dup2(devnull, STDIN_FILENO);
			dup2(devnull, STDOUT_FILENO);
		}

		/*
		 *	If we're not debugging, then we can't do
		 *	anything with the error messages, so we throw
		 *	them away.
		 *
		 *	If we are debugging, then we want the error
		 *	messages to go to the STDERR of the server.
		 */
		if (debug_flag == 0) {
			dup2(devnull, STDERR_FILENO);
		}
		close(devnull);

		/*
		 *	The server may have MANY FD's open.  We don't
		 *	want to leave dangling FD's for the child process
		 *	to play funky games with, so we close them.
		 */
		closefrom(3);

		/*
		 *	I swear the signature for execve is wrong and should take 'char const * const argv[]'.
		 */
		execve(argv[0], argv, envp);
		printf("Failed to execute \"%s\": %s", argv[0], fr_syserror(errno)); /* fork output will be captured */

		/*
		 *	Where the status code is interpreted as a module rcode
		 * 	one is subtracted from it, to allow 0 to equal success
		 *
		 *	2 is RLM_MODULE_FAIL + 1
		 */
		exit(2);
	}

	/*
	 *	Free child environment variables
	 */
	for (i = 0; i < envlen; i++) {
		free(envp[i]);
	}

	/*
	 *	Parent process.
	 */
	if (pid < 0) {
		RDEBUG("Couldn't fork %s: %s", argv[0], fr_syserror(errno));
		if (exec_wait) {
			/* safe because these either need closing or are == -1 */
			close(to_child[0]);
			close(to_child[1]);
			close(from_child[0]);
			close(from_child[1]);
		}
		return -1;
	}

	/*
	 *	We're not waiting, exit, and ignore any child's status.
	 */
	if (exec_wait) {
		/*
		 *	Close the ends of the pipe(s) the child is using
		 *	return the ends of the pipe(s) our caller wants
		 *
		 */
		if (input_fd) {
			*input_fd = to_child[1];
			close(to_child[0]);
		}
		if (output_fd) {
			*output_fd = from_child[0];
			close(from_child[1]);
		}
	}

	return pid;
#else
	if (exec_wait) {
		RDEBUG("Wait is not supported");
		return -1;
	}

	{
		/*
		 *	The _spawn and _exec families of functions are
		 *	found in Windows compiler libraries for
		 *	portability from UNIX. There is a variety of
		 *	functions, including the ability to pass
		 *	either a list or array of parameters, to
		 *	search in the PATH or otherwise, and whether
		 *	or not to pass an environment (a set of
		 *	environment variables). Using _spawn, you can
		 *	also specify whether you want the new process
		 *	to close your program (_P_OVERLAY), to wait
		 *	until the new process is finished (_P_WAIT) or
		 *	for the two to run concurrently (_P_NOWAIT).

		 *	_spawn and _exec are useful for instances in
		 *	which you have simple requirements for running
		 *	the program, don't want the overhead of the
		 *	Windows header file, or are interested
		 *	primarily in portability.
		 */

		/*
		 *	FIXME: check return code... what is it?
		 */
		_spawnve(_P_NOWAIT, argv[0], argv, envp);
	}

	return 0;
#endif
}
// Create a new client session. This should really check the version number.
CSession2* CCentRepToolServer::NewSessionL(const TVersion&,const RMessage2&) const
	{
	RDEBUG("CentRepToolServer: CCentRepToolServer::NewSessionL");
	return new (ELeave) CCentRepToolSession();
	}
// A new session is being created
// Cancel the shutdown timer if it was running
void CCentRepToolServer::AddSession()
	{
	RDEBUG("CentRepToolServer: CPolicyEngineServer::AddSession");
	++iSessionCount;
	iShutdown.Cancel();
	}
Example #10
0
/*
 *			SQL xlat function
 *
 *  For selects the first value of the first column will be returned,
 *  for inserts, updates and deletes the number of rows affected will be
 *  returned instead.
 */
static ssize_t sql_xlat(void *instance, REQUEST *request, char const *query, char *out, size_t freespace)
{
	rlm_sql_handle_t *handle = NULL;
	rlm_sql_row_t row;
	rlm_sql_t *inst = instance;
	ssize_t ret = 0;
	size_t len = 0;

	/*
	 *	Add SQL-User-Name attribute just in case it is needed
	 *	We could search the string fmt for SQL-User-Name to see if this is
	 * 	needed or not
	 */
	sql_set_user(inst, request, NULL);

	handle = fr_connection_get(inst->pool);
	if (!handle) {
		return 0;
	}

	rlm_sql_query_log(inst, request, NULL, query);

	/*
	 *	If the query starts with any of the following prefixes,
	 *	then return the number of rows affected
	 */
	if ((strncasecmp(query, "insert", 6) == 0) ||
	    (strncasecmp(query, "update", 6) == 0) ||
	    (strncasecmp(query, "delete", 6) == 0)) {
		int numaffected;
		char buffer[21]; /* 64bit max is 20 decimal chars + null byte */

		if (rlm_sql_query(&handle, inst, query) != RLM_SQL_OK) {
			char const *error = (inst->module->sql_error)(handle, inst->config);
			REDEBUG("SQL query failed: %s", error);

			ret = -1;
			goto finish;
		}

		numaffected = (inst->module->sql_affected_rows)(handle, inst->config);
		if (numaffected < 1) {
			RDEBUG("SQL query affected no rows");

			goto finish;
		}

		/*
		 *	Don't chop the returned number if freespace is
		 *	too small.  This hack is necessary because
		 *	some implementations of snprintf return the
		 *	size of the written data, and others return
		 *	the size of the data they *would* have written
		 *	if the output buffer was large enough.
		 */
		snprintf(buffer, sizeof(buffer), "%d", numaffected);

		len = strlen(buffer);
		if (len >= freespace){
			RDEBUG("rlm_sql (%s): Can't write result, insufficient string space", inst->config->xlat_name);

			(inst->module->sql_finish_query)(handle, inst->config);

			ret = -1;
			goto finish;
		}

		memcpy(out, buffer, len + 1); /* we did bounds checking above */
		ret = len;

		(inst->module->sql_finish_query)(handle, inst->config);

		goto finish;
	} /* else it's a SELECT statement */

	if (rlm_sql_select_query(&handle, inst, query) != RLM_SQL_OK) {
		ret = -1;  /* error handled by rlm_sql_select_query */

		goto finish;
	}

	ret = rlm_sql_fetch_row(&row, &handle, inst);
	if (ret) {
		REDEBUG("SQL query failed");
		(inst->module->sql_finish_select_query)(handle, inst->config);
		ret = -1;

		goto finish;
	}

	if (!row) {
		RDEBUG("SQL query returned no results");
		(inst->module->sql_finish_select_query)(handle, inst->config);
		ret = -1;

		goto finish;
	}

	if (!row[0]){
		RDEBUG("NULL value in first column of result");
		(inst->module->sql_finish_select_query)(handle, inst->config);
		ret = -1;

		goto finish;
	}

	len = strlen(row[0]);
	if (len >= freespace){
		RDEBUG("Insufficient string space");
		(inst->module->sql_finish_select_query)(handle, inst->config);

		ret = -1;
		goto finish;
	}

	strlcpy(out, row[0], freespace);
	ret = len;

	(inst->module->sql_finish_select_query)(handle, inst->config);

finish:
	fr_connection_release(inst->pool, handle);

	return ret;
}
void CShutdown::RunL()
	{
	RDEBUG("CentRepToolServer timeout ... closing");
	CActiveScheduler::Stop();
	}
Example #12
0
static rlm_rcode_t CC_HINT(nonnull) mod_checksimul(void *instance, REQUEST * request) {
	rlm_rcode_t		rcode = RLM_MODULE_OK;
	rlm_sql_handle_t 	*handle = NULL;
	rlm_sql_t		*inst = instance;
	rlm_sql_row_t		row;
	int			check = 0;
	uint32_t		ipno = 0;
	char const     		*call_num = NULL;
	VALUE_PAIR		*vp;
	int			ret;
	uint32_t		nas_addr = 0;
	uint32_t		nas_port = 0;

	char 			*expanded = NULL;

	/* If simul_count_query is not defined, we don't do any checking */
	if (!inst->config->simul_count_query) return RLM_MODULE_NOOP;

	if ((!request->username) || (request->username->length == '\0')) {
		REDEBUG("Zero Length username not permitted");

		return RLM_MODULE_INVALID;
	}


	if(sql_set_user(inst, request, NULL) < 0) {
		return RLM_MODULE_FAIL;
	}

	if (radius_axlat(&expanded, request, inst->config->simul_count_query, sql_escape_func, inst) < 0) {
		sql_unset_user(inst, request);
		return RLM_MODULE_FAIL;
	}

	/* initialize the sql socket */
	handle = fr_connection_get(inst->pool);
	if (!handle) {
		talloc_free(expanded);
		sql_unset_user(inst, request);
		return RLM_MODULE_FAIL;
	}

	if (rlm_sql_select_query(&handle, inst, expanded) != RLM_SQL_OK) {
		rcode = RLM_MODULE_FAIL;
		goto finish;
	}

	ret = rlm_sql_fetch_row(&row, &handle, inst);
	if (ret != 0) {
		rcode = RLM_MODULE_FAIL;
		goto finish;
	}
	if (!row) {
		rcode = RLM_MODULE_FAIL;
		goto finish;
	}

	request->simul_count = atoi(row[0]);

	(inst->module->sql_finish_select_query)(handle, inst->config);
	TALLOC_FREE(expanded);

	if (request->simul_count < request->simul_max) {
		rcode = RLM_MODULE_OK;
		goto finish;
	}

	/*
	 *	Looks like too many sessions, so let's start verifying
	 *	them, unless told to rely on count query only.
	 */
	if (!inst->config->simul_verify_query) {
		rcode = RLM_MODULE_OK;

		goto finish;
	}

	if (radius_axlat(&expanded, request, inst->config->simul_verify_query, sql_escape_func, inst) < 0) {
		rcode = RLM_MODULE_FAIL;

		goto finish;
	}

	if (rlm_sql_select_query(&handle, inst, expanded) != RLM_SQL_OK) goto finish;

	/*
	 *      Setup some stuff, like for MPP detection.
	 */
	request->simul_count = 0;

	if ((vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS, 0, TAG_ANY)) != NULL) {
		ipno = vp->vp_ipaddr;
	}

	if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID, 0, TAG_ANY)) != NULL) {
		call_num = vp->vp_strvalue;
	}

	while (rlm_sql_fetch_row(&row, &handle, inst) == 0) {
		if (!row) break;

		if (!row[2]){
			RDEBUG("Cannot zap stale entry. No username present in entry");
			rcode = RLM_MODULE_FAIL;

			goto finish;
		}

		if (!row[1]){
			RDEBUG("Cannot zap stale entry. No session id in entry");
			rcode = RLM_MODULE_FAIL;

			goto finish;
		}

		if (row[3]) {
			nas_addr = inet_addr(row[3]);
		}

		if (row[4]) {
			nas_port = atoi(row[4]);
		}

		check = rad_check_ts(nas_addr, nas_port, row[2], row[1]);
		if (check == 0) {
			/*
			 *	Stale record - zap it.
			 */
			if (inst->config->deletestalesessions == true) {
				uint32_t framed_addr = 0;
				char proto = 0;
				int sess_time = 0;

				if (row[5])
					framed_addr = inet_addr(row[5]);
				if (row[7]){
					if (strcmp(row[7], "PPP") == 0)
						proto = 'P';
					else if (strcmp(row[7], "SLIP") == 0)
						proto = 'S';
				}
				if (row[8])
					sess_time = atoi(row[8]);
				session_zap(request, nas_addr, nas_port,
					    row[2], row[1], framed_addr,
					    proto, sess_time);
			}
		}
		else if (check == 1) {
			/*
			 *	User is still logged in.
			 */
			++request->simul_count;

			/*
			 *      Does it look like a MPP attempt?
			 */
			if (row[5] && ipno && inet_addr(row[5]) == ipno) {
				request->simul_mpp = 2;
			} else if (row[6] && call_num && !strncmp(row[6],call_num,16)) {
				request->simul_mpp = 2;
			}
		} else {
			/*
			 *      Failed to check the terminal server for
			 *      duplicate logins: return an error.
			 */
			REDEBUG("Failed to check the terminal server for user '%s'.", row[2]);

			rcode = RLM_MODULE_FAIL;
			goto finish;
		}
	}

	finish:

	(inst->module->sql_finish_select_query)(handle, inst->config);
	fr_connection_release(inst->pool, handle);
	talloc_free(expanded);
	sql_unset_user(inst, request);

	/*
	 *	The Auth module apparently looks at request->simul_count,
	 *	not the return value of this module when deciding to deny
	 *	a call for too many sessions.
	 */
	return rcode;
}
Example #13
0
/*
 *	Generic function for failing between a bunch of queries.
 *
 *	Uses the same principle as rlm_linelog, expanding the 'reference' config
 *	item using xlat to figure out what query it should execute.
 *
 *	If the reference matches multiple config items, and a query fails or
 *	doesn't update any rows, the next matching config item is used.
 *
 */
static int acct_redundant(rlm_sql_t *inst, REQUEST *request, sql_acct_section_t *section)
{
	rlm_rcode_t		rcode = RLM_MODULE_OK;

	rlm_sql_handle_t	*handle = NULL;
	int			sql_ret;
	int			numaffected = 0;

	CONF_ITEM		*item;
	CONF_PAIR 		*pair;
	char const		*attr = NULL;
	char const		*value;

	char			path[MAX_STRING_LEN];
	char			*p = path;
	char			*expanded = NULL;

	rad_assert(section);

	if (section->reference[0] != '.') {
		*p++ = '.';
	}

	if (radius_xlat(p, sizeof(path) - (p - path), request, section->reference, NULL, NULL) < 0) {
		rcode = RLM_MODULE_FAIL;

		goto finish;
	}

	item = cf_reference_item(NULL, section->cs, path);
	if (!item) {
		rcode = RLM_MODULE_FAIL;

		goto finish;
	}

	if (cf_item_is_section(item)){
		REDEBUG("Sections are not supported as references");
		rcode = RLM_MODULE_FAIL;

		goto finish;
	}

	pair = cf_itemtopair(item);
	attr = cf_pair_attr(pair);

	RDEBUG2("Using query template '%s'", attr);

	handle = fr_connection_get(inst->pool);
	if (!handle) {
		rcode = RLM_MODULE_FAIL;

		goto finish;
	}

	sql_set_user(inst, request, NULL);

	while (true) {
		value = cf_pair_value(pair);
		if (!value) {
			RDEBUG("Ignoring null query");
			rcode = RLM_MODULE_NOOP;

			goto finish;
		}

		if (radius_axlat(&expanded, request, value, sql_escape_func, inst) < 0) {
			rcode = RLM_MODULE_FAIL;

			goto finish;
		}

		if (!*expanded) {
			RDEBUG("Ignoring null query");
			rcode = RLM_MODULE_NOOP;
			talloc_free(expanded);

			goto finish;
		}

		rlm_sql_query_log(inst, request, section, expanded);

		/*
		 *  If rlm_sql_query cannot use the socket it'll try and
		 *  reconnect. Reconnecting will automatically release
		 *  the current socket, and try to select a new one.
		 *
		 *  If we get RLM_SQL_RECONNECT it means all connections in the pool
		 *  were exhausted, and we couldn't create a new connection,
		 *  so we do not need to call fr_connection_release.
		 */
		sql_ret = rlm_sql_query(&handle, inst, expanded);
		TALLOC_FREE(expanded);
		if (sql_ret == RLM_SQL_RECONNECT) {
			rcode = RLM_MODULE_FAIL;
			goto finish;
		}
		rad_assert(handle);

		/*
		 *  Assume all other errors are incidental, and just meant our
		 *  operation failed and its not a client or SQL syntax error.
		 *
		 *  @fixme We should actually be able to distinguish between key
		 *  constraint violations (which we expect) and other errors.
		 */
		if (sql_ret == RLM_SQL_OK) {
			numaffected = (inst->module->sql_affected_rows)(handle, inst->config);
			if (numaffected > 0) {
				break;	/* A query succeeded, were done! */
			}

			RDEBUG("No records updated");
		}

		(inst->module->sql_finish_query)(handle, inst->config);

		/*
		 *  We assume all entries with the same name form a redundant
		 *  set of queries.
		 */
		pair = cf_pair_find_next(section->cs, pair, attr);

		if (!pair) {
			RDEBUG("No additional queries configured");
			rcode = RLM_MODULE_NOOP;

			goto finish;
		}

		RDEBUG("Trying next query...");
	}

	(inst->module->sql_finish_query)(handle, inst->config);

finish:
	talloc_free(expanded);
	fr_connection_release(inst->pool, handle);
	sql_unset_user(inst, request);

	return rcode;
}
Example #14
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;
}
Example #15
0
/*
 *	redisn xlat function. Right now only xGET are supported. Only
 *	the first element of the SELECT result will be used.
 */
static int redisn_xlat(void *instance, REQUEST *request,
		    char *fmt, char *out, size_t freespace,
		    UNUSED RADIUS_ESCAPE_STRING func)
{
	REDISSOCK *redis_socket=NULL;
	REDIS_ROW row;
	REDIS_INST *inst = instance;
	char querystr[MAX_QUERY_LEN];
	char redisnusername[MAX_STRING_LEN];
	size_t ret = 0;

	RDEBUG("redisn_xlat");

	/*
         * Add REDISN-User-Name attribute just in case it is needed
         *  We could search the string fmt for REDISN-User-Name to see if this is
         *  needed or not
         */
	redisn_set_user(inst, request, redisnusername, NULL);
	/*
	 * Do an xlat on the provided string (nice recursive operation).
	 */
	if (!radius_xlat(querystr, sizeof(querystr), fmt, request, redisn_escape_func, inst)) {
		radlog(L_ERR, "rlm_redisn (%s): xlat failed.",
		       inst->xlat_name);
		return 0;
	}

	query_log(request, inst, querystr);
	redis_socket = redisn_get_socket(inst);
	if (redis_socket == NULL)
		return 0;

	if (rlm_redisn_query(inst, redis_socket, querystr)<0) {
	  radlog(L_ERR, "rlm_redisn (%s): database query error, %s",
		 inst->xlat_name,querystr);
	  redisn_release_socket(inst,redis_socket);
	  return 0;
	  }

	ret = rlm_redisn_fetch_row(inst, redis_socket);

	if (ret) {
		RDEBUG("REDIS query did not succeed");
		(inst->redisn_finish_query)(inst, redis_socket);
		redisn_release_socket(inst,redis_socket);
		return 0;
	}

	row = redis_socket->row;
	if (row == NULL) {
		RDEBUG("REDIS query did not return any results");
		(inst->redisn_finish_query)(inst, redis_socket);
		redisn_release_socket(inst,redis_socket);
		return 0;
	}

	if (row[0] == NULL){
		RDEBUG("row[0] returned NULL");
		(inst->redisn_finish_query)(inst, redis_socket);
		redisn_release_socket(inst,redis_socket);
		return 0;
	}
	ret = strlen(row[0]);
	if (ret >= freespace){
		RDEBUG("Insufficient string space");
		(inst->redisn_finish_query)(inst, redis_socket);
		redisn_release_socket(inst,redis_socket);
		return 0;
	}

	strlcpy(out,row[0],freespace);

	RDEBUG("redisn_xlat finished");

	(inst->redisn_finish_query)(inst,redis_socket);
	redisn_release_socket(inst,redis_socket);
	return ret;
}
// A session is being destroyed
// Start the shutdown timer if it is the last session.
void CCentRepToolServer::DropSession()
	{
	RDEBUG("CentRepToolServer: CPolicyEngineServer::DropSession");
	if (--iSessionCount==0)
		iShutdown.Start();
	}
Example #17
0
static rlm_rcode_t rlm_redisn_checksimul(void *instance, REQUEST * request) {
	REDISSOCK 	*redis_socket;
	REDIS_INST	*inst = instance;
	REDIS_ROW	row;
	char		querystr[MAX_QUERY_LEN];
	char		redisnusername[MAX_STRING_LEN];
	int		check = 0;
        uint32_t        ipno = 0;
        char            *call_num = NULL;
	VALUE_PAIR      *vp;
	int		ret;
	uint32_t	nas_addr = 0;
	int		nas_port = 0;

	/* If simul_count_query is not defined, we don't do any checking */
	if (!inst->simul_count_query ||
	    (inst->simul_count_query[0] == 0)) {
		return RLM_MODULE_NOOP;
	}

	if((request->username == NULL) || (request->username->length == 0)) {
		radlog_request(L_ERR, 0, request, "Zero Length username not permitted\n");
		return RLM_MODULE_INVALID;
	}


	if(redisn_set_user(inst, request, redisnusername, NULL) < 0)
		return RLM_MODULE_FAIL;

	radius_xlat(querystr, sizeof(querystr), inst->simul_count_query, request, redisn_escape_func, inst);

	/* initialize the redisn socket */
	redis_socket = redisn_get_socket(inst);
	if(redis_socket == NULL)
		return RLM_MODULE_FAIL;

	if(rlm_redisn_query(inst, redis_socket, querystr)) {
		radlog(L_ERR, "rlm_redisn (%s) redisn_checksimul: Database query failed", inst->xlat_name);
		redisn_release_socket(inst, redis_socket);
		return RLM_MODULE_FAIL;
	}

	ret = rlm_redisn_fetch_row(inst, redis_socket);

	if (ret != 0) {
		(inst->redisn_finish_query)(inst, redis_socket);
		redisn_release_socket(inst, redis_socket);
		return RLM_MODULE_FAIL;
	}

	row = redis_socket->row;
	if (row == NULL) {
		(inst->redisn_finish_query)(inst, redis_socket);
		redisn_release_socket(inst, redis_socket);
		return RLM_MODULE_FAIL;
	}

	request->simul_count = atoi(row[0]);
	(inst->redisn_finish_query)(inst, redis_socket);

	if(request->simul_count < request->simul_max) {
		redisn_release_socket(inst, redis_socket);
		return RLM_MODULE_OK;
	}

	/*
	 *	Looks like too many sessions, so let's start verifying
	 *	them, unless told to rely on count query only.
	 */
	if (!inst->simul_verify_query ||
	    (inst->simul_verify_query[0] == '\0')) {
		redisn_release_socket(inst, redis_socket);
		return RLM_MODULE_OK;
	}

	radius_xlat(querystr, sizeof(querystr), inst->simul_verify_query, request, redisn_escape_func, inst);
	if(rlm_redisn_query(inst, redis_socket, querystr)) {
		radlog_request(L_ERR, 0, request, "Database query error");
		redisn_release_socket(inst, redis_socket);
		return RLM_MODULE_FAIL;
	}

        /*
         *      Setup some stuff, like for MPP detection.
         */
	request->simul_count = 0;

        if ((vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS, 0, TAG_ANY)) != NULL)
                ipno = vp->vp_ipaddr;
        if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID, 0, TAG_ANY)) != NULL)
                call_num = vp->vp_strvalue;


	while (rlm_redisn_fetch_row(inst, redis_socket) == 0) {
		row = redis_socket->row;
		if (row == NULL)
			break;
		if (!row[2]){
			(inst->redisn_finish_query)(inst, redis_socket);
			redisn_release_socket(inst, redis_socket);
			RDEBUG("Cannot zap stale entry. No username present in entry.", inst->xlat_name);
			return RLM_MODULE_FAIL;
		}
		if (!row[1]){
			(inst->redisn_finish_query)(inst, redis_socket);
			redisn_release_socket(inst, redis_socket);
			RDEBUG("Cannot zap stale entry. No session id in entry.", inst->xlat_name);
			return RLM_MODULE_FAIL;
		}
		if (row[3])
			nas_addr = inet_addr(row[3]);
		if (row[4])
			nas_port = atoi(row[4]);

		check = rad_check_ts(nas_addr, nas_port, row[2], row[1]);

		if (check == 0) {
			/*
			 *	Stale record - zap it.
			 */
			if (inst->deletestalesessions == TRUE) {
				uint32_t framed_addr = 0;
				char proto = 0;
				int sess_time = 0;

				if (row[5])
					framed_addr = inet_addr(row[5]);
				if (row[7]){
					if (strcmp(row[7], "PPP") == 0)
						proto = 'P';
					else if (strcmp(row[7], "SLIP") == 0)
						proto = 'S';
				}
				if (row[8])
					sess_time = atoi(row[8]);
				session_zap(request, nas_addr, nas_port,
					    row[2], row[1], framed_addr,
					    proto, sess_time);
			}
		}
		else if (check == 1) {
			/*
			 *	User is still logged in.
			 */
			++request->simul_count;

                        /*
                         *      Does it look like a MPP attempt?
                         */
                        if (row[5] && ipno && inet_addr(row[5]) == ipno)
                                request->simul_mpp = 2;
                        else if (row[6] && call_num &&
                                !strncmp(row[6],call_num,16))
                                request->simul_mpp = 2;
		}
		else {
			/*
			 *      Failed to check the terminal server for
			 *      duplicate logins: return an error.
			 */
			(inst->redisn_finish_query)(inst, redis_socket);
			redisn_release_socket(inst, redis_socket);
			radlog_request(L_ERR, 0, request, "Failed to check the terminal server for user '%s'.", row[2]);
			return RLM_MODULE_FAIL;
		}
	}

	(inst->redisn_finish_query)(inst, redis_socket);
	redisn_release_socket(inst, redis_socket);

	/*
	 *	The Auth module apparently looks at request->simul_count,
	 *	not the return value of this module when deciding to deny
	 *	a call for too many sessions.
	 */
	return RLM_MODULE_OK;
}
inline CCentRepToolSession::CCentRepToolSession()
	{
	RDEBUG("CentRepToolServer: CCentRepToolSession::CCentRepToolSession");
	}
Example #19
0
/** Read from the child process.
 *
 * @param request The current request.
 * @param fd file descriptor to read from.
 * @param pid pid of child, will be reaped if it dies.
 * @param timeout amount of time to wait, in seconds.
 * @param answer buffer to write into.
 * @param left length of buffer.
 * @return -1 on error, or length of output.
 */
int radius_readfrom_program(REQUEST *request, int fd, pid_t pid, int timeout,
			    char *answer, int left)
{
	int done = 0;
#ifndef __MINGW32__
	int status;
	struct timeval start;
#ifdef O_NONBLOCK
	bool nonblock = true;
#endif

#ifdef O_NONBLOCK
	/*
	 *	Try to set it non-blocking.
	 */
	do {
		int flags;

		if ((flags = fcntl(fd, F_GETFL, NULL)) < 0)  {
			nonblock = false;
			break;
		}

		flags |= O_NONBLOCK;
		if( fcntl(fd, F_SETFL, flags) < 0) {
			nonblock = false;
			break;
		}
	} while (0);
#endif


	/*
	 *	Read from the pipe until we doesn't get any more or
	 *	until the message is full.
	 */
	gettimeofday(&start, NULL);
	while (1) {
		int rcode;
		fd_set fds;
		struct timeval when, elapsed, wake;

		FD_ZERO(&fds);
		FD_SET(fd, &fds);

		gettimeofday(&when, NULL);
		tv_sub(&when, &start, &elapsed);
		if (elapsed.tv_sec >= timeout) goto too_long;

		when.tv_sec = timeout;
		when.tv_usec = 0;
		tv_sub(&when, &elapsed, &wake);

		rcode = select(fd + 1, &fds, NULL, NULL, &wake);
		if (rcode == 0) {
		too_long:
			RDEBUG("Child PID %u is taking too much time: forcing failure and killing child.", pid);
			kill(pid, SIGTERM);
			close(fd); /* should give SIGPIPE to child, too */

			/*
			 *	Clean up the child entry.
			 */
			rad_waitpid(pid, &status);
			return -1;
		}
		if (rcode < 0) {
			if (errno == EINTR) continue;
			break;
		}

#ifdef O_NONBLOCK
		/*
		 *	Read as many bytes as possible.  The kernel
		 *	will return the number of bytes available.
		 */
		if (nonblock) {
			status = read(fd, answer + done, left);
		} else
#endif
			/*
			 *	There's at least 1 byte ready: read it.
			 */
			status = read(fd, answer + done, 1);

		/*
		 *	Nothing more to read: stop.
		 */
		if (status == 0) {
			break;
		}

		/*
		 *	Error: See if we have to continue.
		 */
		if (status < 0) {
			/*
			 *	We were interrupted: continue reading.
			 */
			if (errno == EINTR) {
				continue;
			}

			/*
			 *	There was another error.  Most likely
			 *	The child process has finished, and
			 *	exited.
			 */
			break;
		}

		done += status;
		left -= status;
		if (left <= 0) break;
	}
#endif	/* __MINGW32__ */

	/* Strip trailing new lines */
	while ((done > 0) && (answer[done - 1] == '\n')) {
		answer[--done] = '\0';
	}

	return done;
}
void CCentRepToolSession::DispatchMessageL(const RMessage2& aMessage)
	{
	//Subsession management
	switch (aMessage.Function())
	{
		case ECreateRepositorySubSession:
		case ECreateCheckAccessSession:
		{
			RDEBUG("CentRepTool: New repository session");
			NewRepositorySessionL( aMessage);
			return;
		}
		case ECloseRepositorySubSession:
		case ECloseCheckAcceessSession:
		{
			RDEBUG("CentRepTool: Close repository session");
			DeleteRepositorySession( aMessage);
			return;
		}
		case ECheckCommitState :
		{
			RDEBUG("CentRepTool: Check last commit state");
			CRepositorySession::CheckCommitStateL();
			return;
		}
		case EPerformCentRepToolRFS :
		{
			RDEBUG("CentRepTool: Perform RFS");
			PerformRFSL();
			return;
		}
	}

	//Trusted session operations
	CRepositorySession * repositorySession = RepositorySessionFromHandle( aMessage);
	iCurrentSession = repositorySession;
			
	switch (aMessage.Function())
	{
		case EInitRepositorySession:
		{
			RDEBUG("CentRepTool: Init repository session");
			repositorySession->InitRepositorySessionL();
		}
		break;
		case ESetSIDWRForSetting :
		{
			RDEBUG("CentRepTool: Add SID for individual setting");
			repositorySession->SetSecurityIdForSettingL( aMessage);
		}
		break;
		case ESetSIDWRForRange:
		{
			RDEBUG("CentRepTool: Add SID for range");
			repositorySession->SetSecurityIdForRangeL( aMessage);
		}
		break;		
		case ERestoreSetting :
		{
			RDEBUG("CentRepTool: Restore individual setting");
			repositorySession->RestoreSettingL( aMessage);
		}
		break;		
		case ERestoreRange :
		{
			RDEBUG("CentRepTool: Restore range");
			repositorySession->RestoreRangeL( aMessage);
		}
		break;
		case EAddSIDWRForDefaults :
		{
			RDEBUG("CentRepTool: Add SID for all settings (default, range, mask)");
			repositorySession->AddSidForDefaultsL( aMessage);
		}
		break;
		case ERestoreDefaults :
		{
			RDEBUG("CentRepTool: ");
			RDEBUG("CentRepTool: Remove SID from all settings (default, range, mask)");
			repositorySession->RestoreDefaultsL( aMessage);
		}
		break;
		case EFlushRepository :
		{
			RDEBUG("CentRepTool: Commit security changes in repository");
			repositorySession->CommitRepositoryL();
		}
		break;
		case ESetSIDWRForMask :
		{
			RDEBUG("CentRepTool: Set SID for mask setting");
			repositorySession->SetSecurityIdForMaskL( aMessage);
		}
		break;
		case ERestoreMask :
		{
			RDEBUG("CentRepTool: Restore mask setting");
			repositorySession->RestoreMaskL( aMessage);
		}
		break;
		case ERemoveBackupFlagForMask:
		{
			RDEBUG("CentRepTool: Set backup flag for mask");
			repositorySession->RemoveBackupForMaskL( aMessage);
		}
		break;
		case ERestoreBackupFlagForMask:
		{
			RDEBUG("CentRepTool: Restore backup flag for mask");
			repositorySession->RestoreMaskBackupL( aMessage);
		}
		break;
		case ERemoveBackupFlagForDefaults:
		{
			RDEBUG("CentRepTool: Set backup flag for defaults");
			repositorySession->RemoveDefaultBackup();
		}
		break;
		case ERestoreBackupFlagForDefaults:
		{
			RDEBUG("CentRepTool: Restore backup flag for defaults");
			repositorySession->RestoreDefaultBackupL();
		}
		break;		
		case ERemoveBackupFlagForRange:
		{
			RDEBUG("CentRepTool: Set backup flag for range");
			repositorySession->RemoveBackupForRangeL( aMessage);
		}
		break;
		case ERestoreBackupFlagForRange:
		{
			RDEBUG("CentRepTool: Restore backup flag for range");
			repositorySession->RestoreRangeBackupL( aMessage);
		}
		break;		
		case ECheckAccess:
		{
			RDEBUG("CentRepTool: Check access");
			repositorySession->CheckAccessL( aMessage);
		}
		break;		
		default:
		break;	
	}		
		
}
Example #21
0
static int dhcp_process(REQUEST *request)
{
	int rcode;
	unsigned int i;
	VALUE_PAIR *vp;
	dhcp_socket_t *sock;

	vp = pairfind(request->packet->vps, DHCP2ATTR(53)); /* DHCP-Message-Type */
	if (vp) {
		DICT_VALUE *dv = dict_valbyattr(DHCP2ATTR(53), vp->vp_integer);
		DEBUG("Trying sub-section dhcp %s {...}",
		      dv->name ? dv->name : "<unknown>");
		rcode = module_post_auth(vp->vp_integer, request);
	} else {
		DEBUG("DHCP: Failed to find DHCP-Message-Type in packet!");
		rcode = RLM_MODULE_FAIL;
	}

	vp = pairfind(request->reply->vps, DHCP2ATTR(53)); /* DHCP-Message-Type */
	if (vp) {
		request->reply->code = vp->vp_integer;
		if ((request->reply->code != 0) &&
		    (request->reply->code < PW_DHCP_OFFSET)) {
			request->reply->code += PW_DHCP_OFFSET;
		}
	}
	else switch (rcode) {
	case RLM_MODULE_OK:
	case RLM_MODULE_UPDATED:
		if (request->packet->code == PW_DHCP_DISCOVER) {
			request->reply->code = PW_DHCP_OFFER;
			break;

		} else if (request->packet->code == PW_DHCP_REQUEST) {
			request->reply->code = PW_DHCP_ACK;
			break;
		}
		request->reply->code = PW_DHCP_NAK;
		break;

	default:
	case RLM_MODULE_REJECT:
	case RLM_MODULE_FAIL:
	case RLM_MODULE_INVALID:
	case RLM_MODULE_NOOP:
	case RLM_MODULE_NOTFOUND:
		if (request->packet->code == PW_DHCP_DISCOVER) {
			request->reply->code = 0; /* ignore the packet */
		} else {
			request->reply->code = PW_DHCP_NAK;
		}
		break;

	case RLM_MODULE_HANDLED:
		request->reply->code = 0; /* ignore the packet */
		break;
	}

	/*
	 *	TODO: Handle 'output' of RLM_MODULE when acting as a
	 *	DHCP relay We may want to not forward packets in
	 *	certain circumstances.
	 */

	/*
	 * 	Handle requests when acting as a DHCP relay
	 */
	vp = pairfind(request->packet->vps, DHCP2ATTR(256)); /* DHCP-Opcode */
	if (!vp) {
		RDEBUG("FAILURE: Someone deleted the DHCP-Opcode!");
		return 1;
	}

	/* BOOTREPLY received on port 67 (i.e. from a server) */
	if (vp->vp_integer == 2) {
		return dhcprelay_process_server_reply(request);
	}

	/* Packet from client, and we have DHCP-Relay-To-IP-Address */
	if (pairfind(request->config_items, DHCP2ATTR(270))) { 
		return dhcprelay_process_client_request(request);
	}

	/* else it's a packet from a client, without relaying */
	rad_assert(vp->vp_integer == 1); /* BOOTREQUEST */

	sock = request->listener->data;

	/*
	 *	Handle requests when acting as a DHCP server
	 */

	/*
	 *	Releases don't get replies.
	 */
	if (request->packet->code == PW_DHCP_RELEASE) {
		request->reply->code = 0;
	}

	if (request->reply->code == 0) {
		return 1;
	}

	request->reply->sockfd = request->packet->sockfd;

	/*
	 *	Copy specific fields from packet to reply, if they
	 *	don't already exist
	 */
	for (i = 0; i < sizeof(attrnums) / sizeof(attrnums[0]); i++) {
		uint32_t attr = attrnums[i];

		if (pairfind(request->reply->vps, DHCP2ATTR(attr))) continue;
		if ((vp = pairfind(request->packet->vps, DHCP2ATTR(attr)))) {
			pairadd(&request->reply->vps, paircopyvp(vp));
		}
	}

	vp = pairfind(request->reply->vps, DHCP2ATTR(256)); /* DHCP-Opcode */
	rad_assert(vp != NULL);
	vp->vp_integer = 2; /* BOOTREPLY */

	/*
	 * Prepare the reply packet for sending through dhcp_socket_send()
	 */
	request->reply->dst_ipaddr.af = AF_INET;
	request->reply->src_ipaddr.af = AF_INET;
	request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = sock->src_ipaddr.ipaddr.ip4addr.s_addr;

	request->reply->dst_port = request->packet->src_port;
	request->reply->src_port = request->packet->dst_port;

	vp = pairfind(request->reply->vps, DHCP2ATTR(266)); /* DHCP-Gateway-IP-Address */
	if (vp && (vp->vp_ipaddr != htonl(INADDR_ANY))) {
		/* Answer to client's nearest DHCP relay */
		request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
	} else if ((request->reply->code == PW_DHCP_NAK) ||
	    ((vp = pairfind(request->reply->vps, DHCP2ATTR(262))) /* DHCP-Flags */ &&
		(vp->vp_integer & 0x8000) &&
		((vp = pairfind(request->reply->vps, DHCP2ATTR(263))) /* DHCP-Client-IP-Address */ &&
		    (vp->vp_ipaddr == htonl(INADDR_ANY))))) {
		/*
		 * RFC 2131, page 23
		 *
		 * Broadcast on
		 * - DHCPNAK
		 * or
		 * - Broadcast flag is set up and ciaddr == NULL
		 */
		request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
	} else {
		/*
		 * RFC 2131, page 23
		 *
		 * Unicast to
		 * - ciaddr if present
		 * otherwise to yiaddr
		 */
		if ((vp = pairfind(request->reply->vps, DHCP2ATTR(263))) /* DHCP-Client-IP-Address */ &&
		    (vp->vp_ipaddr != htonl(INADDR_ANY))) {
			request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
		} else {
			vp = pairfind(request->reply->vps, DHCP2ATTR(264)); /* DHCP-Your-IP-Address */
			if (!vp) {
				DEBUG("DHCP: Failed to find IP Address for request.");
				return -1;
			}
			
			request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;

			/*
			 * When sending a DHCP_OFFER, make sure our ARP table
			 * contains an entry for the client IP address, or else
			 * packet may not be forwarded if it was the first time
			 * the client was requesting an IP address.
			 */
			if (request->reply->code == PW_DHCP_OFFER) {
				VALUE_PAIR *hwvp = pairfind(request->reply->vps, DHCP2ATTR(267)); /* DHCP-Client-Hardware-Address */

				if (!hwvp) return -1;

				if (fr_dhcp_add_arp_entry(request->reply->sockfd, sock->src_interface, hwvp, vp) < 0) {
					return -1;
				}
			}
		}
	}

	return 1;
}
// RMessagePtr2::Panic() also completes the message. This is:
// (a) important for efficient cleanup within the kernel
// (b) a problem if the message is completed a second time
void PanicClient(const RMessagePtr2& aMessage, TCentRepToolServerPanic aPanic)
	{
	RDEBUG("CentRepTool PanicClient");
	aMessage.Panic( IniConstants::KCentRepToolPanic,aPanic);
	}
/*
 *	Check for an Accounting-Stop
 *	If we find one and we have allocated an IP to this nas/port
 *	combination, then deallocate it.
 */
static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
{
	int rcode = RLM_MODULE_NOOP;
	VALUE_PAIR *vp;
	int acct_status_type;
	rlm_sqlippool_t *inst = (rlm_sqlippool_t *) instance;
	rlm_sql_handle_t *handle;

	vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY);
	if (!vp) {
		RDEBUG("Could not find account status type in packet");
		return RLM_MODULE_NOOP;
	}
	acct_status_type = vp->vp_integer;

	switch (acct_status_type) {
	case PW_STATUS_START:
	case PW_STATUS_ALIVE:
	case PW_STATUS_STOP:
	case PW_STATUS_ACCOUNTING_ON:
	case PW_STATUS_ACCOUNTING_OFF:
		break;		/* continue through to the next section */

	default:
		/* We don't care about any other accounting packet */
		return RLM_MODULE_NOOP;
	}

	handle = inst->sql_inst->sql_get_socket(inst->sql_inst);
	if (!handle) {
		RDEBUG("Cannot allocate sql connection");
		return RLM_MODULE_FAIL;
	}

	if (inst->sql_inst->sql_set_user(inst->sql_inst, request, NULL) < 0) {
		return RLM_MODULE_FAIL;
	}

	switch (acct_status_type) {
	case PW_STATUS_START:
		rcode = mod_accounting_start(handle, inst, request);
		break;

	case PW_STATUS_ALIVE:
		rcode = mod_accounting_alive(handle, inst, request);
		break;

	case PW_STATUS_STOP:
		rcode = mod_accounting_stop(handle, inst, request);
		break;

	case PW_STATUS_ACCOUNTING_ON:
		rcode = mod_accounting_on(handle, inst, request);
		break;

	case PW_STATUS_ACCOUNTING_OFF:
		rcode = mod_accounting_off(handle, inst, request);
		break;
	}

	inst->sql_inst->sql_release_socket(inst->sql_inst, handle);

	return rcode;
}
inline void CShutdown::Start()
	{
	RDEBUG("CentRepToolServer: starting shutdown timeout");
	After(KPolicyEngineShutdownDelay);
	}
Example #25
0
/** Convert value_pair_map_t to VALUE_PAIR(s) and add them to a REQUEST.
 *
 * Takes a single value_pair_map_t, resolves request and list identifiers
 * to pointers in the current request, then attempts to retrieve module
 * specific value(s) using callback, and adds the resulting values to the
 * correct request/list.
 *
 * @param request The current request.
 * @param map specifying destination attribute and location and src identifier.
 * @param func to retrieve module specific values and convert them to
 *	VALUE_PAIRS.
 * @param ctx to be passed to func.
 * @param src name to be used in debugging if different from map value.
 * @return -1 if the operation failed, -2 in the source attribute wasn't valid, 0 on success.
 */
int radius_map2request(REQUEST *request, value_pair_map_t const *map,
		       UNUSED char const *src, radius_tmpl_getvalue_t func, void *ctx)
{
	int rcode;
	vp_cursor_t cursor;
	VALUE_PAIR **list, *vp, *head = NULL;
	char buffer[1024];

	if (radius_request(&request, map->dst->request) < 0) {
		REDEBUG("Mapping \"%s\" -> \"%s\" invalid in this context", map->src->name, map->dst->name);

		return -2;
	}

	list = radius_list(request, map->dst->list);
	if (!list) {
		REDEBUG("Mapping \"%s\" -> \"%s\" invalid in this context", map->src->name, map->dst->name);

		return -2;
	}


	/*
	 *	The callback should either return -1 to signify operations error, -2 when it can't find the
	 *	attribute or list being referenced, or 0 to signify success.
	 *	It may return "sucess", but still have no VPs to work with.
	 *	Only if it returned an error code should it not write anything to the head pointer.
	 */
	rcode = func(&head, request, map, ctx);
	if (rcode < 0) {
		rad_assert(!head);

		return rcode;
	}

	if (!head) return 0;

	VERIFY_VP(head);

	if (debug_flag) for (vp = paircursor(&cursor, &head); vp; vp = pairnext(&cursor)) {
		char *value;

		switch (map->src->type) {
			/*
			 *	Just print the value being assigned
			 */
			default:

			case VPT_TYPE_LITERAL:
				vp_prints_value(buffer, sizeof(buffer), vp, '\'');
				value = buffer;
				break;
			case VPT_TYPE_XLAT:
				vp_prints_value(buffer, sizeof(buffer), vp, '"');
				value = buffer;
				break;
			case VPT_TYPE_DATA:
				vp_prints_value(buffer, sizeof(buffer), vp, 0);
				value = buffer;
				break;
			/*
			 *	Just printing the value doesn't make sense, but we still
			 *	want to know what it was...
			 */
			case VPT_TYPE_LIST:
				vp_prints_value(buffer, sizeof(buffer), vp, '\'');
				value = talloc_asprintf(request, "&%s%s -> %s", map->src->name, vp->da->name, buffer);
				break;
			case VPT_TYPE_ATTR:
				vp_prints_value(buffer, sizeof(buffer), vp, '\'');
				value = talloc_asprintf(request, "&%s -> %s", map->src->name, buffer);
				break;
		}


		RDEBUG("\t\t%s %s %s", map->dst->name, fr_int2str(fr_tokens, vp->op, "<INVALID>"), value);

		if (value != buffer) talloc_free(value);
	}

	/*
	 *	Use pairmove so the operator is respected
	 */
	radius_pairmove(request, list, head);
	return 0;
}
Example #26
0
static rlm_rcode_t rlm_redisn_authorize(void *instance, REQUEST * request)
{
	VALUE_PAIR *check_tmp = NULL;
	VALUE_PAIR *reply_tmp = NULL;
	VALUE_PAIR *user_profile = NULL;
	int     found = 0;
	int	dofallthrough = 1;
	int	rows;
	REDISSOCK *redis_socket;
	REDIS_INST *inst = instance;
	char    querystr[MAX_QUERY_LEN];
	char	redisnusername[MAX_STRING_LEN];
	/*
	 * the profile username is used as the redisnusername during
	 * profile checking so that we don't overwrite the orignal
	 * redisnusername string
	 */
	char   profileusername[MAX_STRING_LEN];

	/*
	 * Set, escape, and check the user attr here
	 */
	if (redisn_set_user(inst, request, redisnusername, NULL) < 0)
		return RLM_MODULE_FAIL;


	/*
	 * reserve a socket
	 */
	redis_socket = redisn_get_socket(inst);
	if (redis_socket == NULL) {
		/* Remove the username we (maybe) added above */
		pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY);
		return RLM_MODULE_FAIL;
	}


	/*
	 *  After this point, ALL 'return's MUST release the REDISN socket!
	 */

	/*
	 * Alright, start by getting the specific entry for the user
	 */
	if (!radius_xlat(querystr, sizeof(querystr), inst->authorize_check_query, request, redisn_escape_func, inst)) {
		radlog_request(L_ERR, 0, request, "Error generating query; rejecting user");
		redisn_release_socket(inst, redis_socket);
		/* Remove the username we (maybe) added above */
		pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY);
		return RLM_MODULE_FAIL;
	}
	rows = redisn_getvpdata(inst, redis_socket, &check_tmp, querystr);
	if (rows < 0) {
		radlog_request(L_ERR, 0, request, "REDISN query error; rejecting user");
		redisn_release_socket(inst, redis_socket);
		/* Remove the username we (maybe) added above */
		pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY);
		pairfree(&check_tmp);
		return RLM_MODULE_FAIL;
	} else if (rows > 0) {
		/*
		 *	Only do this if *some* check pairs were returned
		 */
		if (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) == 0) {
			found = 1;
			RDEBUG2("User found in radcheck table");

			if (inst->authorize_reply_query &&
			    *inst->authorize_reply_query) {

			/*
			 *	Now get the reply pairs since the paircompare matched
			 */
			if (!radius_xlat(querystr, sizeof(querystr), inst->authorize_reply_query, request, redisn_escape_func, inst)) {
				radlog_request(L_ERR, 0, request, "Error generating query; rejecting user");
				redisn_release_socket(inst, redis_socket);
				/* Remove the username we (maybe) added above */
				pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY);
				pairfree(&check_tmp);
				return RLM_MODULE_FAIL;
			}
			if (redisn_getvpdata(inst, redis_socket, &reply_tmp, querystr) < 0) {
				radlog_request(L_ERR, 0, request, "REDISN query error; rejecting user");
				redisn_release_socket(inst, redis_socket);
				/* Remove the username we (maybe) added above */
				pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY);
				pairfree(&check_tmp);
				pairfree(&reply_tmp);
				return RLM_MODULE_FAIL;
			}

			if (!inst->read_groups) {
				dofallthrough = fallthrough(reply_tmp);
				DEBUG("rlm_redisn (%s) %d: dofallthrough: %d",
				      inst->xlat_name,
				      __LINE__,dofallthrough);
			}
			pairxlatmove(request, &request->reply->vps, &reply_tmp);
			}
			pairxlatmove(request, &request->config_items, &check_tmp);
		}
	}

	/*
	 *	Clear out the pairlists
	 */
	pairfree(&check_tmp);
	pairfree(&reply_tmp);

	/*
	 *	dofallthrough is set to 1 by default so that if the user information
	 *	is not found, we will still process groups.  If the user information,
	 *	however, *is* found, Fall-Through must be set in order to process
	 *	the groups as well
	 */
	DEBUG("rlm_redisn (%s) %d: dofallthrough: %d",
	      inst->xlat_name,
	      __LINE__,dofallthrough);
	if (dofallthrough) {
		rows = rlm_redisn_process_groups(inst, request, redis_socket, &dofallthrough);
		if (rows < 0) {
			radlog_request(L_ERR, 0, request, "Error processing groups; rejecting user");
			redisn_release_socket(inst, redis_socket);
			/* Remove the username we (maybe) added above */
			pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY);
			return RLM_MODULE_FAIL;
		} else if (rows > 0) {
			found = 1;
		}
	}

	/*
	 *	repeat the above process with the default profile or User-Profile
	 */
	DEBUG("rlm_redisn (%s) %d: dofallthrough: %d",
	      inst->xlat_name,
	      __LINE__,dofallthrough);
	if (dofallthrough) {
		int profile_found = 0;
		/*
	 	* Check for a default_profile or for a User-Profile.
		*/
		user_profile = pairfind(request->config_items, PW_USER_PROFILE, 0, TAG_ANY);
		if (inst->default_profile[0] != 0 || user_profile != NULL){
			char *profile = inst->default_profile;

			if (user_profile != NULL)
				profile = user_profile->vp_strvalue;
			if (profile && strlen(profile)){
				RDEBUG("Checking profile %s", profile);
				if (redisn_set_user(inst, request, profileusername, profile) < 0) {
					radlog_request(L_ERR, 0, request, "Error setting profile; rejecting user");
					redisn_release_socket(inst, redis_socket);
					/* Remove the username we (maybe) added above */
					pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY);
					return RLM_MODULE_FAIL;
				} else {
					profile_found = 1;
				}
			}
		}

		if (profile_found) {
			rows = rlm_redisn_process_groups(inst, request, redis_socket, &dofallthrough);
			DEBUG("rlm_redisn (%s) %d: dofallthrough: %d",
			      inst->xlat_name,
			      __LINE__,dofallthrough);
			if (rows < 0) {
				radlog_request(L_ERR, 0, request, "Error processing profile groups; rejecting user");
				redisn_release_socket(inst, redis_socket);
				/* Remove the username we (maybe) added above */
				pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY);
				return RLM_MODULE_FAIL;
			} else if (rows > 0) {
				found = 1;
			}
		}
	}

	/* Remove the username we (maybe) added above */
	pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY);
	redisn_release_socket(inst, redis_socket);

	if (!found) {
		RDEBUG("User %s not found", redisnusername);
		return RLM_MODULE_NOTFOUND;
	} else {
		return RLM_MODULE_OK;
	}
}
Example #27
0
/**
 * @brief Parse the MS-SOH response in data and update sohvp.
 *
 * Note that sohvp might still have been updated in event of a failure.
 *
 * @param request Current request
 * @param data MS-SOH blob
 * @param data_len length of MS-SOH blob
 *
 * @return 0 on success, -1 on failure
 *
 */
int soh_verify(REQUEST *request, uint8_t const *data, unsigned int data_len) {

	VALUE_PAIR *vp;
	eap_soh hdr;
	soh_response resp;
	soh_mode_subheader mode;
	soh_tlv tlv;
	int curr_shid=-1, curr_shid_c=-1, curr_hc=-1;

	rad_assert(request->packet != NULL);

	hdr.tlv_type = soh_pull_be_16(data); data += 2;
	hdr.tlv_len = soh_pull_be_16(data); data += 2;
	hdr.tlv_vendor = soh_pull_be_32(data); data += 4;

	if (hdr.tlv_type != 7 || hdr.tlv_vendor != 0x137) {
		RDEBUG("SoH payload is %i %08x not a ms-vendor packet", hdr.tlv_type, hdr.tlv_vendor);
		return -1;
	}

	hdr.soh_type = soh_pull_be_16(data); data += 2;
	hdr.soh_len = soh_pull_be_16(data); data += 2;
	if (hdr.soh_type != 1) {
		RDEBUG("SoH tlv %04x is not a response", hdr.soh_type);
		return -1;
	}

	/* FIXME: check for sufficient data */
	resp.outer_type = soh_pull_be_16(data); data += 2;
	resp.outer_len = soh_pull_be_16(data); data += 2;
	resp.vendor = soh_pull_be_32(data); data += 4;
	resp.inner_type = soh_pull_be_16(data); data += 2;
	resp.inner_len = soh_pull_be_16(data); data += 2;


	if (resp.outer_type!=7 || resp.vendor != 0x137) {
		RDEBUG("SoH response outer type %i/vendor %08x not recognised", resp.outer_type, resp.vendor);
		return -1;
	}
	switch (resp.inner_type) {
		case 1:
			/* no mode sub-header */
			RDEBUG("SoH without mode subheader");
			break;
		case 2:
			mode.outer_type = soh_pull_be_16(data); data += 2;
			mode.outer_len = soh_pull_be_16(data); data += 2;
			mode.vendor = soh_pull_be_32(data); data += 4;
			memcpy(mode.corrid, data, 24); data += 24;
			mode.intent = data[0];
			mode.content_type = data[1];
			data += 2;

			if (mode.outer_type != 7 || mode.vendor != 0x137 || mode.content_type != 0) {
				RDEBUG3("SoH mode subheader outer type %i/vendor %08x/content type %i invalid", mode.outer_type, mode.vendor, mode.content_type);
				return -1;
			}
			RDEBUG3("SoH with mode subheader");
			break;
		default:
			RDEBUG("SoH invalid inner type %i", resp.inner_type);
			return -1;
	}

	/* subtract off the relevant amount of data */
	if (resp.inner_type==2) {
		data_len = resp.inner_len - 34;
	} else {
		data_len = resp.inner_len;
	}

	/* TLV
	 * MS-SOH 2.2.1
	 * See also 2.2.3
	 *
	 * 1 bit mandatory
	 * 1 bit reserved
	 * 14 bits tlv type
	 * 2 bytes tlv length
	 * N bytes payload
	 *
	 */
	while (data_len >= 4) {
		tlv.tlv_type = soh_pull_be_16(data); data += 2;
		tlv.tlv_len = soh_pull_be_16(data); data += 2;

		data_len -= 4;

		switch (tlv.tlv_type) {
			case 2:
				/* System-Health-Id TLV
				 * MS-SOH 2.2.3.1
				 *
				 * 3 bytes IANA/SMI vendor code
				 * 1 byte component (i.e. within vendor, which SoH component
				 */
				curr_shid = soh_pull_be_24(data);
				curr_shid_c = data[3];
				RDEBUG2("SoH System-Health-ID vendor %08x component=%i", curr_shid, curr_shid_c);
				break;

			case 7:
				/* Vendor-Specific packet
				 * MS-SOH 2.2.3.3
				 *
				 * 4 bytes vendor, supposedly ignored by NAP
				 * N bytes payload; for Microsoft component#0 this is the MS TV stuff
				 */
				if (curr_shid==0x137 && curr_shid_c==0) {
					RDEBUG2("SoH MS type-value payload");
					eapsoh_mstlv(request, data + 4, tlv.tlv_len - 4);
				} else {
					RDEBUG2("SoH unhandled vendor-specific TLV %08x/component=%i %i bytes payload", curr_shid, curr_shid_c, tlv.tlv_len);
				}
				break;

			case 8:
				/* Health-Class
				 * MS-SOH 2.2.3.5.6
				 *
				 * 1 byte integer
				 */
				RDEBUG2("SoH Health-Class %i", data[0]);
				curr_hc = data[0];
				break;

			case 9:
				/* Software-Version
				 * MS-SOH 2.2.3.5.7
				 *
				 * 1 byte integer
				 */
				RDEBUG2("SoH Software-Version %i", data[0]);
				break;

			case 11:
				/* Health-Class status
				 * MS-SOH 2.2.3.5.9
				 *
				 * variable data; for the MS System Health vendor, these are 4-byte
				 * integers which are a really, really dumb format:
				 *
				 *  28 bits ignore
				 *  1 bit - 1==product snoozed
				 *  1 bit - 1==microsoft product
				 *  1 bit - 1==product up-to-date
				 *  1 bit - 1==product enabled
				 */
				RDEBUG2("SoH Health-Class-Status - current shid=%08x component=%i", curr_shid, curr_shid_c);

				if (curr_shid==0x137 && curr_shid_c==128) {

					char const *s, *t;
					uint32_t hcstatus = soh_pull_be_32(data);

					RDEBUG2("SoH Health-Class-Status microsoft DWORD=%08x", hcstatus);

					vp = pairmake_packet("SoH-MS-Windows-Health-Status", NULL, T_OP_EQ);
					if (!vp) return 0;

					switch (curr_hc) {
						case 4:
							/* security updates */
							s = "security-updates";
							switch (hcstatus) {
								case 0xff0005:
									pairsprintf(vp, "%s ok all-installed", s);
									break;
								case 0xff0006:
									pairsprintf(vp, "%s warn some-missing", s);
									break;
								case 0xff0008:
									pairsprintf(vp, "%s warn never-started", s);
									break;
								case 0xc0ff000c:
									pairsprintf(vp, "%s error no-wsus-srv", s);
									break;
								case 0xc0ff000d:
									pairsprintf(vp, "%s error no-wsus-clid", s);
									break;
								case 0xc0ff000e:
									pairsprintf(vp, "%s warn wsus-disabled", s);
									break;
								case 0xc0ff000f:
									pairsprintf(vp, "%s error comm-failure", s);
									break;
								case 0xc0ff0010:
									pairsprintf(vp, "%s warn needs-reboot", s);
									break;
								default:
									pairsprintf(vp, "%s error %08x", s, hcstatus);
									break;
							}
							break;

						case 3:
							/* auto updates */
							s = "auto-updates";
							switch (hcstatus) {
								case 1:
									pairsprintf(vp, "%s warn disabled", s);
									break;
								case 2:
									pairsprintf(vp, "%s ok action=check-only", s);
									break;
								case 3:
									pairsprintf(vp, "%s ok action=download", s);
									break;
								case 4:
									pairsprintf(vp, "%s ok action=install", s);
									break;
								case 5:
									pairsprintf(vp, "%s warn unconfigured", s);
									break;
								case 0xc0ff0003:
									pairsprintf(vp, "%s warn service-down", s);
									break;
								case 0xc0ff0018:
									pairsprintf(vp, "%s warn never-started", s);
									break;
								default:
									pairsprintf(vp, "%s error %08x", s, hcstatus);
									break;
							}
							break;

						default:
							/* other - firewall, antivirus, antispyware */
							s = healthclass2str(curr_hc);
							if (s) {
								/* bah. this is vile. stupid microsoft
								 */
								if (hcstatus & 0xff000000) {
									/* top octet non-zero means an error
									 * FIXME: is this always correct? MS-WSH 2.2.8 is unclear
									 */
									t = clientstatus2str(hcstatus);
									if (t) {
										pairsprintf(vp, "%s error %s", s, t);
									} else {
										pairsprintf(vp, "%s error %08x", s, hcstatus);
									}
								} else {
									pairsprintf(vp,
											"%s ok snoozed=%i microsoft=%i up2date=%i enabled=%i",
											s,
											hcstatus & 0x8 ? 1 : 0,
											hcstatus & 0x4 ? 1 : 0,
											hcstatus & 0x2 ? 1 : 0,
											hcstatus & 0x1 ? 1 : 0
											);
								}
							} else {
								pairsprintf(vp, "%i unknown %08x", curr_hc, hcstatus);
							}
							break;
					}
				} else {
					vp = pairmake_packet("SoH-MS-Health-Other", NULL, T_OP_EQ);
					if (!vp) return 0;

					/* FIXME: what to do with the payload? */
					pairsprintf(vp, "%08x/%i ?", curr_shid, curr_shid_c);
				}
				break;

			default:
				RDEBUG("SoH Unknown TLV %i len=%i", tlv.tlv_type, tlv.tlv_len);
				break;
		}

		data += tlv.tlv_len;
		data_len -= tlv.tlv_len;
	}

	return 0;
}
Example #28
0
/*
 *	Accounting: save the account data to our redisn table
 */
static rlm_rcode_t rlm_redisn_accounting(void *instance, REQUEST * request) {

	REDISSOCK *redis_socket = NULL;
	VALUE_PAIR *pair;
	REDIS_INST *inst = instance;
	int	ret = RLM_MODULE_OK;
	int     acctstatustype = 0;
	char    logstr[MAX_QUERY_LEN];
	char	redisnusername[MAX_STRING_LEN];
	char**  queries=NULL;


	/*
	 * Find the Acct Status Type
	 */
	if ((pair = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY)) != NULL) {
		acctstatustype = pair->vp_integer;
	} else {
		radius_xlat(logstr, sizeof(logstr), "packet has no accounting status type. [user '%{User-Name}', nas '%{NAS-IP-Address}']", request, NULL, inst);
		radlog_request(L_ERR, 0, request, "%s", logstr);
		return RLM_MODULE_INVALID;
	}

	switch (acctstatustype) {
			/*
			 * The Terminal server informed us that it was rebooted
			 * STOP all records from this NAS
			 */
		case PW_STATUS_ACCOUNTING_ON:
		  RDEBUG("Received Acct On packet");
		  queries=inst->accounting_on_queries;
		  break;
		case PW_STATUS_ACCOUNTING_OFF:
		  RDEBUG("Received Acct Off packet");
		  queries=inst->accounting_off_queries;
		  break;
		case PW_STATUS_START:
		  RDEBUG("Received Acct Start packet");
		  queries=inst->accounting_start_queries;
		  break;
		case PW_STATUS_STOP:
		  RDEBUG("Received Acct Stop packet");
#if 0 //#ifdef CISCO_ACCOUNTING_HACK
		  {
		    /*
		     * If stop but zero session length AND no previous
		     * session found, drop it as in invalid packet
		     * This is to fix CISCO's aaa from filling our
		     * table with bogus crap
		   */
		    int     acctsessiontime = 0;
		    if ((pair = pairfind(request->packet->vps, PW_ACCT_SESSION_TIME, 0, TAG_ANY)) != NULL)
		      acctsessiontime = pair->vp_integer;
		    
		    if (acctsessiontime <= 0) {
		      radius_xlat(logstr, sizeof(logstr), "stop packet with zero session length. [user '%{User-Name}', nas '%{NAS-IP-Address}']", request, NULL, inst);
		      radlog_request(L_DBG, 0, request, "%s", logstr);
		      redisn_release_socket(inst, redis_socket);
		      return RLM_MODULE_NOOP;
		    }
		  }
#endif

		  queries=inst->accounting_stop_queries;
		  break;
		case PW_STATUS_ALIVE:
		  RDEBUG("Received Acct Alive packet");
		  queries=inst->accounting_update_queries;
		  break;
		  /*
		   *	Anything else is ignored.
		   */
	        default:
		  RDEBUG("Unsupported Acct-Status-Type = %d",
			 acctstatustype);
		  return RLM_MODULE_NOOP;
		  break;
	}
	if (queries==NULL ||*queries==NULL)
	  ret=RLM_MODULE_NOOP;
	else
	  {
	    char    querystr[MAX_QUERY_LEN];
	    redis_socket = redisn_get_socket(inst);
	    if (redis_socket == NULL)
	      return(RLM_MODULE_FAIL);

	    redisn_set_user(inst, request, redisnusername, NULL);

	    while(*queries) {
	      char* query=*queries;		
	      memset(querystr, 0, MAX_QUERY_LEN);
	      radius_xlat(querystr, sizeof(querystr), query, request, redisn_escape_func, inst);
	      query_log(request, inst, querystr);
	      
	      if (rlm_redisn_query(inst, redis_socket, querystr)) {
		radlog_request(L_ERR, 0, request, "Accounting query failed: %s",
			       querystr);
		ret = RLM_MODULE_FAIL;
	      }

	      (inst->redisn_finish_query)(inst, redis_socket);
	      queries++;
	    }
	    redisn_release_socket(inst, redis_socket);
	  }

	return ret;
}
Example #29
0
/*
 *	The xlat function
 */
static ssize_t perl_xlat(void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace)
{

	rlm_perl_t	*inst = (rlm_perl_t *) instance;
	char		*tmp;
	char const	*p, *q;
	int		count;
	size_t		ret = 0;
	STRLEN		n_a;

#ifdef USE_ITHREADS
	PerlInterpreter *interp;

	pthread_mutex_lock(&inst->clone_mutex);
	interp = rlm_perl_clone(inst->perl, inst->thread_key);
	{
		dTHXa(interp);
		PERL_SET_CONTEXT(interp);
	}
	pthread_mutex_unlock(&inst->clone_mutex);
#else
	PERL_SET_CONTEXT(inst->perl);
#endif
	{
		dSP;
		ENTER;SAVETMPS;

		PUSHMARK(SP);

		p = q = fmt;
		while (*p == ' ') {
			p++;
			q++;
		}
		while (*q) {
			if (*q == ' ') {
				XPUSHs(sv_2mortal(newSVpvn(p, q - p)));
				p = q + 1;

				/*
				 *	Don't use an empty string
				 */
				while (*p == ' ') p++;
				q = p;
			}
			q++;
		}

		/*
		 *	And the last bit.
		 */
		if (*p) {
			XPUSHs(sv_2mortal(newSVpvn(p, strlen(p))));
		}

		PUTBACK;

		count = call_pv(inst->func_xlat, G_SCALAR | G_EVAL);

		SPAGAIN;
		if (SvTRUE(ERRSV)) {
			REDEBUG("Exit %s", SvPV(ERRSV,n_a));
			(void)POPs;
		} else if (count > 0) {
			tmp = POPp;
			strlcpy(out, tmp, freespace);
			ret = strlen(out);

			RDEBUG("Len is %zu , out is %s freespace is %zu", ret, out, freespace);
		}

		PUTBACK ;
		FREETMPS ;
		LEAVE ;

	}

	return ret;
}
Example #30
0
/*
 *	%{poke:sql.foo=bar}
 */
static ssize_t xlat_poke(char **out, size_t outlen,
			 UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
			 REQUEST *request, char const *fmt)
{
	int i;
	void *data, *base;
	char *p, *q;
	module_instance_t *mi;
	char *buffer;
	CONF_SECTION *modules;
	CONF_PAIR *cp;
	CONF_PARSER const *variables;
	size_t len;

	rad_assert(outlen > 1);
	rad_assert(request != NULL);
	rad_assert(fmt != NULL);
	rad_assert(out != NULL);
	rad_assert(*out);

	modules = cf_section_sub_find(request->root->config, "modules");
	if (!modules) return 0;

	buffer = talloc_strdup(request, fmt);
	if (!buffer) return 0;

	p = strchr(buffer, '.');
	if (!p) return 0;

	*(p++) = '\0';

	mi = module_find(modules, buffer);
	if (!mi) {
		RDEBUG("Failed finding module '%s'", buffer);
	fail:
		talloc_free(buffer);
		return 0;
	}

	q = strchr(p, '=');
	if (!q) {
		RDEBUG("Failed finding '=' in string '%s'", fmt);
		goto fail;
	}

	*(q++) = '\0';

	if (strchr(p, '.') != NULL) {
		RDEBUG("Can't do sub-sections right now");
		goto fail;
	}

	cp = cf_pair_find(mi->cs, p);
	if (!cp) {
		RDEBUG("No such item '%s'", p);
		goto fail;
	}

	/*
	 *	Copy the old value to the output buffer, that way
	 *	tests can restore it later, if they need to.
	 */
	len = strlcpy(*out, cf_pair_value(cp), outlen);

	if (cf_pair_replace(mi->cs, cp, q) < 0) {
		RDEBUG("Failed replacing pair");
		goto fail;
	}

	base = mi->insthandle;
	variables = mi->entry->module->config;

	/*
	 *	Handle the known configuration parameters.
	 */
	for (i = 0; variables[i].name != NULL; i++) {
		int ret;

		if (variables[i].type == PW_TYPE_SUBSECTION) continue;
		/* else it's a CONF_PAIR */

		/*
		 *	Not the pair we want.  Skip it.
		 */
		if (strcmp(variables[i].name, p) != 0) continue;

		if (variables[i].data) {
			data = variables[i].data; /* prefer this. */
		} else if (base) {
			data = ((char *)base) + variables[i].offset;
		} else {
			DEBUG2("Internal sanity check 2 failed in cf_section_parse");
			goto fail;
		}

		/*
		 *	Parse the pair we found, or a default value.
		 */
		ret = cf_pair_parse(mi->cs, variables[i].name, variables[i].type,
				    data, variables[i].dflt, variables[i].quote);
		if (ret < 0) {
			DEBUG2("Failed inserting new value into module instance data");
			goto fail;
		}
		break;		/* we found it, don't do any more */
	}

	talloc_free(buffer);

	return len;
}