Initial revision

This commit is contained in:
hsn 2003-10-04 12:56:32 +00:00
parent 6102cd8aa6
commit 2a963be06d
4 changed files with 874 additions and 0 deletions

89
include/s_extern.h Normal file
View File

@ -0,0 +1,89 @@
#ifndef _FSP_S_EXTERN_H_
#define _FSP_S_EXTERN_H_ 1
/* conf.c, read and check configuration */
extern int daemonize,use_prebuild_dirlists,read_only,dbug;
extern int permit_passwordless_owners;
extern int use_access_files,use_directory_mtime;
extern int priv_mode,no_unnamed,logging,grab_enabled,ver_enabled;
extern int homedir_restricted;
extern uid_t run_uid;
extern gid_t run_gid;
extern unsigned int maxthcallowed;
extern unsigned short udp_port,packetsize;
extern time_t retry_timeout,session_timeout,stat_cache_timeout;
extern char *logname,*readme_file,*dumpname;
extern char *home_dir;
extern unsigned int dir_cache_limit, stat_cache_limit,fp_cache_limit;
extern char *tmp_dir;
extern mode_t upload_umask, system_umask;
void load_configuration PROTO1(const char *, conffile);
void destroy_configuration PROTO0((void));
/* file.c, file based disk i/o operations */
int init_caches PROTO0((void));
void shutdown_caches PROTO0((void));
void stat_caches PROTO1(FILE *,fp);
const char *validate_path PROTO0((char *, unsigned, PPATH *,DIRINFO **, int));
const char *server_get_dir PROTO0((DIRLISTING **,const DIRINFO *));
const char *server_del_file PROTO0((PPATH *, DIRINFO *));
const char *server_del_dir PROTO2(PPATH *, pp, DIRINFO *,di);
const char *server_make_dir PROTO0((PPATH *, unsigned long,DIRINFO **));
const char *server_get_file PROTO0((PPATH *, FILE **, unsigned long,
unsigned short,DIRINFO *));
const char *server_get_pro PROTO3(DIRINFO *, di, char *, result, const char *, acc);
const char *server_set_pro PROTO2(DIRINFO *,di, const char *, key);
const char *server_up_load PROTO0((char *, unsigned int, unsigned long, unsigned long,
unsigned short));
const char *server_install PROTO0((PPATH *, unsigned long, unsigned short,const char *,DIRINFO *,unsigned int,const char *));
const char *server_secure_file PROTO0((PPATH *, unsigned long,
unsigned short,DIRINFO *));
const char *server_grab_file PROTO0((FILE **, unsigned long,
unsigned short));
const char *server_grab_done PROTO0((unsigned long, unsigned short));
const char *server_stat PROTO1(UBUF *, buf);
const char *server_rename PROTO0((char *,unsigned int,unsigned int));
void init_home_dir PROTO0((void));
/* filecache.c, open filehandles cache */
/* iprange.c IP range services */
extern IPrange *iptab;
const char *check_ip_table PROTO2(unsigned long, inet_num,IPrange *,table);
void free_ip_table PROTO1(IPrange *,table);
void add_ipline PROTO2(const char *, text, IPrange **, table);
void dump_iptab PROTO2(IPrange *,table,FILE *, fp);
/* host.c, DNS and IP host databases */
HTAB *find_host PROTO0((unsigned long));
int init_htab PROTO0((void));
int dump_htab PROTO1(FILE *,fn);
/* server.c, network server operations */
extern time_t cur_time;
extern int shutdowning;
RETSIGTYPE server_interrupt PROTO1(int, signum);
RETSIGTYPE server_dump PROTO1(int, signum);
int server_loop PROTO2(int,fd,time_t,timeout);
int server_reply PROTO0((struct sockaddr_in *, UBUF *, unsigned int, unsigned int));
void send_file PROTO0((struct sockaddr_in *, UBUF *, FILE *, unsigned int,
char *));
/* acl.c, security code */
void load_access_rights PROTO1(DIRINFO *,di);
void save_access_rights PROTO1(DIRINFO *,di);
const char * require_access_rights PROTO4(const DIRINFO *,di,unsigned char,rights,unsigned long, ip_addr, const char *, passwd);
/* main.c, startup and init code */
/* log.c */
extern int logfd;
void fsplogf PROTO0((void));
void fsplogs PROTO0((void));
#ifdef __STDC__
void fsploga(const char *fmt, ...);
#else
void fsploga(va_alist);
#endif
#endif /* _FSP_S_EXTERN_H_ */

218
server/acl.c Normal file
View File

@ -0,0 +1,218 @@
/*********************************************************************\
* Copyright (c) 2003 by Radim Kolar (hsn@cybermail.net) *
* *
* You may copy or modify this file in any manner you wish, provided *
* that this notice is always included, and that you hold the author *
* harmless for any loss or damage resulting from the installation or *
* use of this software. *
\*********************************************************************/
#include "tweak.h"
#include <stdio.h>
#include "server_def.h"
#include "s_extern.h"
#include "my-string.h"
/* loads a password from file in current directory */
static char *load_password PROTO1(const char *, file)
{
/* load password */
FILE *f;
char fsp_passwd[80];
f=fopen(file,"r");
if(f) {
if(fscanf(f, "%79s", fsp_passwd) != 1) {
if(dbug) printf("load_pass: no password found in file\n");
fclose(f);
return NULL;
}
} else
return NULL;
fclose(f);
return strdup(fsp_passwd);
}
/* save a password to file in current directory */
static void save_password PROTO2(const char *,file,const char *,password)
{
/* load password */
FILE *f;
f=fopen(file,"w");
if(f) {
fprintf(f,"%s\n",password);
fclose(f);
}
}
/* save access rights to filesystem */
void save_access_rights PROTO1(DIRINFO *,di)
{
/* step 1 - unlink everything */
unlink(FSP_NOGET);
unlink(FSP_DEL);
unlink(FSP_ADD);
unlink(FSP_MKDIR);
unlink(FSP_RENAME);
unlink(FSP_NOLIST);
unlink(FSP_PASSWORD);
unlink(FSP_OWNER);
unlink(FSP_OWNERPASSWORD);
unlink(FSP_DIRLISTING);
if(!use_access_files) return;
/* step2 save flagfiles */
if(! (di->protection & DIR_GET) ) touch(FSP_NOGET);
if(di->protection & DIR_DEL) touch(FSP_DEL);
if(di->protection & DIR_ADD) touch(FSP_ADD);
if(di->protection & DIR_MKDIR) touch(FSP_MKDIR);
if(di->protection & DIR_RENAME) touch(FSP_RENAME);
if(!di->protection& DIR_LIST) touch(FSP_NOLIST);
/* step3 pazzwordz */
if(di->public_password) save_password(FSP_PASSWORD,di->public_password);
if(di->owner_password) save_password(FSP_OWNERPASSWORD,di->owner_password);
/* save Owner ACL */
if(di->owner)
{
FILE *f;
f=fopen(FSP_OWNER,"w");
if(f)
{
dump_iptab(di->owner,f);
fclose(f);
}
}
}
/* called with current directory == tested directory */
/* load access rights for validated directory */
void load_access_rights PROTO1(DIRINFO *,di)
{
struct stat sf;
FILE *f;
char owner_line[256];
di->owner=NULL;
di->owner_password=NULL;
di->public_password=NULL;
di->protection=DIR_LIST|DIR_GET;
di->readme=NULL;
/* load directory readme file */
if(!FSP_STAT(readme_file,&sf))
{
f=fopen(readme_file,"r");
if(f)
{
unsigned int s;
/* max readme file size is
* packetsize - pro_bytes (now 1) - 1 (for /0)
*/
s=min(packetsize-PRO_BYTES-1,sf.st_size);
di->readme=malloc(s+1);
if(di->readme)
{
fread(di->readme,s,1,f);
di->protection|=DIR_README;
}
fclose(f);
}
}
if(!use_access_files) return;
/* LOAD ACCESS RIGHTS FROM FILES IN CURRENT DIRECTORY */
if(fexist(FSP_NOGET)) di->protection^=DIR_GET;
if(fexist(FSP_DEL)) di->protection|=DIR_DEL;
if(fexist(FSP_ADD)) di->protection|=DIR_ADD;
if(fexist(FSP_MKDIR)) di->protection|=DIR_MKDIR;
if(fexist(FSP_RENAME)) di->protection|=DIR_RENAME;
if(fexist(FSP_NOLIST)) di->protection^=DIR_LIST;
if(!FSP_STAT(FSP_PASSWORD,&sf))
if(sf.st_size>0)
di->public_password=load_password(FSP_PASSWORD);
/* load owner info */
f=fopen(FSP_OWNER,"r");
if(!f)
return;
while(fscanf(f, "%255[^\n\r]", owner_line) == 1)
{
add_ipline(owner_line,&di->owner);
}
fclose(f);
/* .. and password */
if(!FSP_STAT(FSP_OWNERPASSWORD,&sf))
{
if(sf.st_size>0)
di->owner_password=load_password(FSP_OWNERPASSWORD);
}
}
/* does caller has enough security rights? */
/* if rights has DIR_PRIV set than caller is restristed and need also
* at least 'N' record to get it, if he has DIR_README, we will send him
* a datagram with error reply */
const char * require_access_rights PROTO4(const DIRINFO *,di,unsigned char,rights,unsigned long, ip_addr, const char *, passwd)
{
const char *acc=NULL;
/* check if we has record in an owner tabl. */
if(di->owner)
{
/* check ip access */
acc=check_ip_table(ip_addr,di->owner);
}
if(acc!=NULL)
{
if(acc[0]=='I' || acc[0]=='D')
/* bazmeg IP! */
return acc;
if(acc[0]=='O') /* possible owner */
{
if(di->owner_password==NULL)
{
if(permit_passwordless_owners)
return acc; /* passwordless owner */
} else
{
/* do we have a password? */
if(passwd)
{
/* compare passwords */
if(!strcmp(passwd,di->owner_password))
return acc; /* owner with good password */
} else
if(rights & DIR_OWNER)
return "DPassword required for owner";
}
}
}
if(rights & DIR_OWNER)
return "DNot an owner";
/* is password needed for public access? */
if(di->public_password)
{
if(passwd==NULL)
return "DYou need a password";
else
if(strcmp(di->public_password,passwd))
return "DInvalid password";
}
/* now check public access rights */
if( (rights & di->protection) ||
(rights==0)
)
return "NWelcome on board captain!";
else
return "DPermission denied";
}

258
server/fifocache.c Normal file
View File

@ -0,0 +1,258 @@
/*
* Simple FIFO generic cache. (c) Radim Kolar 2003.
* This file is copyrighted as LGPL.
*
* When this file is used as part of FSP, it uses 2-term BSD license
* (aka MIT/X11 License).
*/
#include "tweak.h"
#include <malloc.h>
#include <string.h>
#include <stdio.h>
#include "fifocache.h"
/* allocates a memory for new cache stucture and init it */
struct FifoCache * f_cache_new(unsigned int cachesize,unsigned int entrysize,
void (*edf) (void *),unsigned int keysize, void (*kdf) (void *), int (*kcf)(const void *,const void *))
{
struct FifoCache *cache;
if(cachesize==0) return NULL;
if(entrysize==0 && keysize==0) return NULL;
cache=calloc(1,sizeof(struct FifoCache));
if(cache==NULL) return NULL;
cache->cachesize=cachesize;
cache->keysize=keysize;
cache->entrysize=entrysize;
if(entrysize==0)
cache->e_head=calloc(1,1);
else
cache->e_head=calloc(cachesize,entrysize);
if(keysize==0)
cache->k_head=calloc(1,1);
else
cache->k_head=calloc(cachesize,keysize);
if(!cache->e_head || !cache->k_head)
{
f_cache_destroy(cache);
return NULL;
}
cache->k_next=cache->k_head;
if(keysize==0)
cache->k_stop=NULL;
else
cache->k_stop=cache->k_head+cache->keysize*cache->cachesize;
cache->e_next=cache->e_head;
if(entrysize==0)
cache->e_stop=NULL;
else
cache->e_stop=cache->e_head+cache->entrysize*cache->cachesize;
cache->k_destroy_func=kdf;
cache->e_destroy_func=edf;
cache->k_compare_func=kcf;
return cache;
}
/* set memory profile functions */
void f_cache_set_memory_profilers(struct FifoCache *cache,unsigned int (*keysize) (void *key),unsigned int (*entrysize) (void *entry))
{
cache->get_keysize=keysize;
cache->get_entrysize=entrysize;
}
void f_cache_stats(struct FifoCache *cache,FILE *f)
{
unsigned int i;
unsigned int used=0;
unsigned int j;
unsigned int dkey=0;
unsigned int dentry=0;
if(f==NULL) return;
/* count used items */
for(i=0;i<cache->cachesize;i++)
{
if(cache->keysize>0)
{
for(j=0;j<cache->keysize;j++)
{
if( *(cache->k_head+i*cache->keysize+j) != 0)
{
used++;
break;
}
}
}
}
/* calculate dynamic memory used */
if(cache->get_keysize)
{
for(i=0;i<cache->cachesize;i++)
{
dkey+=cache->get_keysize(cache->k_head+i*cache->keysize);
}
}
if(cache->get_entrysize)
{
for(i=0;i<cache->cachesize;i++)
{
dentry+=cache->get_entrysize(cache->e_head+i*cache->entrysize);
}
}
fprintf(f,"%u entries (%u used). Memory: %u hdr, keys %u static + %u dynamic, entries %u static + %u dynamic. Hit ratio: %u hit, %u miss.\n",
cache->cachesize,used,sizeof(struct FifoCache), cache->cachesize*cache->keysize,dkey,cache->cachesize*cache->entrysize,dentry,cache->hit,cache->miss);
}
unsigned int f_cache_void_profiler(void *anything)
{
return 0;
}
/* destroys cache without deallocationg of elements itself */
void f_cache_destroy(struct FifoCache *cache)
{
if(cache==NULL) return;
if(cache->e_head)
{
memset(cache->e_head,0,cache->entrysize*cache->cachesize);
free(cache->e_head);
}
if(cache->k_head) {
memset(cache->k_head,0,cache->keysize*cache->cachesize);
free(cache->k_head);
}
cache->e_head=NULL;
cache->k_head=NULL;
free(cache);
}
/* copy record into cache, free existing record */
/* returns pointer to data entry in cache */
void * f_cache_put(struct FifoCache *cache,const void *key,const void *data)
{
void *where;
/* free place for new element */
if(cache->k_destroy_func) cache->k_destroy_func(cache->k_next);
if(cache->e_destroy_func) cache->e_destroy_func(cache->e_next);
/* copy new element in */
where=cache->e_next;
memcpy(cache->k_next,key,cache->keysize);
memcpy(cache->e_next,data,cache->entrysize);
/* update next pos. */
cache->e_next+=cache->entrysize;
cache->k_next+=cache->keysize;
/* roll over? */
if(cache->e_next==cache->e_stop || cache->k_next==cache->k_stop)
{
cache->e_next=cache->e_head;
cache->k_next=cache->k_head;
}
return where;
}
/* find element by key */
void *f_cache_find(struct FifoCache *cache,const void *key)
{
unsigned int i;
if(!cache->k_compare_func) return NULL;
if(cache->keysize==0) return NULL;
for(i=0;i<cache->cachesize;i++)
if(!cache->k_compare_func(key,cache->k_head+i*cache->keysize))
{
cache->hit++;
return cache->e_head+i*cache->entrysize;
}
cache->miss++;
return NULL;
}
/* clear all elements from the cache */
void f_cache_clear(struct FifoCache *cache)
{
unsigned int i;
/* free entries */
for(i=0;i<cache->cachesize;i++)
{
if(cache->k_destroy_func)
cache->k_destroy_func(cache->k_head+i*cache->keysize);
if(cache->e_destroy_func)
cache->e_destroy_func(cache->e_head+i*cache->entrysize);
}
/* clear entries */
memset(cache->k_head,0,cache->cachesize*cache->keysize);
memset(cache->e_head,0,cache->cachesize*cache->entrysize);
cache->k_next=cache->k_head;
cache->e_next=cache->e_head;
cache->hit=0;
cache->miss=0;
}
/* find key for given entry */
void * f_cache_get_key(struct FifoCache *cache,const void *entry)
{
unsigned int i;
if(cache->entrysize==0 || cache->keysize==0) return NULL;
/* check if pointer is good */
if(entry<(const void *)cache->e_head || entry>=(const void *)cache->e_stop) return NULL;
/* find cache index */
i=((const BYTE *)(entry)-cache->e_head)/cache->entrysize;
return cache->k_head+cache->keysize*i;
}
/* delete entry from cache, returns one if object is deleted */
int f_cache_delete_entry(struct FifoCache *cache, void *entry)
{
unsigned int i;
if(cache->entrysize==0) return 0;
/* check if pointer is good */
if(entry<(const void *)cache->e_head || entry>=(const void *)cache->e_stop) return 0;
/* find cache index */
i=((BYTE *)(entry)-cache->e_head)/cache->entrysize;
/* deallocate */
if(cache->k_destroy_func) cache->k_destroy_func(cache->k_head+cache->keysize*i);
if(cache->e_destroy_func) cache->e_destroy_func(entry);
/* zero them */
memset(entry,0,cache->entrysize);
memset(cache->k_head+cache->keysize*i,0,cache->keysize);
return 1;
}
/* returns how many objects was deleted */
int f_cache_delete_by_key(struct FifoCache *cache, void *key)
{
unsigned int i;
int deleted=0;
if(!cache->k_compare_func) return 0;
for(i=0;i<cache->cachesize;i++)
{
if(!cache->k_compare_func(key,cache->k_head+i*cache->keysize))
{
deleted+=f_cache_delete_entry(cache,cache->e_head+i*cache->entrysize);
}
}
return deleted;
}

309
server/iprange.c Normal file
View File

@ -0,0 +1,309 @@
/*********************************************************************\
* Copyright (c) 2003 by Radim Kolar (hsn@cybermail.net) *
* Copyright (c) 1991 by Wen-King Su (wen-king@vlsi.cs.caltech.edu) *
* *
* You may copy or modify this file in any manner you wish, provided *
* that this notice is always included, and that you hold the author *
* harmless for any loss or damage resulting from the installation or *
* use of this software. *
\*********************************************************************/
#include "tweak.h"
#include <ctype.h>
#include <netdb.h>
#include "server_def.h"
#include "s_extern.h"
#include "my-string.h"
/* Function for IPrange structure */
IPrange *iptab=NULL;
#define skip_whitespace(x) do {while (*(x)&&isspace(*(x))) (x)++;} while (0)
/* check if inet_number matches entry in IPrange table */
/* return pointer to specified message */
static char *check_ip PROTO2(unsigned long, inet_num, const IPrange *, iprange)
{
unsigned int j;
unsigned char val[4];
inet_num = ntohl(inet_num);
val[0] = (inet_num & 0x000000ff) ;
val[1] = (inet_num & 0x0000ff00) >> 8;
val[2] = (inet_num & 0x00ff0000) >> 16;
val[3] = (inet_num & 0xff000000) >> 24;
for (j = 0; j < 4; j++)
if (iprange->lo[j] > val[j] || val[j] > iprange->hi[j]) return NULL;
return iprange->text;
}
const char *check_ip_table PROTO2(unsigned long, inet_num,IPrange *,table)
{
char *res;
while(table)
{
if(!table->text) return NULL; /* EOT! */
res=check_ip(inet_num,table);
if(res) return res;
table++;
}
return NULL;
}
void free_ip_table PROTO1(IPrange *,table)
{
IPrange *head=table;
/* free strings */
while(table++)
{
if(!table->text) break;
free(table->text);
}
free(head);
}
/* IP parsing fun */
/* parse the text string as an integer and return a value between 0x00 and 0xff
if there is any error in forming the value (e.g., the text string
isn't an integer, or the integer value is too large) then make the
text string NULL */
static unsigned char parse_ipcomponentnum PROTO1(const char * *, textp)
{
unsigned long val = 0;
if (!isdigit(**textp)) {
*textp = 0;
} else
do {
val = 10 * val + (**textp - '0');
(*textp)++;
} while (isdigit(**textp));
if (val > 0xff) {
val = 0;
*textp = 0;
}
return val;
}
/* parse a whole field of a numerical IP address; it can be one of:
integer >> fixed value
integer '-' integer >> range of values
'*' >> same as 0-255
*/
static const char *parse_ipcomponent PROTO3(const char *, text, unsigned char *, lo,
unsigned char *, hi)
{
if (*text == '*') {
*lo = 0x00;
*hi = 0xff;
return (text + 1);
}
*lo = parse_ipcomponentnum(&text);
if (!text) return 0;
if (*text == '-') {
text++;
*hi = parse_ipcomponentnum(&text);
} else *hi = *lo;
return text;
}
static IPrange *parse_ipnumber PROTO1(const char *, text)
{
IPrange *reply;
int i;
reply = (IPrange *)malloc(sizeof(IPrange));
for (i = 3; i >= 0 && !isspace(*text); i--) {
if (i < 3) {
if (*text != '.') return 0;
else text++;
}
text = parse_ipcomponent(text, &reply->lo[i], &reply->hi[i]);
if (!text) {
free((char *)reply);
return 0;
}
}
/* fill in the gaps in the case that the loop terminated due to
the occurrence of white-space */
for (; i >= 0; i--) {
reply->lo[i] = 0x00;
reply->hi[i] = 0xff;
}
return reply;
}
static IPrange *parse_hostname PROTO2(const char *, text, unsigned int, len)
{
IPrange *reply;
struct hostent *hostaddr;
unsigned long inet_num;
char *hostname;
hostname = malloc(len + 1);
strncpy(hostname, text, len);
hostname[len] = 0;
hostaddr = gethostbyname(hostname);
free(hostname);
if (!hostaddr) return 0;
reply = (IPrange *)malloc(sizeof(IPrange));
inet_num = ((struct in_addr *)(hostaddr->h_addr))->s_addr;
reply->lo[0] = reply->hi[0] = (inet_num & 0x000000ff) ;
reply->lo[1] = reply->hi[1] = (inet_num & 0x0000ff00) >> 8;
reply->lo[2] = reply->hi[2] = (inet_num & 0x00ff0000) >> 16;
reply->lo[3] = reply->hi[3] = (inet_num & 0xff000000) >> 24;
return reply;
}
/* parse a single line for the IP hosts file */
/* returns IPrange structure,first letter in message is type */
/*
# syntax of ipline is: host_mask host_type [message]
# host_type is one of D, I, or N :
# I hosts are ignored
# N hosts are treated as normal
# D hosts will receive the error string message given as the third parameter
# 128.4-8.*.* -- (* acts as the range 0 - 255)
*/
static IPrange *parse_ipline PROTO1(const char *, text)
{
IPrange *reply;
char type = 0;
const char *message = 0;
size_t messlen = 0, addresslen;
/* skip the leading white-space */
skip_whitespace(text);
/* if the line is commented or empty, ignore it */
if (!*text || *text == '#') return 0;
/* load hostname range (can not have spaces inside) */
message = text;
while (*message && !isspace(*message)) message++;
addresslen = message - text;
/* find the first non-space character after the address - this
identifies the type of host this is */
skip_whitespace(message);
if (!*message || *message == '#') {
fprintf(stderr, "No host type specified in config file:\n\t%s\n", text);
/* if a host name is mentioned by itself, then treat it as ignored
or normal depending on the value of priv_mode */
return 0;
}
/* the first character after the host name is the type of host */
type = *message;
/* skip over the white space trailing the type - the start of the
associated message */
message++; /* remember skip_whitespace() is a macro... */
skip_whitespace(message);
/* `remove' the trailing white-space from the message */
messlen = strlen(message);
while (messlen > 0 && isspace(message[messlen-1])) messlen--;
/* if the first character of the address is numerical or '*' then parse
as a numerical address, otherwise we do a host lookup on the name. */
if (*text == '*' || isdigit(*text))
reply = parse_ipnumber(text);
else
reply = parse_hostname(text, addresslen);
if (!reply) {
fprintf(stderr, "Badly formed address in config file:\n\t%s\n", text);
return 0;
}
/* allocate a string to hold the message */
reply->text = malloc(1 + messlen + 1); /* type + text + '\0' */
if(!reply->text)
{
free(reply);
return 0;
}
reply->text[0] = type;
strncpy(&reply->text[1], message, messlen);
reply->text[1 + messlen] = '\0';
return reply;
}
void add_ipline PROTO2(const char *, text, IPrange **, table)
{
IPrange *nl;
IPrange *newtab;
int i;
nl = parse_ipline(text);
if(!nl) return;
/* add a new record to table */
if(*table==NULL)
{
*table=malloc(sizeof(IPrange)*2);
if(!*table) return;
memcpy(*table,nl,sizeof(IPrange));
free(nl);
((*table)+1)->text=NULL;
return;
}
/* count records in IPrange table */
i=0;
while( ((*table)+i++)->text!=NULL);
newtab=realloc(table,sizeof (IPrange) * (i+1));
if(!newtab) return;
*table=newtab;
memcpy( (*table)+i,nl,sizeof(IPrange));
free(nl);
((*table)+i+1)->text=NULL;
}
/****************************************************************************
* Write out the IP table in the .IPTAB_DUMP file.
****************************************************************************/
void dump_iptab PROTO2(IPrange *,table,FILE *, fp)
{
if(fp==NULL)
{
if(dbug)
fp=stdout;
else
return;
}
while(table) {
if(!table->text) break;
fprintf(fp, "%d-%d.%d-%d.%d-%d.%d-%d %c %s\n",
table->lo[3], table->hi[3],
table->lo[2], table->hi[2],
table->lo[1], table->hi[1],
table->lo[0], table->hi[0],
table->text[0],&table->text[1]);
table++;
}
}