static void read_one(ddns_alias_t *alias, int nonslookup) { FILE *fp; char path[256]; alias->last_update = 0; memset(alias->address, 0, sizeof(alias->address)); cache_file(alias->name, path, sizeof(path)); fp = fopen(path, "r"); if (!fp) { if (nonslookup) return; /* Try a DNS lookup of our last known IP#. */ nslookup(alias); } else { struct stat st; char address[MAX_ADDRESS_LEN]; if (fgets(address, sizeof(address), fp)) { logit(LOG_INFO, "Cached IP# %s from previous invocation.", address); strncpy(alias->address, address, sizeof(alias->address)); } /* Initialize time since last update from modification time of cache file. */ if (!fstat(fileno(fp), &st)) { alias->last_update = st.st_mtime; logit(LOG_INFO, "Last update of %s on %s", alias->name, ctime(&st.st_mtime)); } fclose(fp); } }
void network_peer_cache::flush() { std::ofstream cache_file("peer_cache"); for (std::vector<ip::tcp::endpoint>::iterator it = peers_.begin(); it != peers_.end(); ++it) cache_file << it->address().to_string() << ':' << it->port(); }
FIMULTIBITMAP * DLL_CALLCONV FreeImage_OpenMultiBitmapFromHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_handle handle, int flags) { try { BOOL read_only = FALSE; // modifications (if any) will be stored into the memory cache if (io && handle) { // retrieve the plugin list to find the node belonging to this plugin PluginList *list = FreeImage_GetPluginList(); if (list) { PluginNode *node = list->FindNodeFromFIF(fif); if (node) { std::auto_ptr<FIMULTIBITMAP> bitmap (new FIMULTIBITMAP); std::auto_ptr<MULTIBITMAPHEADER> header (new MULTIBITMAPHEADER); std::auto_ptr<FreeImageIO> tmp_io (new FreeImageIO (*io)); header->io = tmp_io.get(); header->m_filename = NULL; header->node = node; header->fif = fif; header->handle = handle; header->changed = FALSE; header->read_only = read_only; header->m_cachefile = NULL; header->cache_fif = fif; header->load_flags = flags; // store the MULTIBITMAPHEADER in the surrounding FIMULTIBITMAP structure bitmap->data = header.get(); // cache the page count header->page_count = FreeImage_InternalGetPageCount(bitmap.get()); // allocate a continueus block to describe the bitmap header->m_blocks.push_back((BlockTypeS *)new BlockContinueus(0, header->page_count - 1)); if (!read_only) { // set up the cache std::auto_ptr<CacheFile> cache_file (new CacheFile("", TRUE)); if (cache_file->open()) { header->m_cachefile = cache_file.release(); } } tmp_io.release(); header.release(); return bitmap.release(); } } } } catch (std::bad_alloc &) { /** @todo report error */ } return NULL; }
CPLErr GDALWMSCache::Write(const char *key, const CPLString &file_name) { CPLString cache_file(KeyToCacheFile(key)); // printf("GDALWMSCache::Write(%s, %s) -> %s\n", key, file_name.c_str()); if (CPLCopyFile(cache_file.c_str(), file_name.c_str()) != CE_None) { MakeDirs(cache_file.c_str()); CPLCopyFile(cache_file.c_str(), file_name.c_str()); } return CE_None; }
CPLString GDALWMSCache::KeyToCacheFile(const char *key) { CPLString hash(MD5String(key)); CPLString cache_file(m_cache_path); if (cache_file.size() && (cache_file[cache_file.size() - 1] != '/')) cache_file.append(1, '/'); for (int i = 0; i < m_cache_depth; ++i) { cache_file.append(1, hash[i]); cache_file.append(1, '/'); } cache_file.append(hash); cache_file.append(m_postfix); return cache_file; }
CPLErr GDALWMSCache::Read(const char *key, CPLString *file_name) { CPLErr ret = CE_Failure; CPLString cache_file(KeyToCacheFile(key)); VSILFILE* fp = VSIFOpenL(cache_file.c_str(), "rb"); if (fp != NULL) { VSIFCloseL(fp); *file_name = cache_file; ret = CE_None; } // printf("GDALWMSCache::Read(...) -> %s\n", cache_file.c_str()); return ret; }
/* Update cache with new IP * /var/run/inadyn/my.server.name.cache { LAST-IPADDR } MTIME */ int write_cache_file(ddns_alias_t *alias) { FILE *fp; char path[256]; cache_file(alias->name, path, sizeof(path)); fp = fopen(path, "w"); if (fp) { fprintf(fp, "%s", alias->address); fclose(fp); return 0; } return 1; }
static void io_loop(void) { time_t delay; while (ServerRunning) { /* Run pending events, then get the number of seconds to the next * event */ delay = eventNextTime(); if(delay <= CurrentTime) eventRun(); comm_select(250); /* * Check to see whether we have to rehash the configuration .. */ if(dorehash) { rehash(1); dorehash = 0; } if(dorehashbans) { rehash_bans(1); dorehashbans = 0; } if(doremotd) { sendto_realops_flags(UMODE_ALL, L_ALL, "Got signal SIGUSR1, reloading ircd motd file"); free_cachefile(user_motd); user_motd = cache_file(MPATH, "ircd.motd", 0); doremotd = 0; } } }
/* Create pid and cache file repository, make sure we can write to it. If * we are restarted we cannot otherwise make sure we've not already updated * the IP -- and the user will be locked-out of their DDNS server provider * for excessive updates. */ int os_check_perms(void *UNUSED(arg)) { char path[256]; /* Create files with permissions 0644 */ umask(S_IWGRP | S_IWOTH); cache_file("example.com", path, sizeof(path)); if (mkparentdir(path)) { logit(LOG_ERR, "No write permission to %s, aborting.", path); logit(LOG_ERR, "Cannot guarantee DDNS server won't lock you out for excessive updates."); return RC_FILE_IO_ACCESS_ERROR; } /* Not creating a pidfile is OK, the cache file is the critical point. */ pidfile(pidfile_path); return 0; }
network_peer_cache::network_peer_cache() : getp_(0) { std::ifstream cache_file("peer_cache"); while (cache_file && !cache_file.eof()) { std::string ip; cache_file >> ip; std::string::size_type separator = ip.find(':'); if (separator == std::string::npos) continue; boost::asio::ip::address_v4 address = boost::asio::ip::address_v4::from_string(ip.substr(0, separator)); DLOG(INFO) << "Loading cached peer: " << address.to_string() << ':' << ip.substr(separator + 1); peers_.push_back( ip::tcp::endpoint( address, boost::lexical_cast<unsigned short>( ip.substr(separator + 1) ) ) ); } }
int main(int argc, char *argv[]) { int i; int key; char *name; time_t start; size_t total=0; pid_t pid; start=time(NULL); if (getenv("DEBUG_CACHER")!=NULL) debug=1; if (argc==1){ status(); return 0; } if (argv[1][0]=='-'){ cleanup(); return 0; } signal(2,cleanup); signal(15,cleanup); for (key=SHM_KEY,i=1;i<argc;i++,key++){ total+=cache_file(argv[i],key); } if (debug) fprintf(stderr,"Total: %ld bytes in %ld seconds (%7.2f MB/s)\n",total,time(NULL)-start,(double)total/(double)(1024.0*1024.0*(time(NULL)-start))); if (pid=fork()){ //parent if (debug) fprintf(stderr,"Forking\n"); return 0; } else{ while(1){ sleep(60); } } }
FIMULTIBITMAP * DLL_CALLCONV FreeImage_OpenMultiBitmap(FREE_IMAGE_FORMAT fif, const char *filename, BOOL create_new, BOOL read_only, BOOL keep_cache_in_memory, int flags) { FILE *handle = NULL; try { // sanity check on the parameters if (create_new) { read_only = FALSE; } // retrieve the plugin list to find the node belonging to this plugin PluginList *list = FreeImage_GetPluginList(); if (list) { PluginNode *node = list->FindNodeFromFIF(fif); if (node) { std::auto_ptr<FreeImageIO> io (new FreeImageIO); SetDefaultIO(io.get()); if (!create_new) { handle = fopen(filename, "rb"); if (handle == NULL) { return NULL; } } std::auto_ptr<FIMULTIBITMAP> bitmap (new FIMULTIBITMAP); std::auto_ptr<MULTIBITMAPHEADER> header (new MULTIBITMAPHEADER); header->m_filename = new char[strlen(filename) + 1]; strcpy(header->m_filename, filename); header->node = node; header->fif = fif; header->io = io.get (); header->handle = handle; header->changed = FALSE; header->read_only = read_only; header->m_cachefile = NULL; header->cache_fif = fif; header->load_flags = flags; // store the MULTIBITMAPHEADER in the surrounding FIMULTIBITMAP structure bitmap->data = header.get(); // cache the page count header->page_count = FreeImage_InternalGetPageCount(bitmap.get()); // allocate a continueus block to describe the bitmap if (!create_new) { header->m_blocks.push_back((BlockTypeS *)new BlockContinueus(0, header->page_count - 1)); } // set up the cache if (!read_only) { std::string cache_name; ReplaceExtension(cache_name, filename, "ficache"); std::auto_ptr<CacheFile> cache_file (new CacheFile(cache_name, keep_cache_in_memory)); if (cache_file->open()) { // we can use release() as std::bad_alloc won't be thrown from here on header->m_cachefile = cache_file.release(); } else { // an error occured ... fclose(handle); return NULL; } } // return the multibitmap // std::bad_alloc won't be thrown from here on header.release(); // now owned by bitmap io.release(); // now owned by bitmap return bitmap.release(); // now owned by caller } } } catch (std::bad_alloc &) { /** @todo report error */ } if (handle) fclose(handle); return NULL; }
int _rfs_open(struct rfs_instance *instance, const char *path, int flags, uint64_t *desc) { if (instance->sendrecv.socket == -1) { return -ECONNABORTED; } unsigned path_len = strlen(path) + 1; uint16_t fi_flags = rfs_file_flags(flags); unsigned overall_size = sizeof(fi_flags) + path_len; struct rfs_command cmd = { cmd_open, overall_size }; char *buffer = malloc(cmd.data_len); pack(path, path_len, pack_16(&fi_flags, buffer )); send_token_t token = { 0 }; if (do_send(&instance->sendrecv, queue_data(buffer, overall_size, queue_cmd(&cmd, &token))) < 0) { free(buffer); return -ECONNABORTED; } free(buffer); struct rfs_answer ans = { 0 }; if (rfs_receive_answer(&instance->sendrecv, &ans) == -1) { return -ECONNABORTED; } if (ans.command != cmd_open) { return cleanup_badmsg(instance, &ans); } if (ans.ret == -1) { if (ans.ret_errno == -ENOENT) { delete_from_cache(&instance->attr_cache, path); } return -ans.ret_errno; } uint32_t stat_failed = 0; uint32_t user_len = 0; uint32_t group_len = 0; #define ans_buffer_size sizeof(*desc) \ + sizeof(stat_failed) + STAT_BLOCK_SIZE + sizeof(user_len) + sizeof(group_len) \ + (MAX_SUPPORTED_NAME_LEN + 1) + (MAX_SUPPORTED_NAME_LEN + 1) char ans_buffer[ans_buffer_size] = { 0 }; if (ans.data_len > sizeof(ans_buffer)) { return cleanup_badmsg(instance, &ans); } #undef ans_buffer_size if (rfs_receive_data(&instance->sendrecv, ans_buffer, ans.data_len) == -1) { return -ECONNABORTED; } struct stat stbuf = { 0 }; const char *user = unpack_32(&group_len, unpack_32(&user_len, unpack_stat(&stbuf, unpack_32(&stat_failed, unpack_64(desc, ans_buffer ))))); const char *group = user + user_len; DEBUG("handle: %llu\n", (long long unsigned)(*desc)); stbuf.st_uid = resolve_username(instance, user); stbuf.st_gid = resolve_groupname(instance, group, user); if (ans.ret_errno == 0) { if (stat_failed == 0) { cache_file(&instance->attr_cache, path, &stbuf); } resume_add_file_to_open_list(&instance->resume.open_files, path, flags, *desc); } else { delete_from_cache(&instance->attr_cache, path); } return ans.ret == -1 ? -ans.ret_errno : ans.ret; }
bool http_cache::is_in_cache (const std::string& url) const { return fs::exists(cache_file(url)); }
void QMakeSourceFileInfo::loadCache(const QString &cf) { if(cf.isEmpty()) return; #ifdef QMAKE_USE_CACHE QMakeLocalFileName cache_file(cf); int fd = open(QMakeLocalFileName(cf).local().toLatin1(), O_RDONLY); if(fd == -1) return; QFileInfo cache_fi = findFileInfo(cache_file); if(!cache_fi.exists() || cache_fi.isDir()) return; QFile file; if(!file.open(QIODevice::ReadOnly, fd)) return; QTextStream stream(&file); if(stream.readLine() == qmake_version()) { //version check stream.skipWhiteSpace(); bool verified = true; { //cache verification QMap<QString, QStringList> verify; int len = stream.readLine().toInt(); for(int i = 0; i < len; ++i) { QString var = stream.readLine(); QString val = stream.readLine(); verify.insert(var, val.split(';', QString::SkipEmptyParts)); } verified = verifyCache(verify); } if(verified) { stream.skipWhiteSpace(); if(!files) files = new SourceFiles; while(!stream.atEnd()) { QString source = stream.readLine(); QString type = stream.readLine(); QString depends = stream.readLine(); QString mocable = stream.readLine(); stream.skipWhiteSpace(); QMakeLocalFileName fn(source); QFileInfo fi = findFileInfo(fn); SourceFile *file = files->lookupFile(fn); if(!file) { file = new SourceFile; file->file = fn; files->addFile(file); file->type = (SourceFileType)type.toInt(); file->exists = fi.exists(); } if(fi.exists() && fi.lastModified() < cache_fi.lastModified()) { if(!file->dep_checked) { //get depends if(!file->deps) file->deps = new SourceDependChildren; file->dep_checked = true; QStringList depend_list = depends.split(";", QString::SkipEmptyParts); for(int depend = 0; depend < depend_list.size(); ++depend) { QMakeLocalFileName dep_fn(depend_list.at(depend)); QFileInfo dep_fi(findFileInfo(dep_fn)); SourceFile *dep = files->lookupFile(dep_fn); if(!dep) { dep = new SourceFile; dep->file = dep_fn; dep->exists = dep_fi.exists(); dep->type = QMakeSourceFileInfo::TYPE_UNKNOWN; files->addFile(dep); } dep->included_count++; file->deps->addChild(dep); } } if(!file->moc_checked) { //get mocs file->moc_checked = true; file->mocable = mocable.toInt(); } } } } } #endif }
/* * 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; }