Esempio n. 1
0
int DBUtil::Execute(const char* sql, ...)
{
    SQL_INST* sqlinst = (SQL_INST*)dbHandle_;
    if(sqlinst == 0) {
        radlog(L_CONS|L_ERROR, "[DBUtil::Execute] invalid instance");
        return -1;
    }

    char sqlbuf[4096];
    va_list args;
    va_start(args, sql);
    vsNprintf(sqlbuf, sizeof(sqlbuf), sql, args);
    va_end(args);

    SQLSOCK* sqlsock = sql_get_socket(sqlinst);
    if(sqlsock == NULL) {
        return -1;
    }

    if(rlm_sql_query(sqlsock, sqlinst, sqlbuf) != 0) {
        sql_release_socket(sqlinst, sqlsock);
        return -1;
    }

    int result  = rlm_sql_affected_rows(sqlsock, sqlinst);

    rlm_sql_finish_query(sqlsock, sqlinst);
    sql_release_socket(sqlinst, sqlsock);
    return result;
}
Esempio n. 2
0
static
int SelectFirstRowInternal(SQL_INST* sqlinst, const char* sqlbuf, DBUtil::Row& row)
{
    SQLSOCK* sqlsock = sql_get_socket(sqlinst);
    if(sqlsock == NULL) {
        return -1;
    }

    if(rlm_sql_select_query(sqlsock, sqlinst, sqlbuf) != 0) {
        sql_release_socket(sqlinst, sqlsock);
        return -1;
    }

    if(rlm_sql_fetch_row(sqlsock, sqlinst) != 0) {
        rlm_sql_finish_select_query(sqlsock, sqlinst);
        sql_release_socket(sqlinst, sqlsock);
        return -1;
    }

    if(sqlsock->row == NULL) {
        rlm_sql_finish_select_query(sqlsock, sqlinst);
        sql_release_socket(sqlinst, sqlsock);
        return 0;
    }

    int colcnt = rlm_sql_num_fields(sqlsock, sqlinst);
    row.clear();
    for(int i=0; i<colcnt; ++i)
        row.push_back(sqlsock->row[i]);
    rlm_sql_finish_select_query(sqlsock, sqlinst);
    sql_release_socket(sqlinst, sqlsock);
    return 1;
}
Esempio n. 3
0
static int sql_groupcmp(void *instance, REQUEST *request, UNUSED VALUE_PAIR *request_vp, VALUE_PAIR *check,
			UNUSED VALUE_PAIR *check_pairs, UNUSED VALUE_PAIR **reply_pairs)
{
	rlm_sql_handle_t *handle;
	rlm_sql_t *inst = instance;
	rlm_sql_grouplist_t *head, *entry;

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

	/*
	 *	Get a socket for this lookup
	 */
	handle = sql_get_socket(inst);
	if (!handle) {
		return 1;
	}

	/*
	 *	Get the list of groups this user is a member of
	 */
	if (sql_get_grouplist(inst, handle, request, &head) < 0) {
		REDEBUG("Error getting group membership");
		sql_release_socket(inst, handle);
		return 1;
	}

	for (entry = head; entry != NULL; entry = entry->next) {
		if (strcmp(entry->name, check->vp_strvalue) == 0){
			RDEBUG("sql_groupcmp finished: User is a member of group %s",
			       check->vp_strvalue);
			talloc_free(head);
			sql_release_socket(inst, handle);
			return 0;
		}
	}

	/* Free the grouplist */
	talloc_free(head);
	sql_release_socket(inst,handle);

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

	return 1;
}
/* cleanup IP pools and sync them with radacct */
static int nvp_cleanup(rlm_sqlhpwippool_t *data)
{
	rlm_sql_handle_t *sqlsock;

	/* initialize the SQL socket */
	sqlsock = sql_get_socket(data->sqlinst);
	if (!sqlsock) {
		nvp_log(__LINE__, data, L_ERR, "nvp_cleanup(): error while "
					       "requesting new SQL connection");
		return 0;
	}

	/* free IPs of closed sessions */
	if (!nvp_freeclosed(data, sqlsock)) {
		sql_release_socket(data->sqlinst, sqlsock);
		return 0;
	}

	/* add sessions opened in the meantime */
	if (!nvp_query(__LINE__, data, sqlsock,
	    "UPDATE `%s`.`ips`, `radacct` "
	    	"SET "
	    		"`ips`.`pid` = 0, "
	    		"`ips`.`rsv_by` = `radacct`.`acctuniqueid`, "
	    		"`ips`.`rsv_since` = `radacct`.`acctstarttime`, "
	    		"`ips`.`rsv_until` = 0 "
	    	"WHERE "
	    		"`radacct`.`acctstoptime` IS NULL AND "     /* session is opened */
	    		"`ips`.`ip` = INET_ATON(`radacct`.`framedipaddress`) AND "
	    		"("
	    			"`ips`.`pid` IS NULL OR "
/*	    			"(`ips`.`rsv_until` > 0 AND `ips.`rsv_until` < NOW()) " */
	    			"`ips`.`rsv_until` != 0"   /* no acct pkt received yet */
	    		")",
	    data->db_name)) {
		sql_release_socket(data->sqlinst, sqlsock);
		return 0;
	}
	else {
		nvp_finish(data, sqlsock);
	}

	/* count number of free IP addresses in IP pools */
	if (!nvp_syncfree(data, sqlsock)) {
		sql_release_socket(data->sqlinst, sqlsock);
		return 0;
	}

	sql_release_socket(data->sqlinst, sqlsock);
	return 1;
}
Esempio n. 5
0
int DBUtil::Query(RowSet& rset, const char* sql, ...)
{
    SQL_INST* sqlinst = (SQL_INST*)dbHandle_;
    if(sqlinst == 0) {
        radlog(L_CONS|L_ERROR, "[DBUtil::Query] invalid instance");
        return -1;
    }

    char sqlbuf[4096];
    va_list args;
    va_start(args, sql);
    vsNprintf(sqlbuf, sizeof(sqlbuf), sql, args);
    va_end(args);

    SQLSOCK* sqlsock = sql_get_socket(sqlinst);
    if(sqlsock == NULL) {
        return -1;
    }

    if(rlm_sql_select_query(sqlsock, sqlinst, sqlbuf) != 0) {
        sql_release_socket(sqlinst, sqlsock);
        return -1;
    }

    int colcnt = rlm_sql_num_fields(sqlsock, sqlinst);
    int rownum = 0;
    rset.clear();
    for(;;) {
        if(rlm_sql_fetch_row(sqlsock, sqlinst) != 0) {
            rownum = -1;
            break;
        }

        if(sqlsock->row == NULL) {
            break;
        }

        ++rownum;
        Row row;
        for(int i=0; i<colcnt; ++i)
            row.push_back(sqlsock->row[i]);
        rset.push_back(row);
    }

    rlm_sql_finish_select_query(sqlsock, sqlinst);
    sql_release_socket(sqlinst, sqlsock);
    return rownum;
}
Esempio n. 6
0
/*
 *	Execute postauth_query after authentication
 */
static int rlm_sql_postauth(void *instance, REQUEST *request) {
	SQLSOCK 	*sqlsocket = NULL;
	SQL_INST	*inst = instance;
	char		querystr[MAX_QUERY_LEN];
	char		sqlusername[MAX_STRING_LEN];

	DEBUG("rlm_sql (%s): Processing sql_postauth", inst->config->xlat_name);

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

	/* If postauth_query is not defined, we stop here */
	if (inst->config->postauth_query[0] == '\0')
		return RLM_MODULE_NOOP;

	/* Expand variables in the query */
	memset(querystr, 0, MAX_QUERY_LEN);
	radius_xlat(querystr, sizeof(querystr), inst->config->postauth_query,
		    request, sql_escape_func);
	query_log(request, inst, querystr);
	DEBUG2("rlm_sql (%s) in sql_postauth: query is %s",
	       inst->config->xlat_name, querystr);

	/* Initialize the sql socket */
	sqlsocket = sql_get_socket(inst);
	if (sqlsocket == NULL)
		return RLM_MODULE_FAIL;

	/* Process the query */
	if (rlm_sql_query(sqlsocket, inst, querystr)) {
		radlog(L_ERR, "rlm_sql (%s) in sql_postauth: Database query error - %s",
		       inst->config->xlat_name,
		       (char *)(inst->module->sql_error)(sqlsocket, inst->config));
		sql_release_socket(inst, sqlsocket);
		return RLM_MODULE_FAIL;
	}
	(inst->module->sql_finish_query)(sqlsocket, inst->config);

	sql_release_socket(inst, sqlsocket);
	return RLM_MODULE_OK;
}
Esempio n. 7
0
static int generate_sql_clients(SQL_INST *inst)
{
	SQLSOCK *sqlsocket;
	SQL_ROW row;
	char querystr[MAX_QUERY_LEN];
	RADCLIENT *c;
	char *netmask;
	unsigned int i = 0;
	
	DEBUG("rlm_sql (%s): - generate_sql_clients",inst->config->xlat_name);

	if (inst->config->sql_nas_table == NULL){
		radlog(L_ERR, "rlm_sql (%s): sql_nas_table is NULL.",inst->config->xlat_name);
		return -1;
	}
	snprintf(querystr,MAX_QUERY_LEN - 1,"SELECT * FROM %s",inst->config->sql_nas_table);

	DEBUG("rlm_sql (%s): Query: %s",inst->config->xlat_name,querystr);
	sqlsocket = sql_get_socket(inst);
	if (sqlsocket == NULL)
		return -1;
	if (rlm_sql_select_query(sqlsocket,inst,querystr)){
		radlog(L_ERR, "rlm_sql (%s): database query error, %s: %s",
			inst->config->xlat_name,querystr,
			(char *)(inst->module->sql_error)(sqlsocket, inst->config));
		sql_release_socket(inst,sqlsocket);
		return -1;
	}

	while(rlm_sql_fetch_row(sqlsocket, inst) == 0) {
		i++;
		row = sqlsocket->row;
		if (row == NULL)
			break;
/*
 * Format:
 * Row1	Row2	Row3		Row4	Row5	Row6	Row7		Row8
 *
 * id	nasname	shortname	type	ports	secret	community	description
 *
 */

		if (!row[0]){
			radlog(L_ERR, "rlm_sql (%s): No row id found on pass %d",inst->config->xlat_name,i);
			continue;
		}
		if (!row[1]){
			radlog(L_ERR, "rlm_sql (%s): No nasname found for row %s",inst->config->xlat_name,row[0]);
			continue;
		}
		if (strlen(row[1]) >= sizeof(c->longname)){
			radlog(L_ERR, "rlm_sql (%s): nasname of length %d is greater than the allowed maximum of %d",
				inst->config->xlat_name,strlen(row[1]),sizeof(c->longname) - 1);
			continue;
		}	
		
		if (!row[2]){
			radlog(L_ERR, "rlm_sql (%s): No short name found for row %s",inst->config->xlat_name,row[0]);
			continue;
		}
		if (strlen(row[2]) >= sizeof(c->shortname)){
			radlog(L_ERR, "rlm_sql (%s): shortname of length %d is greater than the allowed maximum of %d",
				inst->config->xlat_name,strlen(row[2]),sizeof(c->shortname) - 1);
			continue;
		}
		if (row[3] && strlen(row[3]) >= sizeof(c->nastype)){
			radlog(L_ERR, "rlm_sql (%s): nastype of length %d is greater than the allowed maximum of %d",
				inst->config->xlat_name,strlen(row[3]),sizeof(c->nastype) - 1);
			continue;
		}
		if (!row[5]){
			radlog(L_ERR, "rlm_sql (%s): No secret found for row %s",inst->config->xlat_name,row[0]);
			continue;
		}
		if (strlen(row[5]) >= sizeof(c->secret)){
			radlog(L_ERR, "rlm_sql (%s): secret of length %d is greater than the allowed maximum of %d",
				inst->config->xlat_name,strlen(row[5]),sizeof(c->secret) - 1);
			continue;
		}

		DEBUG("rlm_sql (%s): Read entry nasname=%s,shortname=%s,secret=%s",inst->config->xlat_name,
			row[1],row[2],row[5]);

		c = rad_malloc(sizeof(RADCLIENT));
		memset(c, 0, sizeof(RADCLIENT));

		c->netmask = ~0;
		netmask = strchr(row[1], '/');
		
		/*
		 *      Look for netmasks.
		 */
		c->netmask = ~0;
		if (netmask) {
			int mask_length;

			mask_length = atoi(netmask + 1);
			if ((mask_length < 0) || (mask_length > 32)) {
				radlog(L_ERR, "rlm_sql (%s): Invalid value '%s' for IP network mask for nasname %s.",
						inst->config->xlat_name, netmask + 1,row[1]);
				free(c);
				continue;
			}

			if (mask_length == 0) {
				c->netmask = 0;
			} else {
				c->netmask = ~0 << (32 - mask_length);
			}

			*netmask = '\0';
			c->netmask = htonl(c->netmask);
		}

		c->ipaddr = ip_getaddr(row[1]);
		if (c->ipaddr == INADDR_NONE) {
			radlog(L_CONS|L_ERR, "rlm_sql (%s): Failed to look up hostname %s",
					inst->config->xlat_name, row[1]);
			free(c);
			continue;
		}

		/*
		 *      Update the client name again...
		 */
		if (netmask) {
			*netmask = '/';
			c->ipaddr &= c->netmask;
			strcpy(c->longname, row[1]);
		} else {
			ip_hostname(c->longname, sizeof(c->longname),
					c->ipaddr);
		}

		strcpy((char *)c->secret, row[5]);
		strcpy(c->shortname, row[2]);
		if(row[3] != NULL)
			strcpy(c->nastype, row[3]);

		DEBUG("rlm_sql (%s): Adding client %s (%s) to clients list",inst->config->xlat_name,
			c->longname,c->shortname);

		c->next = mainconfig.clients;
		mainconfig.clients = c;

	}
	(inst->module->sql_finish_select_query)(sqlsocket, inst->config);
	sql_release_socket(inst, sqlsocket);

	return 0;
}
Esempio n. 8
0
static rlm_rcode_t rlm_sql_authorize(void *instance, REQUEST * request)
{
	int ret = RLM_MODULE_NOTFOUND;
	
	rlm_sql_t *inst = instance;
	rlm_sql_handle_t  *handle;
	
	VALUE_PAIR *check_tmp = NULL;
	VALUE_PAIR *reply_tmp = NULL;
	VALUE_PAIR *user_profile = NULL;

	int	dofallthrough = 1;
	int	rows;

	char	querystr[MAX_QUERY_LEN];

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

	/*
	 *  Reserve a socket 
	 *
	 *  After this point use goto error or goto release to cleanup sockets
	 *  temporary pairlists and temporary attributes.
	 */
	handle = sql_get_socket(inst);
	if (handle == NULL)
		goto error;

	/*
	 *  Query the check table to find any conditions associated with 
	 *  this user/realm/whatever...
	 */
	if (inst->config->authorize_check_query &&
	    *inst->config->authorize_check_query) {
		if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_check_query, request, sql_escape_func, inst)) {
			radlog_request(L_ERR, 0, request, "Error generating query; rejecting user");
	
			goto error;
		}
		
		rows = sql_getvpdata(inst, &handle, &check_tmp, querystr);
		if (rows < 0) {
			radlog_request(L_ERR, 0, request, "SQL query error; rejecting user");
	
			goto error;
		}
		
		/*
		 *  Only do this if *some* check pairs were returned
		 */
		if ((rows > 0) && 
		    (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) == 0)) {	
			RDEBUG2("User found in radcheck table");
			
			radius_xlat_move(request, &request->config_items, &check_tmp);
			
			ret = RLM_MODULE_OK;
		}
		
		/*
		 *  We only process reply table items if check conditions
		 *  were verified
		 */
		else
			goto skipreply;
	}
	
	if (inst->config->authorize_reply_query &&
	    *inst->config->authorize_reply_query) {
		/*
		 *  Now get the reply pairs since the paircompare matched
		 */
		if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_reply_query, request, sql_escape_func, inst)) {
			radlog_request(L_ERR, 0, request, "Error generating query; rejecting user");
			
			goto error;
		}
		
		rows = sql_getvpdata(inst, &handle, &reply_tmp, querystr);
		if (rows < 0) {
			radlog_request(L_ERR, 0, request, "SQL query error; rejecting user");

			goto error;
		}
		
		if (rows > 0) {
			if (!inst->config->read_groups) {
				dofallthrough = fallthrough(reply_tmp);
			}
			
			RDEBUG2("User found in radreply table");
			
			radius_xlat_move(request, &request->reply->vps, &reply_tmp);
			
			ret = RLM_MODULE_OK;
		}
	}
	
	skipreply:

	/*
	 *  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.
	 */
	if (dofallthrough) {
		rows = rlm_sql_process_groups(inst, request, handle, &dofallthrough);
		if (rows < 0) {
			radlog_request(L_ERR, 0, request, "Error processing groups; rejecting user");

			goto error;
		}
		
		if (rows > 0)
			ret = RLM_MODULE_OK;
	}

	/*
	 *  Repeat the above process with the default profile or User-Profile
	 */
	if (dofallthrough) {
		/*
	 	 *  Check for a default_profile or for a User-Profile.
		 */
		user_profile = pairfind(request->config_items, PW_USER_PROFILE, 0, TAG_ANY);
		
		const char *profile = user_profile ?
				      user_profile->vp_strvalue :
				      inst->config->default_profile;
			
		if (!profile || !*profile)
			goto release;
			
		RDEBUG("Checking profile %s", profile);
		
		if (sql_set_user(inst, request, profile) < 0) {
			radlog_request(L_ERR, 0, request, "Error setting profile; rejecting user");

			goto error;
		}
		
		rows = rlm_sql_process_groups(inst, request, handle, &dofallthrough);
		if (rows < 0) {
			radlog_request(L_ERR, 0, request, "Error processing profile groups; rejecting user");

			goto error;
		}
		
		if (rows > 0)
			ret = RLM_MODULE_OK;
	}
	
	goto release;
	
	error:
	ret = RLM_MODULE_FAIL;
	
	release:
	sql_release_socket(inst, handle);
		
	pairfree(&check_tmp);
	pairfree(&reply_tmp);
	
	return ret;
}
Esempio n. 9
0
static int sql_groupcmp(void *instance, REQUEST *request, VALUE_PAIR *request_vp, VALUE_PAIR *check,
			VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
{
	rlm_sql_handle_t *handle;
	rlm_sql_t *inst = instance;
	rlm_sql_grouplist_t *group_list, *group_list_tmp;

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

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

	/*
	 *	Get a socket for this lookup
	 */
	handle = sql_get_socket(inst);
	if (handle == NULL) {
		return 1;
	}

	/*
	 *	Get the list of groups this user is a member of
	 */
	if (sql_get_grouplist(inst, handle, request, &group_list) < 0) {
		radlog_request(L_ERR, 0, request,
			       "Error getting group membership");
		sql_release_socket(inst, handle);
		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("sql_groupcmp finished: User is a member of group %s",
			       check->vp_strvalue);
			/* Free the grouplist */
			sql_grouplist_free(&group_list);
			sql_release_socket(inst, handle);
			return 0;
		}
	}

	/* Free the grouplist */
	sql_grouplist_free(&group_list);
	sql_release_socket(inst,handle);

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

	return 1;
}
Esempio n. 10
0
static int generate_sql_clients(rlm_sql_t *inst)
{
	rlm_sql_handle_t *handle;
	rlm_sql_row_t row;
	char querystr[MAX_QUERY_LEN];
	RADCLIENT *c;
	char *prefix_ptr = NULL;
	unsigned int i = 0;
	int numf = 0;

	DEBUG("rlm_sql (%s): Processing generate_sql_clients",
	      inst->config->xlat_name);

	/* NAS query isn't xlat'ed */
	strlcpy(querystr, inst->config->nas_query, sizeof(querystr));
	DEBUG("rlm_sql (%s) in generate_sql_clients: query is %s",
	      inst->config->xlat_name, querystr);

	handle = sql_get_socket(inst);
	if (handle == NULL)
		return -1;
	if (rlm_sql_select_query(&handle,inst,querystr)){
		return -1;
	}

	while(rlm_sql_fetch_row(&handle, inst) == 0) {
		i++;
		row = handle->row;
		if (row == NULL)
			break;
		/*
		 *  The return data for each row MUST be in the following order:
		 *
		 *  0. Row ID (currently unused)
		 *  1. Name (or IP address)
		 *  2. Shortname
		 *  3. Type
		 *  4. Secret
		 *  5. Virtual Server (optional)
		 */
		if (!row[0]){
			radlog(L_ERR, "rlm_sql (%s): No row id found on pass %d",inst->config->xlat_name,i);
			continue;
		}
		if (!row[1]){
			radlog(L_ERR, "rlm_sql (%s): No nasname found for row %s",inst->config->xlat_name,row[0]);
			continue;
		}
		if (!row[2]){
			radlog(L_ERR, "rlm_sql (%s): No short name found for row %s",inst->config->xlat_name,row[0]);
			continue;
		}
		if (!row[4]){
			radlog(L_ERR, "rlm_sql (%s): No secret found for row %s",inst->config->xlat_name,row[0]);
			continue;
		}

		DEBUG("rlm_sql (%s): Read entry nasname=%s,shortname=%s,secret=%s",inst->config->xlat_name,
			row[1],row[2],row[4]);

		c = talloc_zero(inst, RADCLIENT);

#ifdef WITH_DYNAMIC_CLIENTS
		c->dynamic = 1;
#endif

		/*
		 *	Look for prefixes
		 */
		c->prefix = -1;
		prefix_ptr = strchr(row[1], '/');
		if (prefix_ptr) {
			c->prefix = atoi(prefix_ptr + 1);
			if ((c->prefix < 0) || (c->prefix > 128)) {
				radlog(L_ERR, "rlm_sql (%s): Invalid Prefix value '%s' for IP.",
				       inst->config->xlat_name, prefix_ptr + 1);
				talloc_free(c);
				continue;
			}
			/* Replace '/' with '\0' */
			*prefix_ptr = '\0';
		}

		/*
		 *	Always get the numeric representation of IP
		 */
		if (ip_hton(row[1], AF_UNSPEC, &c->ipaddr) < 0) {
			radlog(L_ERR, "rlm_sql (%s): Failed to look up hostname %s: %s",
			       inst->config->xlat_name,
			       row[1], fr_strerror());
			talloc_free(c);
			continue;
		} else {
			char buffer[256];
			ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
			c->longname = talloc_strdup(c, buffer);
		}

		if (c->prefix < 0) switch (c->ipaddr.af) {
		case AF_INET:
			c->prefix = 32;
			break;
		case AF_INET6:
			c->prefix = 128;
			break;
		default:
			break;
		}

		/*
		 *	Other values (secret, shortname, nastype, virtual_server)
		 */
		c->secret = talloc_strdup(c, row[4]);
		c->shortname = talloc_strdup(c, row[2]);
		if(row[3] != NULL)
			c->nastype = strdup(row[3]);

		numf = (inst->module->sql_num_fields)(handle, inst->config);
		if ((numf > 5) && (row[5] != NULL) && *row[5]) c->server = strdup(row[5]);

		DEBUG("rlm_sql (%s): Adding client %s (%s, server=%s) to clients list",
		      inst->config->xlat_name,
		      c->longname,c->shortname, c->server ? c->server : "<none>");
		if (!client_add(NULL, c)) {
			sql_release_socket(inst, handle);
			DEBUG("rlm_sql (%s): Failed to add client %s (%s) to clients list.  Maybe there's a duplicate?",
			      inst->config->xlat_name,
			      c->longname,c->shortname);
			client_free(c);
			return -1;
		}
	}
	(inst->module->sql_finish_select_query)(handle, inst->config);
	sql_release_socket(inst, handle);

	return 0;
}
Esempio n. 11
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 afftected will be
 *  returned instead.
 */
static size_t sql_xlat(void *instance, REQUEST *request,
		    const char *fmt, char *out, size_t freespace)
{
	rlm_sql_handle_t *handle;
	rlm_sql_row_t row;
	rlm_sql_t *inst = instance;
	char querystr[MAX_QUERY_LEN];
	size_t ret = 0;

	RDEBUG("sql_xlat");

	/*
         * 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);
	/*
	 * Do an xlat on the provided string (nice recursive operation).
	 */
	if (!radius_xlat(querystr, sizeof(querystr), fmt, request, sql_escape_func, inst)) {
		radlog(L_ERR, "rlm_sql (%s): xlat failed.",
		       inst->config->xlat_name);
		return 0;
	}

	handle = sql_get_socket(inst);
	if (handle == NULL)
		return 0;

	rlm_sql_query_log(inst, request, NULL, querystr);

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

		if (rlm_sql_query(&handle,inst,querystr)) {
			sql_release_socket(inst,handle);
			
			return 0;
		}
	       
		numaffected = (inst->module->sql_affected_rows)(handle,
								inst->config);
		if (numaffected < 1) {
			RDEBUG("rlm_sql (%s): SQL query affected no rows",
				inst->config->xlat_name);
		}

		/*
		 *	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);
		ret = strlen(buffer);
		if (ret >= freespace){
			RDEBUG("rlm_sql (%s): Can't write result, insufficient string space",
			       inst->config->xlat_name);
			(inst->module->sql_finish_query)(handle,
							 inst->config);
			sql_release_socket(inst,handle);
			return 0;
		}
		
		memcpy(out, buffer, ret + 1); /* we did bounds checking above */

		(inst->module->sql_finish_query)(handle, inst->config);
		sql_release_socket(inst,handle);
		return ret;
	} /* else it's a SELECT statement */

	if (rlm_sql_select_query(&handle,inst,querystr)){
		sql_release_socket(inst,handle);
		return 0;
	}

	ret = rlm_sql_fetch_row(&handle, inst);
	if (ret) {
		RDEBUG("SQL query did not succeed");
		(inst->module->sql_finish_select_query)(handle, inst->config);
		sql_release_socket(inst,handle);
		return 0;
	}

	row = handle->row;
	if (row == NULL) {
		RDEBUG("SQL query did not return any results");
		(inst->module->sql_finish_select_query)(handle, inst->config);
		sql_release_socket(inst,handle);
		return 0;
	}

	if (row[0] == NULL){
		RDEBUG("Null value in first column");
		(inst->module->sql_finish_select_query)(handle, inst->config);
		sql_release_socket(inst,handle);
		return 0;
	}
	ret = strlen(row[0]);
	if (ret >= freespace){
		RDEBUG("Insufficient string space");
		(inst->module->sql_finish_select_query)(handle, inst->config);
		sql_release_socket(inst,handle);
		return 0;
	}

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

	RDEBUG("sql_xlat finished");

	(inst->module->sql_finish_select_query)(handle, inst->config);
	sql_release_socket(inst,handle);
	return ret;
}
Esempio n. 12
0
static int sql_groupcmp(void *instance, REQUEST *request, VALUE_PAIR *request_vp, VALUE_PAIR *check,
			VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
{
	SQLSOCK *sqlsocket;
	SQL_INST *inst = instance;
	char sqlusername[MAX_STRING_LEN];
	SQL_GROUPLIST *group_list, *group_list_tmp;

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

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

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

	/*
	 *	Get the list of groups this user is a member of
	 */
	if (sql_get_grouplist(inst, sqlsocket, 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_SQL_USER_NAME, 0);
		sql_release_socket(inst, sqlsocket);
		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("sql_groupcmp finished: User is a member of group %s",
			       check->vp_strvalue);
			/* Free the grouplist */
			sql_grouplist_free(&group_list);
			/* Remove the username we (maybe) added above */
			pairdelete(&request->packet->vps, PW_SQL_USER_NAME, 0);
			sql_release_socket(inst, sqlsocket);
			return 0;
		}
	}

	/* Free the grouplist */
	sql_grouplist_free(&group_list);
	/* Remove the username we (maybe) added above */
	pairdelete(&request->packet->vps, PW_SQL_USER_NAME, 0);
	sql_release_socket(inst,sqlsocket);

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

	return 1;
}
Esempio n. 13
0
static int rlm_sql_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;
	SQLSOCK *sqlsocket;
	SQL_INST *inst = instance;
	char    querystr[MAX_QUERY_LEN];
	char	sqlusername[MAX_STRING_LEN];
	/*
	 * the profile username is used as the sqlusername during
	 * profile checking so that we don't overwrite the orignal
	 * sqlusername string
	 */
	char   profileusername[MAX_STRING_LEN];

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


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


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

	/*
	 * Alright, start by getting the specific entry for the user
	 */
	if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_check_query, request, sql_escape_func)) {
		radlog_request(L_ERR, 0, request, "Error generating query; rejecting user");
		sql_release_socket(inst, sqlsocket);
		/* Remove the username we (maybe) added above */
		pairdelete(&request->packet->vps, PW_SQL_USER_NAME, 0);
		return RLM_MODULE_FAIL;
	}
	rows = sql_getvpdata(inst, sqlsocket, &check_tmp, querystr);
	if (rows < 0) {
		radlog_request(L_ERR, 0, request, "SQL query error; rejecting user");
		sql_release_socket(inst, sqlsocket);
		/* Remove the username we (maybe) added above */
		pairdelete(&request->packet->vps, PW_SQL_USER_NAME, 0);
		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->config->authorize_reply_query &&
			    *inst->config->authorize_reply_query) {

			/*
			 *	Now get the reply pairs since the paircompare matched
			 */
			if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_reply_query, request, sql_escape_func)) {
				radlog_request(L_ERR, 0, request, "Error generating query; rejecting user");
				sql_release_socket(inst, sqlsocket);
				/* Remove the username we (maybe) added above */
				pairdelete(&request->packet->vps, PW_SQL_USER_NAME, 0);
				pairfree(&check_tmp);
				return RLM_MODULE_FAIL;
			}
			if (sql_getvpdata(inst, sqlsocket, &reply_tmp, querystr) < 0) {
				radlog_request(L_ERR, 0, request, "SQL query error; rejecting user");
				sql_release_socket(inst, sqlsocket);
				/* Remove the username we (maybe) added above */
				pairdelete(&request->packet->vps, PW_SQL_USER_NAME, 0);
				pairfree(&check_tmp);
				pairfree(&reply_tmp);
				return RLM_MODULE_FAIL;
			}

			if (!inst->config->read_groups)
				dofallthrough = fallthrough(reply_tmp);
			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
	 */
	if (dofallthrough) {
		rows = rlm_sql_process_groups(inst, request, sqlsocket, &dofallthrough);
		if (rows < 0) {
			radlog_request(L_ERR, 0, request, "Error processing groups; rejecting user");
			sql_release_socket(inst, sqlsocket);
			/* Remove the username we (maybe) added above */
			pairdelete(&request->packet->vps, PW_SQL_USER_NAME, 0);
			return RLM_MODULE_FAIL;
		} else if (rows > 0) {
			found = 1;
		}
	}

	/*
	 *	repeat the above process with the default profile or User-Profile
	 */
	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);
		if (inst->config->default_profile[0] != 0 || user_profile != NULL){
			char *profile = inst->config->default_profile;

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

		if (profile_found) {
			rows = rlm_sql_process_groups(inst, request, sqlsocket, &dofallthrough);
			if (rows < 0) {
				radlog_request(L_ERR, 0, request, "Error processing profile groups; rejecting user");
				sql_release_socket(inst, sqlsocket);
				/* Remove the username we (maybe) added above */
				pairdelete(&request->packet->vps, PW_SQL_USER_NAME, 0);
				return RLM_MODULE_FAIL;
			} else if (rows > 0) {
				found = 1;
			}
		}
	}

	/* Remove the username we (maybe) added above */
	pairdelete(&request->packet->vps, PW_SQL_USER_NAME, 0);
	sql_release_socket(inst, sqlsocket);

	if (!found) {
		RDEBUG("User %s not found", sqlusername);
		return RLM_MODULE_NOTFOUND;
	} else {
		return RLM_MODULE_OK;
	}
}
Esempio n. 14
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 afftected 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 = sql_get_socket(inst);
	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)) {
			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)){
		char const *error = (inst->module->sql_error)(handle, inst->config);
		REDEBUG("SQL query failed: %s", error);
		ret = -1;

		goto finish;
	}

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

		goto finish;
	}

	row = handle->row;
	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:
	sql_release_socket(inst, handle);

	return ret;
}
Esempio n. 15
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 = sql_get_socket(inst);
	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 sql_release_socket.
		 */
		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);
	sql_release_socket(inst, handle);

	return rcode;
}
/* assign new IP address, if required */
static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request)
{
	VALUE_PAIR *vp;
	char const *pname;       /* name of requested IP pool */
	uint32_t nasip;	     /* NAS IP in host byte order */
	struct in_addr ip = {0};    /* reserved IP for client (net. byte order) */
	rlm_sql_handle_t *sqlsock;
	unsigned long s_gid,	/* _s_elected in sql result set */
		      s_prio,       /* as above */
		      s_pid,	/* as above */
		      gid,	  /* real integer value */
		      pid,	  /* as above */
		      weights_sum, used_sum, ip_start, ip_stop, connid;
	long prio;

	rlm_sqlhpwippool_t *inst = (rlm_sqlhpwippool_t *) instance;

	/* if IP is already there, then nothing to do */
	vp = pairfind(request->reply->vps, PW_FRAMED_IP_ADDRESS, 0, TAG_ANY);
	if (vp) {
		nvp_log(__LINE__, inst, L_DBG,
			"mod_post_auth(): IP address "
			"already in the reply packet - exiting");
		return RLM_MODULE_NOOP;
	}

	/* if no pool name, we don't need to do anything */
	vp = pairfind(request->reply->vps, ASN_IP_POOL_NAME, VENDORPEC_ASN, TAG_ANY);
	if (vp) {
		pname = vp->vp_strvalue;
		nvp_log(__LINE__, inst, L_DBG,
			"mod_post_auth(): pool name = '%s'",
			pname);
	}
	else {
		nvp_log(__LINE__, inst, L_DBG,
			"mod_post_auth(): no IP pool name - exiting");
		return RLM_MODULE_NOOP;
	}

	/* if no NAS IP address, assign 0 */
	vp = pairfind(request->packet->vps, PW_NAS_IP_ADDRESS, 0, TAG_ANY);
	if (vp) {
		nasip = ntohl(vp->vp_ipaddr);
	}
	else {
		nasip = 0;
		nvp_log(__LINE__, inst, L_DBG,
			"mod_post_auth(): no NAS IP address in "
			"the request packet - using \"0.0.0.0/0\" (any)");
	}

	/* get our database connection */
	sqlsock = sql_get_socket(inst->sqlinst);
	if (!sqlsock) {
		nvp_log(__LINE__, inst, L_ERR,
			"mod_post_auth(): error while requesting an SQL socket");
		return RLM_MODULE_FAIL;
	}

	/* get connection id as temporary unique integer */
	if (nvp_select(__LINE__, inst, sqlsock, "SELECT CONNECTION_ID()") < 1) {
		nvp_log(__LINE__, inst, L_ERR, "mod_post_auth(): WTF ;-)!");
		nvp_select_finish(inst, sqlsock);
		sql_release_socket(inst->sqlinst, sqlsock);
		return RLM_MODULE_FAIL;
	}

	connid = strtoul(sqlsock->row[0], (char **) NULL, 10);
	nvp_select_finish(inst, sqlsock);

	/* synchronize with radacct db, if needed */
	if (++inst->sincesync >= inst->sync_after
#ifdef HAVE_PTHREAD_D
	    && (pthread_mutex_trylock(&inst->mutex)) == 0
#endif
	   ) {
		int r;

		inst->sincesync = 0;

		nvp_log(__LINE__, inst, L_DBG,
			"mod_post_auth(): syncing with radacct table");

		r = (nvp_freeclosed(inst, sqlsock) && nvp_syncfree(inst, sqlsock));

#ifdef HAVE_PTHREAD_D
		pthread_mutex_unlock(&inst->mutex);
#endif

		if (!r) {
			nvp_log(__LINE__, inst, L_ERR,
				"mod_post_auth(): synchronization failed");
			sql_release_socket(inst->sqlinst, sqlsock);
			return RLM_MODULE_FAIL;
		}
	}

	for (s_gid = 0; s_gid < RLM_NETVIM_MAX_ROWS && !(ip.s_addr); s_gid++) {
		nvp_log(__LINE__, inst, L_DBG,
			"mod_post_auth(): selecting gid on position %lu",
			s_gid);

		/* find the most specific group which NAS belongs to */
		switch (nvp_select(__LINE__, inst, sqlsock,
		       "SELECT `host_groups`.`gid` "
		       	"FROM "
		       		"`%s`.`host_groups`, "
		       		"`%1$s`.`gid_ip`, "
		       		"`%1$s`.`ids` "
		       	"WHERE "
		       		"`host_groups`.`gid` = `ids`.`id` AND "
		       		"`ids`.`enabled` = 1 AND "
		       		"`host_groups`.`gid` = `gid_ip`.`gid` AND "
		       		"%lu BETWEEN `gid_ip`.`ip_start` AND `gid_ip`.`ip_stop` "
		       	"ORDER BY (`gid_ip`.`ip_stop` - `gid_ip`.`ip_start`) ASC "
		       	"LIMIT %lu, 1",
		       inst->db_name, nasip, s_gid)) {
			case -1:
				nvp_log(__LINE__, inst, L_ERR,
					"mod_post_auth(): couldn't find "
					"any more matching host groups");
				goto end_gid;		  /* exit the main loop */
			case 0:
				sql_release_socket(inst->sqlinst, sqlsock);
				return RLM_MODULE_FAIL;
		}

		/* store the group ID and free memory occupied by results */
		gid = strtoul(sqlsock->row[0], (char **) NULL, 10);
		nvp_select_finish(inst, sqlsock);

		for (s_prio = 0; s_prio < RLM_NETVIM_MAX_ROWS && !(ip.s_addr); s_prio++) {
			nvp_log(__LINE__, inst, L_DBG,
				"mod_post_auth(): selecting prio on position %lu",
				s_prio);

			/* prepare to search for best fit pool */
			switch (nvp_select(__LINE__, inst, sqlsock,
				"SELECT "
					"`ip_pools`.`prio`, "
					"SUM(`ip_pools`.`weight`) AS `weights_sum`, "
					"(SUM(`ip_pools`.`total`) - "
						"SUM(`ip_pools`.`free`)) AS `used_sum` "
					"FROM "
						"`%s`.`ip_pools`, "
						"`%1$s`.`ids`, "
					 	"`%1$s`.`pool_names` "
					"WHERE "
						"`ip_pools`.`gid` = %lu AND "
						"`ids`.`id` = `ip_pools`.`pid` AND "
						"`ids`.`enabled` = 1 AND "
						"`pool_names`.`pnid` = `ip_pools`.`pnid` AND "
						"`pool_names`.`name` = '%s' AND "
						"`ip_pools`.`free` > 0 "
					"GROUP BY `prio` "
					"ORDER BY `prio` ASC "
					"LIMIT %lu, 1",
				inst->db_name, gid, pname, s_prio)) {
				case -1:
					nvp_log(__LINE__, inst, L_DBG,
						"mod_post_auth(): couldn't find "
						"any more matching pools for gid = %u",
						gid);
					goto end_prio;	       /* select next gid */
				case 0:
					sql_release_socket(inst->sqlinst, sqlsock);
					return RLM_MODULE_FAIL;
			}

			/* store the prio and weights sum */
			prio = strtol(sqlsock->row[0], (char **) NULL, 10);
			weights_sum = strtoul(sqlsock->row[1], (char **) NULL, 10);
			used_sum = strtoul(sqlsock->row[2], (char **) NULL, 10);

			/* free memory */
			nvp_select_finish(inst, sqlsock);

			for (s_pid = 0; s_pid < RLM_NETVIM_MAX_ROWS && !(ip.s_addr); s_pid++) {
				nvp_log(__LINE__, inst, L_DBG,
					"mod_post_auth(): selecting PID on position %lu",
					s_pid);

				/* search for best fit pool */
				switch (nvp_select(__LINE__, inst, sqlsock,
					"SELECT "
						"`ip_pools`.`pid`, "
						"`ip_pools`.`ip_start`, "
						"`ip_pools`.`ip_stop` "
						"FROM "
							"`%s`.`ip_pools`, "
							"`%1$s`.`ids`, "
							"`%1$s`.`pool_names` "
						"WHERE "
							"`ip_pools`.`gid` = %lu AND "
							"`ids`.`id` = `ip_pools`.`pid` AND "
							"`ids`.`enabled` = 1 AND "
							"`pool_names`.`pnid` = `ip_pools`.`pnid` AND "
							"`pool_names`.`name` = '%s' AND "
							"`ip_pools`.`free` > 0 AND "
							"`prio` = %ld "
						"ORDER BY (`weight`/%lu.0000 - (`total` - `free`)/%lu) DESC "
						"LIMIT %lu, 1",
					inst->db_name, gid, pname, prio,
					weights_sum, used_sum, s_pid)) {
					case -1:
						nvp_log(__LINE__, inst, L_DBG,
							"mod_post_auth(): couldn't find any more "
							"matching pools of prio = %ld for gid = %lu",
							prio, gid);
						goto end_pid;	      /* select next prio */
					case 0:
						sql_release_socket(inst->sqlinst, sqlsock);
						return RLM_MODULE_FAIL;
				}

				/* store the inst and free memory occupied by results */
				pid = strtoul(sqlsock->row[0], (char **) NULL, 10);
				ip_start = strtoul(sqlsock->row[1], (char **) NULL, 10);
				ip_stop = strtoul(sqlsock->row[2], (char **) NULL, 10);
				nvp_select_finish(inst, sqlsock);

				/* reserve an IP address */
				if (!nvp_query(__LINE__, inst, sqlsock,
				    "UPDATE `%s`.`ips` "
				    	"SET "
				    		"`pid` = %lu, "
				    		"`rsv_since` = NOW(), "
				    		"`rsv_by` = '" RLM_NETVIM_TMP_PREFIX "%lu', "
				    		"`rsv_until` = NOW() + INTERVAL %d SECOND "
				    	"WHERE "
				    		"`ip` BETWEEN %lu AND %lu AND "
				    		"("
				    			"`pid` IS NULL OR "
				    			"(`rsv_until` > 0 AND `rsv_until` < NOW())"
				    		") "
				    	"ORDER BY RAND() "
				    	"LIMIT 1",
				    inst->db_name, pid, connid, inst->free_after, ip_start, ip_stop)) {
					sql_release_socket(inst->sqlinst, sqlsock);
					return RLM_MODULE_FAIL;
				}
				else {
					nvp_finish(inst, sqlsock);
				}

				/* select assigned IP address */
				switch (nvp_select(__LINE__, inst, sqlsock,
					"SELECT `ip` "
						"FROM `%s`.`ips` "
						"WHERE `rsv_by` = '" RLM_NETVIM_TMP_PREFIX "%lu' "
						"ORDER BY `rsv_since` DESC "
						"LIMIT 1",
					inst->db_name, connid)) {
					case -1:
						nvp_log(__LINE__, inst, L_ERR,
							"mod_post_auth(): couldn't reserve an IP address "
							"from pool of pid = %lu (prio = %ld, gid = %lu)",
							pid, prio, gid);
						continue;			    /* select next pid */
					case 0:
						sql_release_socket(inst->sqlinst, sqlsock);
						return RLM_MODULE_FAIL;
				}

				/* update free IPs count */
				if (!nvp_query(__LINE__, inst, sqlsock,
				    "UPDATE `%s`.`ip_pools` "
				    	"SET "
				    		"`free` = `free` - 1 "
				    	"WHERE "
				    		"`pid` = %lu "
			    	"LIMIT 1",
				    inst->db_name, pid)) {
					sql_release_socket(inst->sqlinst, sqlsock);
					return RLM_MODULE_FAIL;
				}
				else {
					nvp_finish(inst, sqlsock);
				}

				/* get assigned IP and free memory */
				ip.s_addr = htonl(strtoul(sqlsock->row[0], (char **) NULL, 10));
				nvp_select_finish(inst, sqlsock);
			} /* pid */
end_pid: continue;	   /* stupid */
		} /* prio */
end_prio: continue;	  /* stupid */
	} /* gid */
end_gid:

	/* release SQL socket */
	sql_release_socket(inst->sqlinst, sqlsock);

	/* no free IP address found */
	if (!ip.s_addr) {
		nvp_log(__LINE__, inst, L_INFO,
			"mod_post_auth(): no free IP address found!");

		if (inst->no_free_fail) {
			nvp_log(__LINE__, inst, L_DBG, "mod_post_auth(): rejecting user");
			return RLM_MODULE_REJECT;
		}
		else {
			nvp_log(__LINE__, inst, L_DBG, "mod_post_auth(): exiting");
			return RLM_MODULE_NOOP;
		}
	}

	/* add IP address to reply packet */
	vp = radius_paircreate(request, &request->reply->vps,
			       PW_FRAMED_IP_ADDRESS, 0);
	vp->vp_ipaddr = ip.s_addr;

	nvp_log(__LINE__, inst, L_DBG, "mod_post_auth(): returning %s",
		inet_ntoa(ip));
	return RLM_MODULE_OK;
}
Esempio n. 17
0
/*
 *	sql xlat function. Right now only SELECTs are supported. Only
 *	the first element of the SELECT result will be used.
 */
static int sql_xlat(void *instance, REQUEST *request,
		    char *fmt, char *out, size_t freespace,
		    RADIUS_ESCAPE_STRING func)
{
	SQLSOCK *sqlsocket;
	SQL_ROW row;
	SQL_INST *inst = instance;
	char querystr[MAX_QUERY_LEN];
	char sqlusername[MAX_STRING_LEN];
	int ret = 0;

	DEBUG("rlm_sql (%s): - sql_xlat", inst->config->xlat_name);
	/*
         * 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, sqlusername, NULL);
	/*
	 * Do an xlat on the provided string (nice recursive operation).
	 */
	if (!radius_xlat(querystr, sizeof(querystr), fmt, request, sql_escape_func)) {
		radlog(L_ERR, "rlm_sql (%s): xlat failed.",
		       inst->config->xlat_name);
		return 0;
	}

	query_log(request, inst,querystr);
	sqlsocket = sql_get_socket(inst);
	if (sqlsocket == NULL)
		return 0;
	if (rlm_sql_select_query(sqlsocket,inst,querystr)){
		radlog(L_ERR, "rlm_sql (%s): database query error, %s: %s",
		       inst->config->xlat_name,querystr,
		       (char *)(inst->module->sql_error)(sqlsocket, inst->config));
		sql_release_socket(inst,sqlsocket);
		return 0;
	}

	ret = rlm_sql_fetch_row(sqlsocket, inst);

	if (ret) {
		DEBUG("rlm_sql (%s): SQL query did not succeed",
		      inst->config->xlat_name);
		(inst->module->sql_finish_select_query)(sqlsocket, inst->config);
		sql_release_socket(inst,sqlsocket);
		return 0;
	}

	row = sqlsocket->row;
	if (row == NULL) {
		DEBUG("rlm_sql (%s): SQL query did not return any results",
		      inst->config->xlat_name);
		(inst->module->sql_finish_select_query)(sqlsocket, inst->config);
		sql_release_socket(inst,sqlsocket);
		return 0;
	}

	if (row[0] == NULL){
		DEBUG("rlm_sql (%s): row[0] returned NULL",
		      inst->config->xlat_name);
		(inst->module->sql_finish_select_query)(sqlsocket, inst->config);
		sql_release_socket(inst,sqlsocket);
		return 0;
	}
	ret = strlen(row[0]);
	if (ret > freespace){
		DEBUG("rlm_sql (%s): sql_xlat:: Insufficient string space",
		      inst->config->xlat_name);
		(inst->module->sql_finish_select_query)(sqlsocket, inst->config);
		sql_release_socket(inst,sqlsocket);
		return 0;
	}

	strncpy(out,row[0],ret);

	DEBUG("rlm_sql (%s): - sql_xlat finished",
	      inst->config->xlat_name);

	(inst->module->sql_finish_select_query)(sqlsocket, inst->config);
	sql_release_socket(inst,sqlsocket);
	return ret;
}
Esempio n. 18
0
static int rlm_sql_checksimul(void *instance, REQUEST * request) {
	SQLSOCK 	*sqlsocket;
	SQL_INST	*inst = instance;
	SQL_ROW		row;
	char		querystr[MAX_QUERY_LEN];
	char		sqlusername[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->config->simul_count_query[0] == 0) {
		return RLM_MODULE_NOOP;
	}

	if((request->username == NULL) || (request->username->length == 0)) {
		radlog(L_ERR, "rlm_sql (%s): Zero Length username not permitted\n", inst->config->xlat_name);
		return RLM_MODULE_INVALID;
	}


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

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

	/* initialize the sql socket */
	sqlsocket = sql_get_socket(inst);
	if(sqlsocket == NULL)
		return RLM_MODULE_FAIL;

	if(rlm_sql_select_query(sqlsocket, inst, querystr)) {
		radlog(L_ERR, "rlm_sql (%s) sql_checksimul: Database query failed", inst->config->xlat_name);
		sql_release_socket(inst, sqlsocket);
		return RLM_MODULE_FAIL;
	}

	ret = rlm_sql_fetch_row(sqlsocket, inst);

	if (ret != 0) {
		(inst->module->sql_finish_select_query)(sqlsocket, inst->config);
		sql_release_socket(inst, sqlsocket);
		return RLM_MODULE_FAIL;
	}

	row = sqlsocket->row;
	if (row == NULL) {
		(inst->module->sql_finish_select_query)(sqlsocket, inst->config);
		sql_release_socket(inst, sqlsocket);
		return RLM_MODULE_FAIL;
	}

	request->simul_count = atoi(row[0]);
	(inst->module->sql_finish_select_query)(sqlsocket, inst->config);

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

	/* Looks like too many sessions, so lets start verifying them */

	if (inst->config->simul_verify_query[0] == 0) {
		/* No verify query defined, so skip verify step and rely on count query only */
		sql_release_socket(inst, sqlsocket);
		return RLM_MODULE_OK;
	}

	radius_xlat(querystr, sizeof(querystr), inst->config->simul_verify_query, request, sql_escape_func);
	if(rlm_sql_select_query(sqlsocket, inst, querystr)) {
		radlog(L_ERR, "rlm_sql (%s): sql_checksimul: Database query error", inst->config->xlat_name);
		sql_release_socket(inst, sqlsocket);
		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)) != NULL)
                ipno = vp->lvalue;
        if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID)) != NULL)
                call_num = vp->strvalue;


	while (rlm_sql_fetch_row(sqlsocket, inst) == 0) {
		row = sqlsocket->row;
		if (row == NULL)
			break;
		if (!row[2]){
			(inst->module->sql_finish_select_query)(sqlsocket, inst->config);
			sql_release_socket(inst, sqlsocket);
			DEBUG("rlm_sql (%s): Cannot zap stale entry. No username present in entry.", inst->config->xlat_name);
			return RLM_MODULE_FAIL;
		}
		if (!row[1]){
			(inst->module->sql_finish_select_query)(sqlsocket, inst->config);
			sql_release_socket(inst, sqlsocket);
			DEBUG("rlm_sql (%s): Cannot zap stale entry. No session id in entry.", inst->config->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]);

                /*
                 *      Failed to check the terminal server for
                 *      duplicate logins: Return an error.
                 */
		if (check < 0) {
			(inst->module->sql_finish_select_query)(sqlsocket, inst->config);
			sql_release_socket(inst, sqlsocket);
			DEBUG("rlm_sql (%s) rad_check_ts() failed.",
			      inst->config->xlat_name);
			return RLM_MODULE_FAIL;
		}

		if(check == 1) {
			++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 {
                        /*
                         *      Stale record - zap it.
                         */
			uint32_t framed_addr = 0;
			char proto = 'P';

			if (row[5])
				framed_addr = inet_addr(row[5]);
			if (row[7])
				if (strcmp(row[7],"SLIP") == 0)
					proto = 'S';

			session_zap(request,
				    nas_addr,nas_port,row[2],row[1],
				    framed_addr, proto);
		}
	}

	(inst->module->sql_finish_select_query)(sqlsocket, inst->config);
	sql_release_socket(inst, sqlsocket);

	/* 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;

}
Esempio n. 19
0
static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
{
	rlm_rcode_t rcode = RLM_MODULE_NOOP;

	rlm_sql_t *inst = instance;
	rlm_sql_handle_t  *handle;

	VALUE_PAIR *check_tmp = NULL;
	VALUE_PAIR *reply_tmp = NULL;
	VALUE_PAIR *user_profile = NULL;

	bool	user_found = false;

	sql_fall_through_t do_fall_through = FALL_THROUGH_DEFAULT;

	int	rows;

	char	*expanded = NULL;

	rad_assert(request->packet != NULL);
	rad_assert(request->reply != NULL);

	if (!inst->config->authorize_check_query && !inst->config->authorize_reply_query &&
	    !inst->config->read_groups && !inst->config->read_profiles) {
	 	RWDEBUG("No authorization checks configured, returning noop");

	 	return RLM_MODULE_NOOP;
	}

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

	/*
	 *	Reserve a socket
	 *
	 *	After this point use goto error or goto release to cleanup socket temporary pairlists and
	 *	temporary attributes.
	 */
	handle = sql_get_socket(inst);
	if (!handle) {
		rcode = RLM_MODULE_FAIL;
		goto error;
	}

	/*
	 *	Query the check table to find any conditions associated with this user/realm/whatever...
	 */
	if (inst->config->authorize_check_query) {
		vp_cursor_t cursor;
		VALUE_PAIR *vp;

		if (radius_axlat(&expanded, request, inst->config->authorize_check_query,
				 sql_escape_func, inst) < 0) {
			REDEBUG("Error generating query");
			rcode = RLM_MODULE_FAIL;
			goto error;
		}

		rows = sql_getvpdata(request, inst, &handle, &check_tmp, expanded);
		TALLOC_FREE(expanded);
		if (rows < 0) {
			REDEBUG("SQL query error");
			rcode = RLM_MODULE_FAIL;
			goto error;
		}

		if (rows == 0) goto skipreply;	/* Don't need to free VPs we don't have */

		/*
		 *	Only do this if *some* check pairs were returned
		 */
		RDEBUG2("User found in radcheck table");
		user_found = true;
		if (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) != 0) {
			pairfree(&check_tmp);
			check_tmp = NULL;
			goto skipreply;
		}

		RDEBUG2("Conditional check items matched, merging assignment check items");
		RINDENT();
		for (vp = fr_cursor_init(&cursor, &check_tmp);
		     vp;
		     vp = fr_cursor_next(&cursor)) {
			if (!fr_assignment_op[vp->op]) continue;

			rdebug_pair(2, request, vp);
		}
		REXDENT();
		radius_pairmove(request, &request->config_items, check_tmp, true);

		rcode = RLM_MODULE_OK;
		check_tmp = NULL;
	}

	if (inst->config->authorize_reply_query) {
		/*
		 *	Now get the reply pairs since the paircompare matched
		 */
		if (radius_axlat(&expanded, request, inst->config->authorize_reply_query,
				 sql_escape_func, inst) < 0) {
			REDEBUG("Error generating query");
			rcode = RLM_MODULE_FAIL;
			goto error;
		}

		rows = sql_getvpdata(request->reply, inst, &handle, &reply_tmp, expanded);
		TALLOC_FREE(expanded);
		if (rows < 0) {
			REDEBUG("SQL query error");
			rcode = RLM_MODULE_FAIL;
			goto error;
		}

		if (rows == 0) goto skipreply;

		do_fall_through = fall_through(reply_tmp);

		RDEBUG2("User found in radreply table, merging reply items");
		user_found = true;

		rdebug_pair_list(L_DBG_LVL_2, request, reply_tmp);

		radius_pairmove(request, &request->reply->vps, reply_tmp, true);

		rcode = RLM_MODULE_OK;
		reply_tmp = NULL;
	}

skipreply:
	if ((do_fall_through == FALL_THROUGH_YES) ||
	    (inst->config->read_groups && (do_fall_through == FALL_THROUGH_DEFAULT))) {
		rlm_rcode_t ret;

		RDEBUG3("... falling-through to group processing");
		ret = rlm_sql_process_groups(inst, request, &handle, &do_fall_through);
		switch (ret) {
		/*
		 *	Nothing bad happened, continue...
		 */
		case RLM_MODULE_UPDATED:
			rcode = RLM_MODULE_UPDATED;
			/* FALL-THROUGH */
		case RLM_MODULE_OK:
			if (rcode != RLM_MODULE_UPDATED) {
				rcode = RLM_MODULE_OK;
			}
			/* FALL-THROUGH */
		case RLM_MODULE_NOOP:
			user_found = true;
			break;

		case RLM_MODULE_NOTFOUND:
			break;

		default:
			rcode = ret;
			goto release;
		}
	}

	/*
	 *	Repeat the above process with the default profile or User-Profile
	 */
	if ((do_fall_through == FALL_THROUGH_YES) ||
	    (inst->config->read_profiles && (do_fall_through == FALL_THROUGH_DEFAULT))) {
		rlm_rcode_t ret;

		/*
		 *  Check for a default_profile or for a User-Profile.
		 */
		RDEBUG3("... falling-through to profile processing");
		user_profile = pairfind(request->config_items, PW_USER_PROFILE, 0, TAG_ANY);

		char const *profile = user_profile ?
				      user_profile->vp_strvalue :
				      inst->config->default_profile;

		if (!profile || !*profile) {
			goto release;
		}

		RDEBUG2("Checking profile %s", profile);

		if (sql_set_user(inst, request, profile) < 0) {
			REDEBUG("Error setting profile");
			rcode = RLM_MODULE_FAIL;
			goto error;
		}

		ret = rlm_sql_process_groups(inst, request, &handle, &do_fall_through);
		switch (ret) {
		/*
		 *	Nothing bad happened, continue...
		 */
		case RLM_MODULE_UPDATED:
			rcode = RLM_MODULE_UPDATED;
			/* FALL-THROUGH */
		case RLM_MODULE_OK:
			if (rcode != RLM_MODULE_UPDATED) {
				rcode = RLM_MODULE_OK;
			}
			/* FALL-THROUGH */
		case RLM_MODULE_NOOP:
			user_found = true;
			break;

		case RLM_MODULE_NOTFOUND:
			break;

		default:
			rcode = ret;
			goto release;
		}
	}

	/*
	 *	At this point the key (user) hasn't be found in the check table, the reply table
	 *	or the group mapping table, and there was no matching profile.
	 */
release:
	if (!user_found) {
		rcode = RLM_MODULE_NOTFOUND;
	}

	sql_release_socket(inst, handle);
	sql_unset_user(inst, request);

	return rcode;

error:
	pairfree(&check_tmp);
	pairfree(&reply_tmp);
	sql_unset_user(inst, request);

	sql_release_socket(inst, handle);

	return rcode;
}
static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
{
	VALUE_PAIR *vp;
	rlm_sql_handle_t *sqlsock;
	struct in_addr nasip;      /* NAS IP */
	char const *sessid;     /* unique session id */
	char nasipstr[16];	 /* NAS IP in string format */
	uint32_t framedip = 0;     /* client's IP, host byte order */
	uint32_t acct_type;

	rlm_sqlhpwippool_t *inst = (rlm_sqlhpwippool_t *) instance;

	/* if no unique session ID, don't even try */
	vp = pairfind(request->packet->vps, PW_ACCT_UNIQUE_SESSION_ID, 0, TAG_ANY);
	if (vp) {
		sessid = vp->vp_strvalue;
	}
	else {
		nvp_log(__LINE__, inst, L_ERR,
			"mod_accounting(): unique session ID not found");
		return RLM_MODULE_FAIL;
	}

	vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY);
	if (vp) {
		acct_type = vp->vp_integer;
	}
	else {
		nvp_log(__LINE__, inst, L_ERR, "mod_accounting(): "
					       "couldn't find type of accounting packet");
		return RLM_MODULE_FAIL;
	}

	if (!(acct_type == PW_STATUS_START ||
	      acct_type == PW_STATUS_ALIVE ||
	      acct_type == PW_STATUS_STOP  ||
	      acct_type == PW_STATUS_ACCOUNTING_OFF ||
	      acct_type == PW_STATUS_ACCOUNTING_ON)) {
		return RLM_MODULE_NOOP;
	}

	/* connect to database */
	sqlsock = sql_get_socket(inst->sqlinst);
	if (!sqlsock) {
		nvp_log(__LINE__, inst, L_ERR,
			"mod_accounting(): couldn't connect to database");
		return RLM_MODULE_FAIL;
	}


	switch (acct_type) {
		case PW_STATUS_START:
		case PW_STATUS_ALIVE:
			vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS, 0, TAG_ANY);
			if (!vp) {
				nvp_log(__LINE__, inst, L_ERR, "mod_accounting(): no framed IP");
				sql_release_socket(inst->sqlinst, sqlsock);
				return RLM_MODULE_FAIL;
			}

			framedip = ntohl(vp->vp_ipaddr);

			if (!nvp_query(__LINE__, inst, sqlsock,
			    "UPDATE `%s`.`ips` "
			    	"SET "
			    		"`rsv_until` = 0, "
			    		"`rsv_by` = '%s' "
			    	"WHERE `ip` = %lu",
			    inst->db_name, sessid, framedip)) {
				sql_release_socket(inst->sqlinst, sqlsock);
				return RLM_MODULE_FAIL;
			}
			nvp_finish(inst, sqlsock);
			break;

		case PW_STATUS_STOP:
			if (!nvp_query(__LINE__, inst, sqlsock,
			    "UPDATE `%s`.`ips`, `%1$s`.`ip_pools` "
			    	"SET "
			    		"`ips`.`rsv_until` = NOW() + INTERVAL %u SECOND, "
			    		"`ip_pools`.`free` = `ip_pools`.`free` + 1 "
			    	"WHERE "
			    		"`ips`.`rsv_by` = '%s' AND "
			    		"`ips`.`ip` BETWEEN `ip_pools`.`ip_start` AND `ip_pools`.`ip_stop`",
			    inst->db_name, inst->free_after, sessid)) {
				sql_release_socket(inst->sqlinst, sqlsock);
				return RLM_MODULE_FAIL;
			}
			nvp_finish(inst, sqlsock);
		break;

		case PW_STATUS_ACCOUNTING_OFF:
		case PW_STATUS_ACCOUNTING_ON:
			vp = pairfind(request->packet->vps, PW_NAS_IP_ADDRESS, 0, TAG_ANY);
			if (!vp) {
				nvp_log(__LINE__, inst, L_ERR, "mod_accounting(): no NAS IP");
				sql_release_socket(inst->sqlinst, sqlsock);
				return RLM_MODULE_FAIL;
			}

			nasip.s_addr = vp->vp_ipaddr;
			strlcpy(nasipstr, inet_ntoa(nasip), sizeof(nasipstr));

			if (!nvp_query(__LINE__, inst, sqlsock,
			    "UPDATE `%s`.`ips`, `radacct` "
			    	"SET `ips`.`rsv_until` = NOW() + INTERVAL %u SECOND "
			    	"WHERE "
			    		"`radacct`.`nasipaddress` = '%s' AND "
			    		"`ips`.`rsv_by` = `radacct`.`acctuniqueid`",
			    inst->db_name, inst->free_after, nasipstr)) {
				sql_release_socket(inst->sqlinst, sqlsock);
				return RLM_MODULE_FAIL;
			}
			nvp_finish(inst, sqlsock);

			break;
	}

	sql_release_socket(inst->sqlinst, sqlsock);
	return RLM_MODULE_OK;
}
Esempio n. 21
0
static int sql_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check,
			VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
{
	SQLSOCK *sqlsocket;
	SQL_ROW row;
	SQL_INST *inst = instance;
	char querystr[MAX_QUERY_LEN];
	char sqlusername[MAX_STRING_LEN];

	check_pairs = check_pairs;
	reply_pairs = reply_pairs;

	DEBUG("rlm_sql (%s): - sql_groupcmp", inst->config->xlat_name);
	if (!check || !check->strvalue || !check->length){
		DEBUG("rlm_sql (%s): sql_groupcmp: Illegal group name",
		      inst->config->xlat_name);
		return 1;
	}
	if (req == NULL){
		DEBUG("rlm_sql (%s): sql_groupcmp: NULL request",
		      inst->config->xlat_name);
		return 1;
	}
	if (inst->config->groupmemb_query[0] == 0)
		return 1;
	/*
	 * Set, escape, and check the user attr here
	 */
	if (sql_set_user(inst, req, sqlusername, NULL) < 0)
		return 1;
	if (!radius_xlat(querystr, sizeof(querystr), inst->config->groupmemb_query, req, sql_escape_func)){
		radlog(L_ERR, "rlm_sql (%s): xlat failed.",
		       inst->config->xlat_name);
		/* Remove the username we (maybe) added above */
		pairdelete(&req->packet->vps, PW_SQL_USER_NAME);
		return 1;
	}
	/* Remove the username we (maybe) added above */
	pairdelete(&req->packet->vps, PW_SQL_USER_NAME);

	sqlsocket = sql_get_socket(inst);
	if (sqlsocket == NULL)
		return 1;
	if ((inst->module->sql_select_query)(sqlsocket,inst->config,querystr) <0){
		radlog(L_ERR, "rlm_sql (%s): database query error, %s: %s",
		       inst->config->xlat_name,querystr,
		       (char *)(inst->module->sql_error)(sqlsocket,inst->config));
		sql_release_socket(inst,sqlsocket);
		return 1;
	}
	while (rlm_sql_fetch_row(sqlsocket, inst) == 0) {
		row = sqlsocket->row;
		if (row == NULL)
			break;
		if (row[0] == NULL){
			DEBUG("rlm_sql (%s): row[0] returned NULL",
			      inst->config->xlat_name);
			(inst->module->sql_finish_select_query)(sqlsocket, inst->config);
			sql_release_socket(inst, sqlsocket);
			return 1;
		}
		if (strcmp(row[0],check->strvalue) == 0){
			DEBUG("rlm_sql (%s): - sql_groupcmp finished: User belongs in group %s",
			      inst->config->xlat_name,
			      (char *)check->strvalue);
			(inst->module->sql_finish_select_query)(sqlsocket, inst->config);			sql_release_socket(inst, sqlsocket);
			return 0;
		}
	}

	(inst->module->sql_finish_select_query)(sqlsocket, inst->config);
	sql_release_socket(inst,sqlsocket);

	DEBUG("rlm_sql (%s): - sql_groupcmp finished: User does not belong in group %s",
	      inst->config->xlat_name, (char *)check->strvalue);

	return 1;
}
Esempio n. 22
0
static rlm_rcode_t 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;
	int			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 || (inst->config->simul_count_query[0] == '\0')) {
		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) {
		return RLM_MODULE_FAIL;
	}

	/* initialize the sql socket */
	handle = sql_get_socket(inst);
	if (!handle) {
		talloc_free(expanded);
		return RLM_MODULE_FAIL;
	}

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

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

	row = handle->row;
	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 || (inst->config->simul_verify_query[0] == '\0')) {
		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)) {
		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(&handle, inst) == 0) {
		row = handle->row;
		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);
	sql_release_socket(inst, handle);
	talloc_free(expanded);

	/*
	 *	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;
}
Esempio n. 23
0
static int rlm_sql_authorize(void *instance, REQUEST * request)
{
	VALUE_PAIR *check_tmp = NULL;
	VALUE_PAIR *reply_tmp = NULL;
	VALUE_PAIR *user_profile = NULL;
	int     found = 0;
	SQLSOCK *sqlsocket;
	SQL_INST *inst = instance;
	char    querystr[MAX_QUERY_LEN];
	char	sqlusername[MAX_STRING_LEN];

	/*
	 *	They MUST have a user name to do SQL authorization.
	 */
	if ((request->username == NULL) ||
	    (request->username->length == 0)) {
		radlog(L_ERR, "rlm_sql (%s): zero length username not permitted\n", inst->config->xlat_name);
		return RLM_MODULE_INVALID;
	}

	/*
	 *	Set, escape, and check the user attr here.
	 */
	if (sql_set_user(inst, request, sqlusername, NULL) < 0)
		return RLM_MODULE_FAIL;
	radius_xlat(querystr, sizeof(querystr), inst->config->authorize_check_query, request, sql_escape_func);

	sqlsocket = sql_get_socket(inst);
	if (sqlsocket == NULL) {
		/* Remove the username we (maybe) added above */
		pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
		return RLM_MODULE_FAIL;
	}

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

	found = sql_getvpdata(inst, sqlsocket, &check_tmp, querystr, PW_VP_USERDATA);
	/*
	 *      Find the entry for the user.
	 */
	if (found > 0) {
		radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_check_query, request, sql_escape_func);
		sql_getvpdata(inst, sqlsocket, &check_tmp, querystr, PW_VP_GROUPDATA);
		radius_xlat(querystr, sizeof(querystr), inst->config->authorize_reply_query, request, sql_escape_func);
		sql_getvpdata(inst, sqlsocket, &reply_tmp, querystr, PW_VP_USERDATA);
		radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_reply_query, request, sql_escape_func);
		sql_getvpdata(inst, sqlsocket, &reply_tmp, querystr, PW_VP_GROUPDATA);
	} else if (found < 0) {
		radlog(L_ERR, "rlm_sql (%s): SQL query error; rejecting user",
		       inst->config->xlat_name);
		sql_release_socket(inst, sqlsocket);
		/* Remove the username we (maybe) added above */
		pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
		pairfree(&check_tmp);
		return RLM_MODULE_FAIL;

	} else {
		radlog(L_DBG, "rlm_sql (%s): User %s not found in radcheck",
		       inst->config->xlat_name, sqlusername);

                /*
		 * We didn't find the user in radcheck, so we try looking
		 * for radgroupcheck entry
		 */
                radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_check_query, request, sql_escape_func);
                found = sql_getvpdata(inst, sqlsocket, &check_tmp, querystr, PW_VP_GROUPDATA);
                radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_reply_query, request, sql_escape_func);
                sql_getvpdata(inst, sqlsocket, &reply_tmp, querystr, PW_VP_GROUPDATA);
        }
	if (!found)
		radlog(L_DBG, "rlm_sql (%s): User %s not found in radgroupcheck",
		       inst->config->xlat_name, sqlusername);
	if (found || (!found && inst->config->query_on_not_found)){
		int def_found = 0;

		/*
	 	* Check for a default_profile or for a User-Profile.
		*/
		user_profile = pairfind(request->config_items, PW_USER_PROFILE);
		if (inst->config->default_profile[0] != 0 || user_profile != NULL){
			char *profile = inst->config->default_profile;

			if (user_profile != NULL)
				profile = user_profile->strvalue;
			if (profile && strlen(profile)){
				radlog(L_DBG, "rlm_sql (%s): Checking profile %s",
				       inst->config->xlat_name, profile);
				if (sql_set_user(inst, request, sqlusername, profile) < 0) {
					sql_release_socket(inst, sqlsocket);
					pairfree(&reply_tmp);
					pairfree(&check_tmp);
					return RLM_MODULE_FAIL;
				}
				radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_check_query,
									request, sql_escape_func);
				def_found = sql_getvpdata(inst, sqlsocket, &check_tmp, querystr, PW_VP_GROUPDATA);
				if (def_found)
					found = 1;
				radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_reply_query,
									request, sql_escape_func);
				sql_getvpdata(inst, sqlsocket, &reply_tmp, querystr, PW_VP_GROUPDATA);
			}
		}
	}

	/*
	 *	We don't need the SQL socket anymore.
	 */
	sql_release_socket(inst, sqlsocket);

	if (!found) {
		radlog(L_DBG, "rlm_sql (%s): User not found",
		       inst->config->xlat_name);
		/* Remove the username we (maybe) added above */
		pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
		pairfree(&reply_tmp);
		pairfree(&check_tmp);
		return RLM_MODULE_NOTFOUND;
	}

	/*
	 * Uncomment these lines for debugging
	 * Recompile, and run 'radiusd -X'
	 */

	/*
	DEBUG2("rlm_sql:  check items");
	vp_listdebug(check_tmp);
	DEBUG2("rlm_sql:  reply items");
	vp_listdebug(reply_tmp);
	*/

	if (paircmp(request, request->packet->vps, check_tmp, &reply_tmp) != 0) {
		radlog(L_INFO, "rlm_sql (%s): No matching entry in the database for request from user [%s]",
		       inst->config->xlat_name, sqlusername);
		/* Remove the username we (maybe) added above */
		pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
		pairfree(&reply_tmp);
		pairfree(&check_tmp);
		return RLM_MODULE_NOTFOUND;
	}

	pairxlatmove(request, &request->reply->vps, &reply_tmp);
	pairxlatmove(request, &request->config_items, &check_tmp);
	pairfree(&reply_tmp);
	pairfree(&check_tmp);

	/* Remove the username we (maybe) added above */
	pairdelete(&request->packet->vps, PW_SQL_USER_NAME);

	return RLM_MODULE_OK;
}
Esempio n. 24
0
static int generate_sql_clients(rlm_sql_t *inst)
{
	rlm_sql_handle_t *handle;
	rlm_sql_row_t row;
	unsigned int i = 0;
	RADCLIENT *c;

	DEBUG("rlm_sql (%s): Processing generate_sql_clients",
	      inst->config->xlat_name);

	DEBUG("rlm_sql (%s) in generate_sql_clients: query is %s",
	      inst->config->xlat_name, inst->config->client_query);

	handle = sql_get_socket(inst);
	if (!handle) {
		return -1;
	}

	if (rlm_sql_select_query(&handle, inst, inst->config->client_query)){
		return -1;
	}

	while((rlm_sql_fetch_row(&handle, inst) == 0) && (row = handle->row)) {
		char *server = NULL;
		i++;

		/*
		 *  The return data for each row MUST be in the following order:
		 *
		 *  0. Row ID (currently unused)
		 *  1. Name (or IP address)
		 *  2. Shortname
		 *  3. Type
		 *  4. Secret
		 *  5. Virtual Server (optional)
		 */
		if (!row[0]){
			ERROR("rlm_sql (%s): No row id found on pass %d",inst->config->xlat_name,i);
			continue;
		}
		if (!row[1]){
			ERROR("rlm_sql (%s): No nasname found for row %s",inst->config->xlat_name,row[0]);
			continue;
		}
		if (!row[2]){
			ERROR("rlm_sql (%s): No short name found for row %s",inst->config->xlat_name,row[0]);
			continue;
		}
		if (!row[4]){
			ERROR("rlm_sql (%s): No secret found for row %s",inst->config->xlat_name,row[0]);
			continue;
		}

		if (((inst->module->sql_num_fields)(handle, inst->config) > 5) && (row[5] != NULL) && *row[5]) {
			server = row[5];
		}

		DEBUG("rlm_sql (%s): Adding client %s (%s) to %s clients list",
		      inst->config->xlat_name,
		      row[1], row[2], server ? server : "global");

		/* FIXME: We should really pass a proper ctx */
		c = client_from_query(NULL,
				      row[1],	/* identifier */
				      row[4],	/* secret */
				      row[2],	/* shortname */
				      row[3],	/* type */
				      server,	/* server */
				      false);	/* require message authenticator */
		if (!c) {
			continue;
		}

		if (!client_add(NULL, c)) {
			WARN("Failed to add client, possible duplicate?");

			client_free(c);
			continue;
		}

		DEBUG("rlm_sql (%s): Client \"%s\" (%s) added", c->longname, c->shortname,
		      inst->config->xlat_name);
	}

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

	return 0;
}
Esempio n. 25
0
/*
 *	Accounting: save the account data to our sql table
 */
static int rlm_sql_accounting(void *instance, REQUEST * request) {

	SQLSOCK *sqlsocket = NULL;
	VALUE_PAIR *pair;
	SQL_INST *inst = instance;
	int	ret = RLM_MODULE_OK;
	int     numaffected = 0;
	int     acctstatustype = 0;
	char    querystr[MAX_QUERY_LEN];
	char    logstr[MAX_QUERY_LEN];
	char	sqlusername[MAX_STRING_LEN];

#ifdef CISCO_ACCOUNTING_HACK
	int     acctsessiontime = 0;
#endif

	memset(querystr, 0, MAX_QUERY_LEN);

	/*
	 * Find the Acct Status Type
	 */
	if ((pair = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE)) != NULL) {
		acctstatustype = pair->lvalue;
	} else {
		radius_xlat(logstr, sizeof(logstr), "packet has no accounting status type. [user '%{User-Name}', nas '%{NAS-IP-Address}']", request, NULL);
		radlog(L_ERR, "rlm_sql (%s) in sql_accounting: %s",
		       inst->config->xlat_name, 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:
		case PW_STATUS_ACCOUNTING_OFF:
			radlog(L_INFO, "rlm_sql (%s): received Acct On/Off packet", inst->config->xlat_name);
			radius_xlat(querystr, sizeof(querystr), inst->config->accounting_onoff_query, request, sql_escape_func);
			query_log(request, inst, querystr);

			sqlsocket = sql_get_socket(inst);
			if (sqlsocket == NULL)
				return(RLM_MODULE_FAIL);
			if (*querystr) { /* non-empty query */
				if (rlm_sql_query(sqlsocket, inst, querystr)) {
					radlog(L_ERR, "rlm_sql (%s): Couldn't update SQL accounting for Acct On/Off packet - %s",
					       inst->config->xlat_name,
					       (char *)(inst->module->sql_error)(sqlsocket, inst->config));
					ret = RLM_MODULE_FAIL;
				}
				(inst->module->sql_finish_query)(sqlsocket, inst->config);
			}

			break;

			/*
			 * Got an update accounting packet
			 */
		case PW_STATUS_ALIVE:

			/*
			 * Set, escape, and check the user attr here
			 */
			sql_set_user(inst, request, sqlusername, NULL);

			radius_xlat(querystr, sizeof(querystr), inst->config->accounting_update_query, request, sql_escape_func);
			query_log(request, inst, querystr);

			sqlsocket = sql_get_socket(inst);
			if (sqlsocket == NULL)
				return(RLM_MODULE_FAIL);
			if (*querystr) { /* non-empty query */
				if (rlm_sql_query(sqlsocket, inst, querystr)) {
					radlog(L_ERR, "rlm_sql (%s): Couldn't update SQL accounting ALIVE record - %s",
					       inst->config->xlat_name,
					       (char *)(inst->module->sql_error)(sqlsocket, inst->config));
					ret = RLM_MODULE_FAIL;
				}
				else {
					numaffected = (inst->module->sql_affected_rows)(sqlsocket, inst->config);
					if (numaffected < 1) {

						/*
						 * If our update above didn't match anything
						 * we assume it's because we haven't seen a
						 * matching Start record.  So we have to
						 * insert this update rather than do an update
						 */
						radius_xlat(querystr, sizeof(querystr), inst->config->accounting_update_query_alt, request, sql_escape_func);
						query_log(request, inst, querystr);
						if (*querystr) { /* non-empty query */
							if (rlm_sql_query(sqlsocket, inst, querystr)) {
								radlog(L_ERR, "rlm_sql (%s): Couldn't insert SQL accounting ALIVE record - %s",
									   inst->config->xlat_name,
									   (char *)(inst->module->sql_error)(sqlsocket, inst->config));
								ret = RLM_MODULE_FAIL;
							}
							(inst->module->sql_finish_query)(sqlsocket, inst->config);
						}
					}
				}
				(inst->module->sql_finish_query)(sqlsocket, inst->config);
			}
			break;

			/*
			 * Got accounting start packet
			 */
		case PW_STATUS_START:

			/*
			 * Set, escape, and check the user attr here
			 */
			sql_set_user(inst, request, sqlusername, NULL);

			radius_xlat(querystr, sizeof(querystr), inst->config->accounting_start_query, request, sql_escape_func);
			query_log(request, inst, querystr);

			sqlsocket = sql_get_socket(inst);
			if (sqlsocket == NULL)
				return(RLM_MODULE_FAIL);
			if (*querystr) { /* non-empty query */
				if (rlm_sql_query(sqlsocket, inst, querystr)) {
					radlog(L_ERR, "rlm_sql (%s): Couldn't insert SQL accounting START record - %s",
					       inst->config->xlat_name,
					       (char *)(inst->module->sql_error)(sqlsocket, inst->config));

					/*
					 * We failed the insert above.  It's probably because
					 * the stop record came before the start.  We try
					 * our alternate query now (typically an UPDATE)
					 */
					radius_xlat(querystr, sizeof(querystr), inst->config->accounting_start_query_alt, request, sql_escape_func);
					query_log(request, inst, querystr);

					if (*querystr) { /* non-empty query */
						if (rlm_sql_query(sqlsocket, inst, querystr)) {
							radlog(L_ERR, "rlm_sql (%s): Couldn't update SQL accounting START record - %s",
							       inst->config->xlat_name,
							       (char *)(inst->module->sql_error)(sqlsocket, inst->config));
							ret = RLM_MODULE_FAIL;
						}
						(inst->module->sql_finish_query)(sqlsocket, inst->config);
					}
				}
				(inst->module->sql_finish_query)(sqlsocket, inst->config);
			}
			break;

			/*
			 * Got accounting stop packet
			 */
		case PW_STATUS_STOP:

			/*
			 * Set, escape, and check the user attr here
			 */
			sql_set_user(inst, request, sqlusername, NULL);

			radius_xlat(querystr, sizeof(querystr), inst->config->accounting_stop_query, request, sql_escape_func);
			query_log(request, inst, querystr);

			sqlsocket = sql_get_socket(inst);
			if (sqlsocket == NULL)
				return(RLM_MODULE_FAIL);
			if (*querystr) { /* non-empty query */
				if (rlm_sql_query(sqlsocket, inst, querystr)) {
					radlog(L_ERR, "rlm_sql (%s): Couldn't update SQL accounting STOP record - %s",
					       inst->config->xlat_name,
					       (char *)(inst->module->sql_error)(sqlsocket, inst->config));
					ret = RLM_MODULE_FAIL;
				}
				else {
					numaffected = (inst->module->sql_affected_rows)(sqlsocket, inst->config);
					if (numaffected < 1) {
						/*
						 * If our update above didn't match anything
						 * we assume it's because we haven't seen a
						 * matching Start record.  So we have to
						 * insert this stop rather than do an update
						 */
#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
					         */
					        if ((pair = pairfind(request->packet->vps, PW_ACCT_SESSION_TIME)) != NULL)
					                acctsessiontime = pair->lvalue;

						if (acctsessiontime <= 0) {
							radius_xlat(logstr, sizeof(logstr), "stop packet with zero session length. [user '%{User-Name}', nas '%{NAS-IP-Address}']", request, NULL);
							radlog(L_ERR, "rlm_sql (%s) in sql_accounting: %s", inst->config->xlat_name, logstr);
							sql_release_socket(inst, sqlsocket);
							ret = RLM_MODULE_NOOP;
						}
#endif

						radius_xlat(querystr, sizeof(querystr), inst->config->accounting_stop_query_alt, request, sql_escape_func);
						query_log(request, inst, querystr);

						if (*querystr) { /* non-empty query */
							if (rlm_sql_query(sqlsocket, inst, querystr)) {
								radlog(L_ERR, "rlm_sql (%s): Couldn't insert SQL accounting STOP record - %s",
										inst->config->xlat_name,
										(char *)(inst->module->sql_error)(sqlsocket, inst->config));
								ret = RLM_MODULE_FAIL;
							}
							(inst->module->sql_finish_query)(sqlsocket, inst->config);
						}
					}
				}
				(inst->module->sql_finish_query)(sqlsocket, inst->config);
			}
			break;

			/*
			 *	Anything else is ignored.
			 */
		default:
			radlog(L_INFO, "rlm_sql (%s): Unsupported Acct-Status-Type = %d", inst->config->xlat_name, acctstatustype);
			return RLM_MODULE_NOOP;
			break;

	}

	sql_release_socket(inst, sqlsocket);

	return ret;
}
Esempio n. 26
0
static rlm_rcode_t mod_authorize(void *instance, REQUEST * request)
{
	rlm_rcode_t rcode = RLM_MODULE_NOOP;

	rlm_sql_t *inst = instance;
	rlm_sql_handle_t  *handle;

	VALUE_PAIR *check_tmp = NULL;
	VALUE_PAIR *reply_tmp = NULL;
	VALUE_PAIR *user_profile = NULL;

	bool	user_found = false;
	bool	dofallthrough = true;
	int	rows;

	char	*expanded = NULL;

	rad_assert(request != NULL);
	rad_assert(request->packet != NULL);
	rad_assert(request->reply != NULL);

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

	/*
	 *	Reserve a socket
	 *
	 *	After this point use goto error or goto release to cleanup socket temporary pairlists and
	 *	temporary attributes.
	 */
	handle = sql_get_socket(inst);
	if (!handle) {
		rcode = RLM_MODULE_FAIL;
		goto error;
	}

	/*
	 *	Query the check table to find any conditions associated with this user/realm/whatever...
	 */
	if (inst->config->authorize_check_query && (inst->config->authorize_check_query[0] != '\0')) {
		if (radius_axlat(&expanded, request, inst->config->authorize_check_query,
				 sql_escape_func, inst) < 0) {
			REDEBUG("Error generating query");
			rcode = RLM_MODULE_FAIL;
			goto error;
		}

		rows = sql_getvpdata(inst, &handle, request, &check_tmp, expanded);
		TALLOC_FREE(expanded);
		if (rows < 0) {
			REDEBUG("SQL query error");
			rcode = RLM_MODULE_FAIL;
			goto error;
		}

		if (rows == 0) {
			goto skipreply;
		}

		/*
		 *	Only do this if *some* check pairs were returned
		 */
		RDEBUG2("User found in radcheck table");
		user_found = true;
		if (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) != 0) {
			goto skipreply;
		}

		RDEBUG2("Check items matched");
		radius_pairmove(request, &request->config_items, check_tmp, true);
		rcode = RLM_MODULE_OK;
	}

	if (inst->config->authorize_reply_query && (inst->config->authorize_reply_query[0] != '\0')) {
		/*
		 *	Now get the reply pairs since the paircompare matched
		 */
		if (radius_axlat(&expanded, request, inst->config->authorize_reply_query,
				sql_escape_func, inst) < 0) {
			REDEBUG("Error generating query");
			rcode = RLM_MODULE_FAIL;
			goto error;
		}

		rows = sql_getvpdata(inst, &handle, request->reply, &reply_tmp, expanded);
		TALLOC_FREE(expanded);
		if (rows < 0) {
			REDEBUG("SQL query error");
			rcode = RLM_MODULE_FAIL;
			goto error;
		}

		if (rows == 0) {
			goto skipreply;
		}

		if (!inst->config->read_groups) {
			dofallthrough = fallthrough(reply_tmp);
		}

		RDEBUG2("User found in radreply table");
		user_found = true;
		radius_pairmove(request, &request->reply->vps, reply_tmp, true);
		rcode = RLM_MODULE_OK;
	}

	skipreply:

	/*
	 *	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.
	 */
	if (dofallthrough) {
		rlm_rcode_t ret;

		RDEBUG3("... falling-through to group processing");
		ret = rlm_sql_process_groups(inst, request, handle, &dofallthrough);
		switch (ret) {
			/*
			 *	Nothing bad happened, continue...
			 */
			case RLM_MODULE_UPDATED:
				rcode = RLM_MODULE_UPDATED;
				/* FALL-THROUGH */
			case RLM_MODULE_OK:
				if (rcode != RLM_MODULE_UPDATED) {
					rcode = RLM_MODULE_OK;
				}
				/* FALL-THROUGH */
			case RLM_MODULE_NOOP:
				user_found = true;
				break;

			case RLM_MODULE_NOTFOUND:
				break;

			default:
				rcode = ret;
				goto release;
		}
	}

	/*
	 *	Repeat the above process with the default profile or User-Profile
	 */
	if (dofallthrough) {
		rlm_rcode_t ret;

		/*
		 *  Check for a default_profile or for a User-Profile.
		 */
		RDEBUG3("... falling-through to profile processing");
		user_profile = pairfind(request->config_items, PW_USER_PROFILE, 0, TAG_ANY);

		char const *profile = user_profile ?
				      user_profile->vp_strvalue :
				      inst->config->default_profile;

		if (!profile || !*profile) {
			goto release;
		}

		RDEBUG2("Checking profile %s", profile);

		if (sql_set_user(inst, request, profile) < 0) {
			REDEBUG("Error setting profile");
			rcode = RLM_MODULE_FAIL;
			goto error;
		}

		ret = rlm_sql_process_groups(inst, request, handle, &dofallthrough);
		switch (ret) {
			/*
			 *	Nothing bad happened, continue...
			 */
			case RLM_MODULE_UPDATED:
				rcode = RLM_MODULE_UPDATED;
				/* FALL-THROUGH */
			case RLM_MODULE_OK:
				if (rcode != RLM_MODULE_UPDATED) {
					rcode = RLM_MODULE_OK;
				}
				/* FALL-THROUGH */
			case RLM_MODULE_NOOP:
				user_found = true;
				break;

			case RLM_MODULE_NOTFOUND:
				break;

			default:
				rcode = ret;
				goto release;
		}
	}

	/*
	 *	At this point the key (user) hasn't be found in the check table, the reply table
	 *	or the group mapping table, and there was no matching profile.
	 */
	release:
	if (!user_found) {
		rcode = RLM_MODULE_NOTFOUND;
	}

	error:
	sql_release_socket(inst, handle);

	pairfree(&check_tmp);
	pairfree(&reply_tmp);

	return rcode;
}
Esempio n. 27
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)
{
	int	ret = RLM_MODULE_OK;

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

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

	char	path[MAX_STRING_LEN];
	char	querystr[MAX_QUERY_LEN];
	
	char	*p = path;

	rad_assert(section);
	
	if (section->reference[0] != '.')
		*p++ = '.';
	
	if (!radius_xlat(p, (sizeof(path) - (p - path)) - 1,
			section->reference, request, NULL, NULL))
		return RLM_MODULE_FAIL;

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

	if (cf_item_is_section(item)){
		radlog(L_ERR, "Sections are not supported as references");
		
		return RLM_MODULE_FAIL;
	}
	
	pair = cf_itemtopair(item);
	attr = cf_pair_attr(pair);
	
	RDEBUG2("Using query template '%s'", attr);
	
	handle = sql_get_socket(inst);
	if (handle == NULL)
		return RLM_MODULE_FAIL;
		
	sql_set_user(inst, request, NULL);

	while (TRUE) {
		value = cf_pair_value(pair);
		if (!value) {
			RDEBUG("Ignoring null query");
			ret = RLM_MODULE_NOOP;
			
			goto release;
		}
		
		radius_xlat(querystr, sizeof(querystr), value, request,
			    sql_escape_func, inst);
		if (!*querystr) {
			RDEBUG("Ignoring null query");
			ret = RLM_MODULE_NOOP;
			
			goto release;
		}
		
		rlm_sql_query_log(inst, request, section, querystr);
		
		/*
		 *  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 SQL_DOWN it means all connections in the pool
		 *  were exhausted, and we couldn't create a new connection,
		 *  so we do not need to call sql_release_socket.
		 */
		sql_ret = rlm_sql_query(&handle, inst, querystr);	
		if (sql_ret == SQL_DOWN)
			return RLM_MODULE_FAIL;
		
		rad_assert(handle);
	
		/* 
		 *  Assume all other errors are incidental, and just meant our
		 *  operation failed and its not a client or SQL syntax error.
		 */
		if (sql_ret == 0) {
			numaffected = (inst->module->sql_affected_rows)
					(handle, inst->config);
			if (numaffected > 0)
				break;
				
			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");
			
			ret = RLM_MODULE_NOOP;
			
			goto release;
		}

		RDEBUG("Trying next query...");
	}
	
	(inst->module->sql_finish_query)(handle, inst->config);

	release:
	sql_release_socket(inst, handle);

	return ret;
}