Vanilla List Maling List Archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
patch for getname.c, pledit.c; new tool
Howdy,
The server currently misuses crypt(). The salt argument is supposed
to be a two-character string taken from the set [A-Za-z0-9./]. We are
using the player name as salt. If the name isn't valid salt, the
behavior of crypt is undefined. (In fact, it works differently
between solaris and linux. I noticed this when moving the guinness
database to pickled.)
Here is are server and pledit patches and a new tool for changing
passwords. The server patch will work with an "old" database, fixing
broken password entries as they are noticed. Thanks to Dave Ahn for
suggesting this.
Be warned: I've only done minimal testing. Pickled will use this
stuff, so I should find notice any horrible bugs soon enough.
-dave
New files (listed first):
ntserv/salt.h
ntserv/salt.c
tools/ntpasswd.c
Modified files:
tools/Makefile
ntserv/Makefile
ntserv/getname.c
pledit/Makefile
pledit/edit.c
New file: ntserv/salt.h
===================================================================
#ifndef SALT_H
#define SALT_H
typedef char saltbuf[3]; /* Size of salt string buf for crypt(). */
char* salt(const char*, saltbuf);
#endif /* SALT_H */
New file: ntserv/salt.c
===================================================================
#include <ctype.h>
#include "salt.h"
#define DEFAULT 'X'
/* Valid salt chars are [A-Za-z0-9/.] */
static char saltchar(char ch)
{
switch (ch) {
case '/':
case '.':
return ch;
default:
if (isalnum(ch)) return ch;
else return DEFAULT;
}
}
/* Sets sb to a valid salt argument for crypt(), based on s. */
char* salt(const char* s, saltbuf sb)
{
int i;
int end = 0;
int saltlen = sizeof(sb) - 2;
for (i=0; i<saltlen; i++) {
if (!end) end = (*s == '\0');
if (end) {
sb[i] = DEFAULT;
} else {
sb[i] = saltchar(*s);
s++;
}
}
sb[saltlen] = '\0';
return sb;
}
New file: tools/ntpasswd.c
===================================================================
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include "defs.h"
#include "struct.h"
#include "data.h"
#include "salt.h"
char *crypt(const char* key, const char* salt);
/* Search for player by name, leaving f positioned at start of
* player's entry. Returns 0 on error.
*/
static int find(FILE* f, const char* name, struct statentry* player)
{
for(;;) {
if (fread(player, sizeof(struct statentry), 1, f) != 1) {
if (feof(f)) break;
perror("fread");
return 0;
}
if (strcmp(player->name, name) == 0) {
if (fseek(f, -sizeof(struct statentry),
SEEK_CUR) == -1) {
perror("fseek");
return 0;
}
return 1;
}
}
printf("%s not found in database\n", name);
return 0;
}
static const char* check(const char* s)
{
if (strlen(s) < NAME_LEN)
return s;
else
return NULL;
}
int main(int argc, const char** argv)
{
FILE* f;
struct statentry player;
saltbuf sb;
const char* name;
const char* password;
if (argc != 3) {
fprintf(stderr, "usage: %s player password\n",
argv[0]);
return 1;
}
name = check(argv[1]);
password = check(argv[2]);
if (name == NULL || password == NULL) {
fprintf(stderr, "%s: player name and password can be "
"at most %d characters\n", argv[0], NAME_LEN-1);
return 1;
}
getpath();
f = fopen(PlayerFile, "r+b");
if (f == NULL) {
perror(PlayerFile);
return 1;
}
if (! find(f, name, &player)) {
fclose(f);
return 1;
}
/* we could be zeroing the password... */
memset(player.password, 0, sizeof(player.password));
strcpy(player.password, crypt(password, salt(name, sb)));
if (fseek(f, offsetof(struct statentry, password), SEEK_CUR) == -1) {
perror("fseek");
fclose(f);
return 1;
}
if (fwrite(player.password, sizeof(player.password), 1, f) != 1) {
perror("fwrite");
fclose(f);
return 1;
}
fclose(f);
printf("password for %s changed\n", name);
return 0;
}
Index: tools/Makefile
===================================================================
RCS file: /home/netrek/cvsroot/Vanilla/tools/Makefile,v
retrieving revision 1.14
diff -r1.14 Makefile
35c35,36
< sortdb.c ../robots/roboshar.c ../ntserv/smessage.c
---
> sortdb.c ../robots/roboshar.c ../ntserv/smessage.c \
> ntpasswd.c ../ntserv/salt.c
39c40,41
< mergescores keyman updated fun conq_vert convert sortdb cambot
---
> mergescores keyman updated fun conq_vert convert sortdb cambot \
> ntpasswd
69a72
> $(INSTALL) $(INSTALLOPTS) ntpasswd $(LIBDIR)/tools/ntpasswd
80a84,86
>
> ntpasswd: ntpasswd.o $(STRUCTS) $(GETPATH) ../ntserv/salt.h ../ntserv/salt.o
> $(CC) -o $@ $(CFLAGS) ntpasswd.o $(GETPATH) ../ntserv/salt.o
Index: ntserv/Makefile
===================================================================
RCS file: /home/netrek/cvsroot/Vanilla/ntserv/Makefile,v
retrieving revision 1.15
diff -r1.15 Makefile
12c12
< findslot.o getentry.o getname.o getship.o input.o \
---
> findslot.o getentry.o getname.o salt.o getship.o input.o \
30c30
< findslot.c getentry.c getname.c getship.c input.c \
---
> findslot.c getentry.c getname.c salt.c getship.c input.c \
Index: ntserv/getname.c
===================================================================
RCS file: /home/netrek/cvsroot/Vanilla/ntserv/getname.c,v
retrieving revision 1.2
diff -r1.2 getname.c
9a10
> #include <stddef.h>
24a26
> #include "salt.h"
26c28,30
< char *crypt();
---
> char *crypt(const char* key, const char* salt);
> #define streq(a,b) (strcmp((a),(b)) == 0)
> static void savepass(const struct statentry*);
44a49,50
> saltbuf sb;
> char newpass[NAME_LEN];
149c155
< strcpy(player.password, crypt(passPick, namePick));
---
> strcpy(player.password, crypt(passPick, salt(namePick, sb)));
155a162,164
> /* race condition: Two new players joining at once
> * can screw up the database.
> */
162c171
< }
---
> }
174d182
<
176,183c184,199
< if ((strcmp(player.password, crypt(passPick, player.password)) != 0) ||
< lockout()){
< sendClientLogin(NULL);
< } else {
< sendClientLogin(&player.stats);
< strcpy(me->p_name, namePick);
< me->p_pos=position;
< MCOPY(&player.stats, &(me->p_stats), sizeof(struct stats));
---
> strcpy(newpass, crypt(passPick, salt(player.name, sb)));
> if (lockout() ||
> (!streq(player.password, newpass) &&
> !streq(player.password, crypt(passPick, player.password)))) {
> sendClientLogin(NULL);
> flushSockBuf();
> return;
> }
> sendClientLogin(&player.stats);
> strcpy(me->p_name, namePick);
> me->p_pos=position;
> MCOPY(&player.stats, &(me->p_stats), sizeof(struct stats));
> if (!streq(player.password, newpass)) {
> /* update db if we were misuing crypt() */
> strcpy(player.password, newpass);
> savepass(&player);
188a205,219
> static void savepass(const struct statentry* se)
> {
> int fd;
> if (me->p_pos < 0) return;
> printf("getname.c: updating password for %s\n", se->name);
> fd = open(PlayerFile, O_WRONLY, 0644);
> if (fd >= 0) {
> lseek(fd, me->p_pos * sizeof(struct statentry) +
> offsetof(struct statentry, password),
> SEEK_SET);
> write(fd, &se->password, sizeof(se->password));
> close(fd);
> }
> }
>
197c228,230
< lseek(fd, 32 + me->p_pos * sizeof(struct statentry) ,0);
---
> lseek(fd, me->p_pos * sizeof(struct statentry) +
> offsetof(struct statentry, stats),
> SEEK_SET);
Index: pledit/Makefile
===================================================================
RCS file: /home/netrek/cvsroot/Vanilla/pledit/Makefile,v
retrieving revision 1.14
diff -r1.14 Makefile
9,10c9,12
< SRCS = main.c edit.c input.c ../ntserv/getpath.c ../ntserv/data.c
< OBJS = main.o edit.o input.o ../ntserv/getpath.o ../ntserv/data.o
---
> SRCS = main.c edit.c input.c ../ntserv/getpath.c ../ntserv/data.c \
> ../ntserv/salt.c
> OBJS = main.o edit.o input.o ../ntserv/getpath.o ../ntserv/data.o \
> ../ntserv/salt.o
Index: pledit/edit.c
===================================================================
RCS file: /home/netrek/cvsroot/Vanilla/pledit/edit.c,v
retrieving revision 1.1.1.1
diff -r1.1.1.1 edit.c
18c18
<
---
> #include "salt.h"
583c583
< char *crypt();
---
> char *crypt(const char*, const char*);
589a590
> saltbuf sb;
719c720
< strcpy(sep->password, crypt(sep->password, sep->name));
---
> strcpy(sep->password, crypt(sep->password, salt(sep->name, sb)));