示例#1
0
url
resolve_tex (url name) {
  string s= as_string (name);
  if (is_cached ("font_cache.scm", s)) {
    url u= url_system (cache_get ("font_cache.scm", s) -> label);
    if (exists (u)) return u;
    cache_reset ("font_cache.scm", s);
  }

  bench_start ("resolve tex");
  url u= url_none ();
  if (ends (s, "mf" )) {
    u= resolve_tfm (name);
#ifdef OS_WIN32
    if (is_none (u))
      u= resolve_tfm (replace (s, ".mf", ".tfm"));
#endif
  }
  if (ends (s, "tfm")) u= resolve_tfm (name);
  if (ends (s, "pk" )) u= resolve_pk  (name);
  if (ends (s, "pfb")) u= resolve_pfb (name);
  bench_cumul ("resolve tex");

  if (!is_none (u)) cache_set ("font_cache.scm", s, as_string (u));
  //cout << "Resolve " << name << " -> " << u << "\n";
  return u;
}
示例#2
0
static int stream_cache_seek (stream_wrapper_t * wrapper, int64_t pos, int whence)
{
    int ret = 0;
    cache_ctx_t *ctx = (cache_ctx_t *)wrapper->stream_priv;
    stream_cache_t *cache = ctx->cache;
    stream_wrapper_t *real_st = ctx->wrapper;
    stream_ctrl_t *info = &wrapper->info;
    info->eof_flag = 0;
    dt_info(TAG,"Enter cache seek \n");
    // ret stream size
    if(whence == AVSEEK_SIZE)
    {
        dt_debug(TAG,"REQUEST STREAM SIZE:%lld \n",info->stream_size);
        return info->stream_size;
    }
    int step;
    int orig;
    if(whence == SEEK_SET)
    {
        step = abs(info->cur_pos - pos);
        orig = (info->cur_pos > pos)?0:1;
    }
    if(whence == SEEK_CUR)
    {
        step = abs(pos);
        orig = (pos < 0)?0:1;
    }

    if(cache_seek(cache,step,orig) == 0) // seek in cache
    {
        dt_info(TAG,"cache seek success \n");
    }
    else // seek through real stream ops
    {
        pause_cache_thread(ctx);
        ret =real_st->seek(real_st,pos,whence); // fixme: seek maybe failed for online video
        if(ret != DTERROR_NONE)
        {
            dt_error(TAG,"SEEK FAILED \n");
        }
        cache_reset(ctx->cache);
        resume_cache_thread(ctx);
    }

    info->eof_flag = 0;
    if(whence == SEEK_SET)
        info->cur_pos = pos;
    if(whence == SEEK_CUR)
        info->cur_pos += pos;

    return ret;
}
示例#3
0
static void bc_reset_handler(void) {
  cache_reset();
}
示例#4
0
文件: timer.c 项目: RhostMUSH/trunk
void NDECL(dispatch)
{
char	*cmdsave;

	cmdsave = mudstate.debug_cmd;
	mudstate.debug_cmd = (char *)"< dispatch >";

	/* this routine can be used to poll from interface.c */

	if (!mudstate.alarm_triggered) return;	
	mudstate.alarm_triggered = 0;
	mudstate.lastnowmsec = mudstate.nowmsec;
	mudstate.lastnow = mudstate.now;
	mudstate.nowmsec = time_ng(NULL);
	mudstate.now = (time_t) floor(mudstate.nowmsec);

	do_second();
	local_second();

	/* Free list reconstruction */

	if ((mudconf.control_flags & CF_DBCHECK) &&
	    (mudstate.check_counter <= mudstate.nowmsec)) {
		mudstate.check_counter = mudconf.check_interval + mudstate.nowmsec;
		mudstate.debug_cmd = (char *)"< dbck >";
		cache_reset(0);
		do_dbck (NOTHING, NOTHING, 0);
		cache_reset(0);
		pcache_trim();
	}

	/* Database dump routines */

	if ((mudconf.control_flags & CF_CHECKPOINT) &&
	    (mudstate.dump_counter <= mudstate.nowmsec)) {
		mudstate.dump_counter = mudconf.dump_interval + mudstate.nowmsec;
		mudstate.debug_cmd = (char *)"< dump >";
		fork_and_dump(0, (char *)NULL);
	}

	/* Idle user check */

	if ((mudconf.control_flags & CF_IDLECHECK) &&
	    (mudstate.idle_counter <= mudstate.nowmsec)) {
		mudstate.idle_counter = mudconf.idle_interval + mudstate.nowmsec;
		mudstate.debug_cmd = (char *)"< idlecheck >";
		cache_reset(0);
		check_idle();

	}

#ifdef HAVE_GETRUSAGE
	/* Memory use stats */

	if (mudstate.mstats_counter <= mudstate.nowmsec) {

		int	curr;

		mudstate.mstats_counter = 15 + mudstate.nowmsec;
		curr = mudstate.mstat_curr;
		if ( (curr >= 0 ) && (mudstate.now > mudstate.mstat_secs[curr]) ) {

			struct rusage	usage;

			curr = 1-curr;
			getrusage(RUSAGE_SELF, &usage);
			mudstate.mstat_ixrss[curr] = usage.ru_ixrss;
			mudstate.mstat_idrss[curr] = usage.ru_idrss;
			mudstate.mstat_isrss[curr] = usage.ru_isrss;
			mudstate.mstat_secs[curr] = mudstate.now;
			mudstate.mstat_curr = curr;
		}
	}
#endif

#ifdef RWHO_IN_USE
	if ((mudconf.control_flags & CF_RWHO_XMIT) &&
	    (mudstate.rwho_counter <= mudstate.nowmsec)) {
		mudstate.rwho_counter = mudconf.rwho_interval + mudstate.nowmsec;
		mudstate.debug_cmd = (char *)"< rwho update >";
		rwho_update();
	}
#endif

	/* reset alarm */

	alarm_msec (next_timer());
	mudstate.debug_cmd = cmdsave;
}
示例#5
0
文件: nuauthconf.c 项目: regit/nufw
/**
 * exit function if a signal is received in daemon mode.
 *
 * Argument: signal number
 * Return: None
 */
gboolean nuauth_reload(int signum)
{
	struct nuauth_params *newconf = NULL;
	gboolean restart;
	int retval;

	g_message("[+] Reload NuAuth server");
	nuauth_install_signals(FALSE);

	/* Reload the configuration file */
	retval = nuauth_parse_configuration(nuauthconf->configfile);
	if (retval != 0) {
		log_message(CRITICAL, DEBUG_AREA_MAIN,
			    "Cannot reload configuration (file '%s')",
			    nuauthconf->configfile);
		return -1;
	}

	init_nuauthconf(&newconf);
	g_message("nuauth module reloading");

	/* block threads of pool at start */
	block_thread_pools();
	/* we have to wait that all threads are blocked */
	wait_all_thread_pools();
	/* unload modules */
	unload_modules();

	/* Only duplicate configfile info, if configfile has not been set */
	if (! newconf->configfile) {
		newconf->configfile = g_strdup(nuauthconf->configfile);
	}

	/* switch conf before loading modules */
	restart = compare_nuauthparams(nuauthconf, newconf);

	if (restart == FALSE) {
		apply_new_config(newconf);
		/* debug is set via command line thus duplicate */
		newconf->debug_level = nuauthconf->debug_level;
		free_nuauth_params(nuauthconf);
		g_free(nuauthconf);
		nuauthconf = newconf;
	} else {
		free_nuauth_params(newconf);
	}

	/* reload modules with new conf */
	load_modules();
	/* init period */
	nuauthconf->periods = init_periods(nuauthconf);
	/* ask cache to reset */
	if (nuauthconf->acl_cache) {
		cache_reset(nuauthdatas->acl_cache);
	}

	release_thread_pools();
	nuauth_install_signals(TRUE);

	force_refresh_crl_file();

	g_message("[+] NuAuth server reloaded");
	return restart;
}
示例#6
0
文件: gadgets.c 项目: spnow/ropit
// find valid instructions offsets before ret
int _ropit_x86_find_gadgets (uint8_t *bytes, int len, int64_t *rets, int n_rets) {
    int sz_inst;                /* size of instruction */
    x86_insn_t insn;         /* instruction */
    int idx_ret, sz_ret;
    int valid_gadget;
    // back track instruction count
    int n_backtrack_inst, n_backtrack_bytes;
    // start for rop search
    uint8_t *start, *gadget_start;
    // disassemble
    int len_disasm;
    int sz_dst;
    char disassembled[DISASSEMBLED_SIZE_MAX] = {0};
    // cache
    FILE *fp_cache;
    struct cache_t *caches;
    int idx_caches, n_caches;
    struct gadget_t *gadgets;
    int idx_gadgets, n_gadgets;
    // cache queue
    struct gadget_cache_queue_t *cache_queue;
    // count
    int count_gadgets;

    // check params
    if (!bytes || len <= 0) {
        debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): Bytes null or len <= 0\n");
        return NULL;
    }

    // search rets
    if (!rets || n_rets <= 0) {
        debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): No rets\n");
        return NULL;
    }

    // init gadget_cache
    fp_cache = fopen("tmp/gadget_cache", "w");
    if (!fp_cache) {
        debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): Failed open (w)\n");
        return NULL;
    }

    // init cache_queue
    cache_queue = NULL;
    if (!gadget_cache_queue_init(&cache_queue)) {
        debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): Cache queue allocation failed\n");
        return NULL;
    }
    gadget_cache_queue_set_file (cache_queue, fp_cache);

    // init gadgets
    n_gadgets = 1024;
    gadgets = calloc(sizeof(struct gadget_t), n_gadgets);
    if (!gadgets) {
        debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): Failed allocating caches\n");
        return NULL;
    }

    for (idx_gadgets = 0; idx_gadgets < n_gadgets; idx_gadgets++)
        gadget_init(&(gadgets[idx_gadgets]), DISASSEMBLED_SIZE_MAX);

    // init caches
    n_caches = 1;
    caches = calloc(sizeof(struct cache_t), n_caches);
    if (!caches) {
        debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): Failed allocating caches\n");
        return NULL;
    }

    for (idx_caches = 0; idx_caches < n_caches; idx_caches++) {
        cache_init(&(caches[idx_caches]), 1024);
    }

    // init disasm
    x86_init(opt_none, NULL, NULL);

    idx_caches = 0;
    idx_gadgets = 0;
    count_gadgets = 0;
    for (idx_ret = 0; idx_ret < n_rets; idx_ret++) {
        start = bytes + rets[idx_ret];

        n_backtrack_inst = 0;
        n_backtrack_bytes = 0;
        while ( bytes <= start && start <= bytes + len ) {
            /* disassemble address */
            sz_inst = x86_disasm(start, len - (start - bytes), 0, 0, &insn);
            x86_oplist_free(&insn);

            if (sz_inst <= 0) {
                // printf("not found inst\n");
                n_backtrack_bytes++;
            }
            else {
                // printf("found inst\n");
                n_backtrack_bytes = 0;

                valid_gadget = 0;
                //
                gadget_start = start;
                if (gadget_start == bytes + rets[idx_ret])
                    valid_gadget = 1;
                else {
                    n_backtrack_inst = 0;
                    // check gadget validity
                    while (bytes <= gadget_start && gadget_start <= bytes + rets[idx_ret]) {
                        /* disassemble address */
                        sz_inst = x86_disasm(gadget_start, gadget_start - bytes, 0, 0, &insn);
                        x86_oplist_free(&insn);
                        if (sz_inst <= 0)
                            break;
                        else {
                            n_backtrack_inst++;
                            gadget_start += sz_inst;
                            if (gadget_start == bytes + rets[idx_ret]) {
                                valid_gadget = 1;
                                break;
                            }
                        }
                    }
                }

                if (valid_gadget == 1) {
                    //
                    ++count_gadgets;

                    // get ret size
                    sz_ret = x86_disasm(bytes + rets[idx_ret], 10, 0, 0, &insn);
                    x86_oplist_free(&insn);

                    // fill gadget structure
                    gadgets[idx_gadgets].ret_addr = rets[idx_ret];
                    gadgets[idx_gadgets].ret_bytes = rets[idx_ret] + bytes;
                    gadgets[idx_gadgets].address = start - bytes;
                    gadgets[idx_gadgets].len_bytes = (rets[idx_ret] - (start - bytes)) + sz_ret;
                    if (gadgets[idx_gadgets].sz_bytes < gadgets[idx_gadgets].len_bytes) {
                        gadgets[idx_gadgets].bytes = realloc (gadgets[idx_gadgets].bytes, gadgets[idx_gadgets].len_bytes);
                        gadgets[idx_gadgets].sz_bytes = gadgets[idx_gadgets].len_bytes;
                    }
                    memcpy(gadgets[idx_gadgets].bytes, start, gadgets[idx_gadgets].len_bytes);

                    if (cache_add (&(caches[idx_caches]), &(gadgets[idx_gadgets])) == -ERR_CACHE_FULL) {
                        gadget_cache_queue_add (cache_queue, &(caches[idx_caches]));
                        gadget_cache_queue_fwrite_worker (cache_queue);
                        cache_reset (&(caches[idx_caches]));
                    }

                    idx_gadgets = (idx_gadgets + 1) % n_gadgets;
                }
            }
            --start;

            // maximum intel instruction size is 15
            // maximum instructions in a gadget is hardcoded to 8 here
            /* TODO : Get more gadgets with n_backtrack_inst instructions
             * Effectively, we stop at the first gadget which has
             * n_backtrack_inst instructions while there might be multiple
             * possibilities.
             */
            if (n_backtrack_bytes >= 15 || n_backtrack_inst == 8)
                break;
        }
    }
    x86_cleanup();

    // write remaining gadgets
    gadget_cache_queue_add (cache_queue, &(caches[idx_caches]));
    gadget_cache_queue_fwrite_worker (cache_queue);
    cache_reset (&(caches[idx_caches]));

    // clean up
    for (idx_caches = 0; idx_caches < n_caches; idx_caches++)
        free(caches[idx_caches].objects);
    free(caches);

    for (idx_gadgets = 0; idx_gadgets < n_gadgets; idx_gadgets++) {
        // gadget_free(&(gadgets[idx_gadgets]));
        // free (gadgets[idx_gadgets].repr);
        free (gadgets[idx_gadgets].bytes);
    }
    free(gadgets);

    gadget_cache_queue_destroy (&cache_queue);

    fclose (fp_cache);

    return count_gadgets;
}
/*
 *	Store logins in the RADIUS utmp file.
 */
static rlm_rcode_t radutmp_accounting(void *instance, REQUEST *request)
{
	rlm_radutmp_t	*inst = instance;
	struct radutmp	utmp, u;
	VALUE_PAIR	*vp;
	int		status = -1;
	uint32_t	nas_address = 0;
	uint32_t	framed_address = 0;
	int		protocol = -1;
	int		fd;
	int		port_seen = 0;
	char		buffer[256];
	char		filename[1024];
	char		ip_name[32]; /* 255.255.255.255 */
	const char	*nas;
	NAS_PORT	*nas_port, myPort;
	radutmp_cache_t *cache;
	int		read_size;
	rbnode_t	*node;

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

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

		if ((vp = pairfind(request->packet->vps, PW_ACCT_SESSION_TIME, 0, TAG_ANY))
		     == NULL || vp->vp_date == 0)
			check1 = 1;
		if ((vp = pairfind(request->packet->vps, PW_ACCT_SESSION_ID, 0, TAG_ANY))
		     != NULL && vp->length == 8 &&
		     memcmp(vp->vp_strvalue, "00000000", 8) == 0)
			check2 = 1;
		if (check1 == 0 || check2 == 0) {
#if 0 /* Cisco sometimes sends START records without username. */
			radlog(L_ERR, "rlm_radutmp: no username in record");
			return RLM_MODULE_FAIL;
#else
			break;
#endif
		}
		radlog(L_INFO, "rlm_radutmp: converting reboot records.");
		if (status == PW_STATUS_STOP)
			status = PW_STATUS_ACCOUNTING_OFF;
		if (status == PW_STATUS_START)
			status = PW_STATUS_ACCOUNTING_ON;
	} while(0);

	memset(&utmp, 0, sizeof(utmp));
	utmp.porttype = 'A';

	/*
	 *	First, find the interesting attributes.
	 */
	for (vp = request->packet->vps; vp; vp = vp->next) {
		switch (vp->da->attribute) {
			case PW_LOGIN_IP_HOST:
			case PW_FRAMED_IP_ADDRESS:
				framed_address = vp->vp_ipaddr;
				utmp.framed_address = vp->vp_ipaddr;
				break;
			case PW_FRAMED_PROTOCOL:
				protocol = vp->vp_integer;
				break;
			case PW_NAS_IP_ADDRESS:
				nas_address = vp->vp_ipaddr;
				utmp.nas_address = vp->vp_ipaddr;
				break;
			case PW_NAS_PORT:
				utmp.nas_port = vp->vp_integer;
				port_seen = 1;
				break;
			case PW_ACCT_DELAY_TIME:
				utmp.delay = vp->vp_integer;
				break;
			case PW_ACCT_SESSION_ID:
				/*
				 *	If it's too big, only use the
				 *	last bit.
				 */
				if (vp->length > sizeof(utmp.session_id)) {
					int length = vp->length - sizeof(utmp.session_id);

					/*
					 * 	Ascend is br0ken - it
					 * 	adds a \0 to the end
					 * 	of any string.
					 * 	Compensate.
					 */
					if (vp->vp_strvalue[vp->length - 1] == 0) {
						length--;
					}

					memcpy(utmp.session_id,
					      vp->vp_strvalue + length,
					      sizeof(utmp.session_id));
				} else {
					memset(utmp.session_id, 0,
					       sizeof(utmp.session_id));
					memcpy(utmp.session_id,
					       vp->vp_strvalue,
					       vp->length);
				}
				break;
			case PW_NAS_PORT_TYPE:
				if (vp->vp_integer <= 4)
					utmp.porttype = porttypes[vp->vp_integer];
				break;
			case PW_CALLING_STATION_ID:
				if(inst->callerid_ok)
					strlcpy(utmp.caller_id,
						(char *)vp->vp_strvalue,
						sizeof(utmp.caller_id));
				break;
		}
	}

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

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

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


	/*
	 *	Set the protocol field.
	 */
	if (protocol == PW_PPP)
		utmp.proto = 'P';
	else if (protocol == PW_SLIP)
		utmp.proto = 'S';
	else
		utmp.proto = 'T';

	utmp.time = request->timestamp - utmp.delay;

	/*
	 *	Get the utmp filename, via xlat.
	 */
	radius_xlat(filename, sizeof(filename), inst->filename, request, NULL);

	/*
	 *	Future: look up filename in filename tree, to get
	 *	radutmp_cache_t pointer
	 */
	cache = &inst->cache;

	/*
	 *	For now, double-check the filename, to be sure it isn't
	 *	changing.
	 */
	if (!cache->filename) {
		cache->filename = strdup(filename);
		rad_assert(cache->filename != NULL);

	} else if (strcmp(cache->filename, filename) != 0) {
		radlog(L_ERR, "rlm_radutmp: We do not support dynamically named files.");
		return RLM_MODULE_FAIL;
	}

	/*
	 *	If the lookup failed, create a new one, and add it
	 *	to the filename tree, and cache the file, as below.
	 */

	/*
	 *	For aging, in the future.
	 */
	cache->last_used = request->timestamp;

	/*
	 *	If we haven't already read the file, then read the
	 *	entire file, in order to cache its entries.
	 */
	if (!cache->cached_file) {
		cache_file(inst, cache);
	}

	/*
	 *	See if this was a reboot.
	 *
	 *	Hmm... we may not want to zap all of the users when
	 *	the NAS comes up, because of issues with receiving
	 *	UDP packets out of order.
	 */
	if (status == PW_STATUS_ACCOUNTING_ON && nas_address) {
		radlog(L_INFO, "rlm_radutmp: NAS %s restarted (Accounting-On packet seen)",
		       nas);
		if (!radutmp_zap(inst, cache, nas_address, utmp.time)) {
			rad_assert(0 == 1);
		}
		return RLM_MODULE_OK;
	}

	if (status == PW_STATUS_ACCOUNTING_OFF && nas_address) {
		radlog(L_INFO, "rlm_radutmp: NAS %s rebooted (Accounting-Off packet seen)",
		       nas);
		if (!radutmp_zap(inst, cache, nas_address, utmp.time)) {
			rad_assert(0 == 1);
		}
		return RLM_MODULE_OK;
	}

	/*
	 *	If we don't know this type of entry, then pretend we
	 *	succeeded.
	 */
	if (status != PW_STATUS_START &&
	    status != PW_STATUS_STOP &&
	    status != PW_STATUS_ALIVE) {
		radlog(L_ERR, "rlm_radutmp: NAS %s port %u unknown packet type %d, ignoring it.",
		       nas, utmp.nas_port, status);
		return RLM_MODULE_NOOP;
	}

	/*
	 *	Perhaps we don't want to store this record into
	 *	radutmp. We skip records:
	 *
	 *	- without a NAS-Port (telnet / tcp access)
	 *	- with the username "!root" (console admin login)
	 */
	if (!port_seen) {
		DEBUG2("  rlm_radutmp: No NAS-Port in the packet.  Cannot do anything.");
		DEBUG2("  rlm_radumtp: WARNING: checkrad will probably not work!");
		return RLM_MODULE_NOOP;
	}

	/*
	 *	Translate the User-Name attribute, or whatever else
	 *	they told us to use.
	 */
	*buffer = '\0';
	radius_xlat(buffer, sizeof(buffer), inst->username, request, NULL);

	/*
	 *	Don't log certain things...
	 */
	if (strcmp(buffer, "!root") == 0) {
		DEBUG2("  rlm_radutmp: Not recording administrative user");

		return RLM_MODULE_NOOP;
	}
	strlcpy(utmp.login, buffer, RUT_NAMESIZE);

	/*
	 *	First, try to open the file.  If it doesn't exist,
	 *	nuke the existing caches, and try to create it.
	 *
	 *	FIXME: Create any intermediate directories, as
	 *	appropriate.  See rlm_detail.
	 */
	fd = open(cache->filename, O_RDWR, inst->permission);
	if (fd < 0) {
		if (errno == ENOENT) {
			DEBUG2("  rlm_radutmp: File %s doesn't exist, creating it.", cache->filename);
			if (!cache_reset(inst, cache)) return RLM_MODULE_FAIL;

			/*
			 *	Try to create the file.
			 */
			fd = open(cache->filename, O_RDWR | O_CREAT,
				  inst->permission);
		}
	} else {		/* exists, but may be empty */
		struct stat buf;

		/*
		 *	If the file is empty, reset the cache.
		 */
		if ((stat(cache->filename, &buf) == 0) &&
		    (buf.st_size == 0) &&
		    (!cache_reset(inst, cache))) {
			return RLM_MODULE_FAIL;
		}
		DEBUG2("  rlm_radutmp: File %s was truncated.  Resetting cache.",
		       cache->filename);
	}

	/*
	 *	Error from creation, or error other than ENOENT: die.
	 */
	if (fd < 0) {
		radlog(L_ERR, "rlm_radutmp: Error accessing file %s: %s",
		       cache->filename, strerror(errno));
		return RLM_MODULE_FAIL;
	}

	/*
	 *	OK.  Now that we've prepared everything we want to do,
	 *	let's see if we've cached the entry.
	 */
	myPort.nas_address = utmp.nas_address;
	myPort.nas_port = utmp.nas_port;

	pthread_mutex_lock(&cache->mutex);
	node = rbtree_find(cache->nas_ports, &myPort);
	pthread_mutex_unlock(&cache->mutex);

	if (node) {
		nas_port = rbtree_node2data(cache->nas_ports, node);
#if 0

		/*
		 *	stat the file, and get excited if it's been
		 *	truncated.
		 *
		 *	i.e wipe out the cache, and re-read the file.
		 */

		/*
		 *	Now find the new entry.
		 */
		pthread_mutex_lock(&cache->mutex);
		node = rbtree_find(cache->nas_ports, &myPort);
		pthread_mutex_unlock(&cache->mutex);
#endif
	}

	if (!node) {
		radutmp_simul_t *user;

		/*
		 *	Not found in the cache, and we're trying to
		 *	delete an existing record: ignore it.
		 */
		if (status == PW_STATUS_STOP) {
			DEBUG2("  rlm_radumtp: Logout entry for NAS %s port %u with no Login: ignoring it.",
			       nas, utmp.nas_port);
			return RLM_MODULE_NOOP;
		}

		pthread_mutex_lock(&cache->mutex);

		/*
		 *	It's a START or ALIVE.  Try to find a free
		 *	offset where we can store the new entry, or
		 *	create one, if one doesn't already exist.
		 */
		if (!cache->free_offsets) {
			cache->free_offsets = rad_malloc(sizeof(NAS_PORT));
			memset(cache->free_offsets, 0,
			       sizeof(*(cache->free_offsets)));
			cache->free_offsets->offset = cache->max_offset;
			cache->max_offset += sizeof(u);
		}

		/*
		 *	Grab the offset, and put it into the various
		 *	caches.
		 */
		nas_port = cache->free_offsets;
		cache->free_offsets = nas_port->next;

		nas_port->nas_address = nas_address;
		nas_port->nas_port = utmp.nas_port;

		if (!rbtree_insert(cache->nas_ports, nas_port)) {
			rad_assert(0 == 1);
		}

		/*
		 *	Allocate new entry, and add it
		 *	to the tree.
		 */
		user = rad_malloc(sizeof(user));
		strlcpy(user->login, utmp.login,
			sizeof(user->login));
		user->simul_count = 1;

		if (!rbtree_insert(inst->user_tree, user)) {
			rad_assert(0 == 1);
		}

		pthread_mutex_unlock(&cache->mutex);

	}

	/*
	 *	Entry was found, or newly created in the cache.
	 *	Seek to the place in the file.
	 */
	lseek(fd, nas_port->offset, SEEK_SET);

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

	/*
	 *	If it WAS found in the cache, double-check it against
	 *	what is in the file.
	 */
	if (node) {
		/*
		 *	If we didn't read anything, then this entry
		 *	doesn't exist.
		 *
		 *	Similarly, if the entry in the file doesn't
		 *	match what we recall, then nuke the cache
		 *	entry.
		 */
		read_size = read(fd, &u, sizeof(u));
		if ((read_size < 0) ||
		    ((read_size > 0) && (read_size  != sizeof(u)))) {
			/*
			 *	Bad read, or bad record.
			 */
			radlog(L_ERR, "rlm_radutmp: Badly formed file %s",
			       cache->filename);
			close(fd);
			return RLM_MODULE_FAIL;
		}

		rad_assert(read_size != 0);

		/*
		 *	We've read a record, go poke at it.
		 */
		if (read_size > 0) {
			/*
			 *	If these aren't true, then
			 *
			 *	a) we have cached a "logout" entry,
			 *	   which we don't do.
			 *
			 *	b) we have cached the wrong NAS address
			 *
			 *	c) we have cached the wrong NAS port.
			 */
			rad_assert(u.type == P_LOGIN);
			rad_assert(u.nas_address == utmp.nas_address);
			rad_assert(u.nas_port == utmp.nas_port);

			/*
			 *	An update for the same session.
			 */
			if (strncmp(utmp.session_id, u.session_id,
				    sizeof(u.session_id)) == 0) {

				/*
				 *	It's a duplicate start, so we
				 *	don't bother writing it.
				 */
				if (status == PW_STATUS_START) {
					DEBUG2("  rlm_radutmp: Login entry for NAS %s port %u duplicate, ignoring it.",
					       nas, u.nas_port);
					close(fd);
					return RLM_MODULE_OK;


				/*
				 *	ALIVE for this session, keep the
				 *	original login time.
				 */
				} else if (status == PW_STATUS_ALIVE) {
					utmp.time = u.time;

				/*
				 *	Stop: delete it from our cache.
				 */
				} else if (status == PW_STATUS_STOP) {
					radutmp_simul_t *user, myUser;

					pthread_mutex_lock(&cache->mutex);
					rbtree_deletebydata(cache->nas_ports,
							    nas_port);

					strlcpy(myUser.login,
						u.login, sizeof(myUser.login));
					user = rbtree_finddata(inst->user_tree,
							       &myUser);
					rad_assert(user != NULL);
					rad_assert(user->simul_count > 0);

					user->simul_count--;
					if (user->simul_count == 0) {
						rbtree_deletebydata(inst->user_tree, user);
					}

					pthread_mutex_unlock(&cache->mutex);

 				} else {
					/*
					 *	We don't know how to
					 *	handle this.
					 */
					rad_assert(0 == 1);
				}

			} else { /* session ID doesn't match */
				/*
				 *	STOP for the right NAS & port,
				 *	but the Acct-Session-Id is
				 *	different.  This means that
				 *	we missed the original "stop",
				 *	and a new "start".
				 */
				if (status == PW_STATUS_STOP) {
					radlog(L_ERR, "rlm_radutmp: Logout entry for NAS %s port %u has old Acct-Session-ID, ignoring it.",
					       nas, u.nas_port);
					close(fd);
					return RLM_MODULE_OK;
				}
			} /* checked session ID's */
		}  /* else we haven't read anything from the file. */
	} /* else the entry wasn't cached, but could have been inserted */

	/*
	 *	Hmm... we may have received a start or alive packet
	 *	AFTER a stop or nas-down, in that case, we want to
	 *	discard the new packet.  However, the original code
	 *	could over-write an idle record with a new login
	 *	record for another NAS && port, so we won't worry
	 *	about this case too much.
	 */

	/*
	 *	Seek to where the entry is, and write it blindly.
	 */
	lseek(fd, nas_port->offset, SEEK_SET); /* FIXME: err */

	if (status != PW_STATUS_STOP) {
		utmp.type = P_LOGIN;
		rad_assert(nas_port != NULL); /* it WAS cached */
	} else {
		/* FIXME: maybe assert that the entry was deleted... */
		memcpy(&utmp, &u, sizeof(utmp));
		utmp.type = P_IDLE;
	}

	write(fd, &utmp, sizeof(utmp)); /* FIXME: err */

	close(fd);	/* and implicitly release the locks */

	return RLM_MODULE_OK;
}