External Authentication Module, NWAuth
This fully useable example external authentication module comes in all
distribution sets. The source is provided on all platforms and
for Windows and most Unix based platforms it is pre-compiled,
as nwauth.exe or nwauth.
If you do compile it, it must be compiled with 32 bit compiler.
Example compile line,
gcc -o nwauth -g -w -Dunix nwauth.c -lc
Note: if you get crypt errors you may need to add, -lcrypt to
the end of the line (e.g. on RedHat6 and above).
An example authentication program for use with DPOP and DMAIL. This
program is spawned as a sub process by both DPOP and DSMTP
(i.e. two processes run simultaneously). DPOP and DSMTP send
commands to authent stdin via a pipe and receives output
from authent stdout via a pipe. Authent simply reads commands with
gets and writes replies with printf BUT fflush must be used after
each printf.
Commands:
For the defintion of the External Authentication Protocol ( to
which nwauth adheres) see the External
Authentication section.
Notes:
- NWAuth is case insensitive for the usernames. So to avoid using
up users on your license, with for example three bobs, being bob, BOB and
Bob, you should probably set
lowercase_username true. This also means that you cannot end up with mixed case
drop file and bin files on UNIX platforms - so well worth doing.
- Version 2 and above of nwauth adds users to an intermediate
user file, nwauth.add, when this reaches 3kBytes, the entries
in this file are added to nwauth.txt. This makes user addition
much faster on large user databases.
- NWAuth and NFS drives Important informtation for those using NFS drives
See the Performance Page for information
about NWAuth's efficiency with 100,000 users.
Below is the source distributed with version 2.5f:
/*
todo:
When change or set command, add to '.add' file
Make database file a command line option.
Sample NetWin Authentication routine, high speed simple text file based
authentication
Command line options:
nwauth -set username[@domain] password INFO
nwauth -mod username[@domain] INFO
nwauth -check username password
nwauth -lookup username
nwauth -del username
nwauth -search string
Normal processing options when used as external authent module for dsmtp/dpop:
exit
+OK shutting down authent process (RHP nope it just goes away but thats ok)
set user password fwd="fred" groups="adults" name="Mr \"Cool\" Smith"
check username[@domain] password fromIPaddress
+OK username@domain drop_file_path uid
lookup username[@domain]
+OK username@domain drop_file_path uid fwd="a@b" groups="adults"
set user password aaa="bbb" ccc="ddd"
+OK user added/modified
delete user
+OK user removed
search string
+DATA user1 info
+DATA user2 info
+DATA user3 info
+DATA user4 info
+OK
Normal processing commands
set user password [INFO]
set user (NULL) [INFO] (change info but leave password unchanged)
check username[@domain] password fromIPaddress
lookup username[@domain]
delete user
search string
Works by using a file nwauth.txt in this format
user:password:info
Changes History:
TRW added: -log option instead of -debug, only log to file,
dsmtp_path\nwauth.txt
TRW fixed bug:
Regan Added :
-Label EXTERNAL_LOG, which disables nwauth log routines and enables other
log routines to be called ie routines in log.c etc...
- if NOAUTHMAIN then myprintf are replaced with buf_print
buf_clear and buf_get are companion routines
Regan Changed :
-Now prints +OK after recieving quit command.
-ncpy is now static as conflicted when included with other .c files that also included
ncpy.
2.0b
29/4/99 for 2.5d TRW changed:
- \n on end of +OK
-
5/5/99 still for 2.5d, TRW changed;
- fflush after +ok in response to exit, for most other
responses it is in the end of the do_command function.
2.0c
11/5/99 for 2.5d TRW changed;
- made db_check and search check that build_index and check_add
had been done at least once (for wadduser as is CGI).
- added -version command
2.0d
17/5/99 for 2.5f TRW changed
- added -size command line option
- made log file get logged to dmail dir (or as set by path
command).
- added more error logging in search.
*/
/* #define NOAUTHMAIN */
/* #define EXTERNAL_LOG*/
#define VERSION "version 2.0d"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifndef WIN32
#include
char *strlwr(char *s);
#endif
#ifdef WIN32
# include
char *crypt(char *key, char *salt);
# define getpid _getpid
#else
char *crypt(const char *key, const char *salt);
#endif
int db_check(char *user, char *pass, char *info);
char *auth_info(char *argv[], int i, int argc);
int lib_date(char *fname);
char *value_encode(char *s);
#include "nwauth.h"
int auth_rebuild(void);
void do_vers(void);
char *file_config(char *fname);
void check_add(void);
int free_index(void);
int has_changed(void);
int do_command(char *s);
int build_index(void);
int str_hash(char *s, int max);
char * db_pass(char *user);
void log_file(char *s);
void auth_fixup(char *user, char *pass, char *info);
static char *ncpy(char *dst, char *src, int len);
void zfreeall(void);
void zstrfree(char *s);
char *zstrdup(char *s);
char * zstrstrnc(char *s1, char *s2) ;
int zstrncmpnc(char *s1, char *s2, int n) ;
int zstrcmpnc(char *s1, char *s2);
#ifdef EXTERNAL_LOG
# include "new_log.h"
#else
void imsg(char * arg_list, ...);
void emsg(char * arg_list, ...);
# define dmsg imsg
#endif
#ifdef NOAUTHMAIN
# define myprintf buf_print
#else
# define myprintf printf
#endif
#define BFSZ 1000
#ifndef FALSE
# define FALSE 0
# define TRUE (!FALSE)
#endif
static int isdebug;
static int islog;
static int isend;
static int pid;
static int done_check_add;
static int done_build_index;
#define DFLT_REBUILD_SIZE 3000
static int rebuild_size;
static char *buffer = NULL;
int f_size(FILE *f);
int auth_init(void)
{
return build_index();
}
int buf_print(char *arg_list, ...)
{
va_list arg_ptr;
char *format, *p;
char text[512];
size_t size = 0, new_size = 0;
va_start(arg_ptr, arg_list);
format = arg_list;
vsprintf(text, format, arg_ptr);
if (buffer) size = strlen(buffer);
new_size = size + strlen(text);
buffer = realloc(buffer, new_size + 2);
p = buffer + size;
strcpy(p, text);
return size;
}
int buf_clear(void)
{
if (buffer) {free(buffer); buffer = NULL;}
return 1;
}
char *buf_get(void)
{
if (buffer) return buffer;
else return "";
}
static char arg_path[BFSZ];
#ifndef NOAUTHMAIN
int main(int argc, char *argv[])
{
char bf[BFSZ];
int t,i;
t = 1;
srand(time(NULL));
for (i=1;argc>i;i++) {
if (strcmp(argv[i],"-debug")==0)
isdebug = TRUE;
else if (strcmp(argv[i],"-log")==0)
islog = TRUE;
else if (strcmp(argv[i],"-version")==0){
do_vers();
return 0;
}
}
/*if (argc>t) {
if (strcmp(argv[t],"-debug")==0) {
t++;
isdebug = TRUE;
}
if (strcmp(argv[t],"-log")==0) {
t++;
islog = TRUE;
}
}*/
pid=getpid();
if (isdebug)
dmsg("\n**DNAuth Started in debug mode, %s, pid=%d exe/log_path={%s}\n",VERSION,pid,file_config(""));
if (islog)
dmsg("\n**DNAuth Started in logging mode, %s, pid=%d exe/log_path={%s}\n",VERSION,pid,file_config(""));
if (!build_index()) return 1;
check_add(); /* Check for new/changed entries */
again:
if (argc>t) {
if (strcmp(argv[t],"-add")==0) {if (t+3>=argc) auth_set(argv[t+1],argv[t+2],auth_info(argv,t+3,argc));}
else if (strcmp(argv[t],"-set")==0) {if (t+2>=argc) goto badp; auth_set(argv[t+1],argv[t+2],auth_info(argv,t+3,argc));}
else if (strcmp(argv[t],"-mod")==0) {if (t+1>=argc) goto badp; auth_set(argv[t+1],"(NULL)",auth_info(argv,t+3,argc));}
else if (strcmp(argv[t],"-del")==0) {if (t+1>=argc) goto badp; auth_del(argv[t+1],FALSE);}
else if (strcmp(argv[t],"-check")==0) {if (t+2>=argc) goto badp; auth_check(argv[t+1],argv[t+2]);}
else if (strcmp(argv[t],"-lookup")==0) {if (t+1>=argc) goto badp; auth_lookup(argv[t+1]);}
else if (strcmp(argv[t],"-search")==0) {if (t+1>=argc) goto badp; auth_search(argv[t+1]);}
else if (strcmp(argv[t],"-path")==0) {if (t+1>=argc) goto badp; strcpy(arg_path,argv[t+1]); t+=2; goto again;}
else if (strcmp(argv[t],"-size")==0) {if (t+1>=argc) goto badp; rebuild_size=atoi(argv[t+1]); t+=2; goto again;}
else if (strcmp(argv[t],"-log")==0) {t++; goto again;}
else if (strcmp(argv[t],"-debug")==0) {t++; goto again;}
else if (strcmp(argv[t],"-help")==0) {
myprintf("Usage:\n");
myprintf("\tnwauth -set user password var1=value ...\n");
myprintf("\tnwauth -mod user var1=value ...\n");
myprintf("\tnwauth -del user\n");
myprintf("\tnwauth -check user password\n");
myprintf("\tnwauth -lookup user\n");
myprintf("\tnwauth -search string\n");
myprintf("\tnwauth -size x -... (sets max size of nwauth.add)\n");
myprintf("\tnwauth -log -... (turns on logging to nwauth.log)\n");
myprintf("\tGive no switches to run in slave mode\n");
}
return 0;
badp: myprintf("Wrong number of paramters\n");
fflush(stdout);
return 0;
}
for (;!isend;) {
if (fgets(bf,BFSZ-1,stdin)==NULL) break;
/* Check if file changes (once a second at most) */
if (has_changed()) build_index();
check_add(); /* Check for new/changed entries */
do_command(bf);
}
myprintf("+OK\n");
fflush(stdout);
return 0;
}
#endif
void do_vers(void)
{
myprintf("+OK nwauth %s\n",VERSION);
fflush(stdout);
}
char *auth_info(char *argv[], int i, int argc)
{
static char info[BFSZ];
strcpy(info,"");
for (;inext) {
/*TRW,2.5f; if (strlen(u->user)==0) continue; */
if (strlen(u->user)==0) { dmsg("debug: empty slot in database (deleted/changed user).\n"); continue;}
if (zstrstrnc(u->user,match)!=NULL) goto showit;
if (zstrstrnc(u->info,match)!=NULL) goto showit;
if (strcmp(match,"*")==0) goto showit;
if (strcmp(u->user,match)==0) goto showit2;
continue;
showit2:
dmsg("ERROR: strcmp matched %s %s\n",u->user,u->info);
continue;
showit:
if (strlen(domain)>0)
if (zstrstrnc(u->user,domain)==NULL) continue;
printf("+DATA %s %s\n",u->user,u->info);
found++;
}
}
printf("+OK Search Complete %d items found\n", found);
return found;
}
int auth_search_old(char *match)
{
FILE *f;
char bf[BFSZ];
char orig[BFSZ];
char user[BFSZ], domain[BFSZ];
char xinfo[BFSZ];
char *s,*out;
int found = 0;
f = fopen(FILE_NWAUTH,"r");
if (f==NULL) {
emsg("-ERR Unable to open %s, %s\n",FILE_NWAUTH,strerror(errno));
return FALSE;
}
strlwr(match);
s = strstr(match,"@");
if (s != NULL) {
strcpy(domain, s);
*s = '\0';
} else strcpy(domain, match);
dmsg("auth_search: matching {%.200s:%.200s} (always lwrcase)\n",match, domain);
for (;!feof(f);) {
if (fgets(bf,BFSZ-1,f)==NULL) break;
strcpy(orig,bf);
strlwr(bf);
if (strstr(bf,match) != NULL && strstr(bf,domain) != NULL) {
s = strtok(orig,":\n"); if (s==NULL) continue;
strcpy(user,s);
s = strtok(NULL,":\n"); if (s==NULL) continue;
s = strtok(NULL,"\n");
if (s==NULL) s = "";
if (!db_check(user,NULL,xinfo)) continue;
out = value_encode(user);
printf("+DATA %s %s\n",user,s);
found++;
}
}
fclose(f);
f = fopen(FILE_ADD,"r");
if (f!=NULL) for (;!feof(f);) {
if (fgets(bf,BFSZ-1,f)==NULL) break;
strcpy(orig,bf);
strlwr(bf);
if (strstr(bf,match) != NULL && strstr(bf,domain) != NULL) {
s = strtok(orig,":\n"); if (s==NULL) continue;
strcpy(user,s);
s = strtok(NULL,":\n"); if (s==NULL) continue;
if (strcmp(s,"(delete)")==0) continue;
s = strtok(NULL,"\n");
if (s==NULL) s = "";
if (!db_check(user,NULL,xinfo)) continue;
out = value_encode(user);
printf("+DATA %s %s\n",user,s);
found++;
}
}
if (f!=NULL) fclose(f);
printf("+OK Search Complete %d items found\n", found);
return found;
}
int lib_date(char *fname)
{
struct stat st;
FILE *f;
f = fopen(fname,"r");
if (f==NULL) return 1;
fstat(fileno(f),&st);
fclose(f);
return (int) st.st_mtime;
}
int has_changed(void)
{
static int last;
int t;
static time_t last_time;
if (time(NULL)==last_time) return FALSE;
last_time = time(NULL);
t = lib_date(FILE_NWAUTH);
if (last==0) last = t;
if (t!=last) {
last = t;
return TRUE;
}
return FALSE;
}
User *auth_find(char *user);
int free_index(void)
{
int i;
User *u,*unext;
for (i=0; inext;
zstrfree(u->user);
zstrfree(u->pass);
zstrfree(u->info);
free(u);
}
users[i] = NULL;
}
zfreeall();
return TRUE;
}
#ifdef WIN32
#include
#endif
char *file_dmail(void)
{
#ifdef WIN32
static char sysdir[BFSZ];
static char binpath[BFSZ];
GetSystemDirectory(sysdir,BFSZ);
sprintf(binpath,"%s\\dmail.conf",sysdir);
return binpath;
#else
return "/etc/dmail.conf";
#endif
}
char *file_config(char *fname)
{
char *s;
char var[BFSZ];
char val[BFSZ];
FILE *f;
static char bf[BFSZ];
static char path[BFSZ];
if (strlen(path)==0) {
f = fopen(file_dmail(),"r");
if (f==NULL) return fname;
for (;!feof(f);) {
if (fgets(bf,BFSZ-1,f)==NULL) break;
s = strtok(bf," \t\r\n"); if (s==NULL) continue;
strcpy(var,s);
strlwr(var);
s = strtok(NULL," \t\r\n"); if (s==NULL) continue;
strcpy(val,s);
if (strcmp(var,"dsmtp_path")==0) {
strcpy(path,val);
}
}
fclose(f);
}
if (strlen(arg_path)>0) sprintf(bf,"%s/%s",arg_path,fname);
else sprintf(bf,"%s/%s",path,fname);
return bf;
}
int build_index(void)
{
FILE *f;
int h;
char *s;
char bf[BFSZ];
int nlines=0;
User *u;
done_build_index=TRUE;
free_index();
f = fopen(FILE_NWAUTH,"r");
if (f==NULL) {
imsg("Unable to open %s, %s\n",FILE_NWAUTH,strerror(errno));
return TRUE;
}
for (;!feof(f);) {
if (fgets(bf,BFSZ-1,f)==NULL) break;
u = malloc(sizeof(User));
s = strtok(bf,":\n \t"); if (s==NULL) continue;
strlwr(s); /* Store usernames in lowercase */
u->user = zstrdup(s);
s = strtok(NULL,":\n \t"); if (s==NULL) continue;
u->pass = zstrdup(s);
s = strtok(NULL,"\n"); if (s==NULL) s = "";
u->info = zstrdup(s);
h = str_hash(u->user,MAX_HASH);
u->next = users[h];
users[h] = u;
nlines++;
}
fclose(f);
imsg("Read %d lines from nwauth.txt\n",nlines);
return TRUE;
}
void auth_fixup(char *user, char *pass, char *info)
{
User *u;
int h;
int dodel = FALSE;
if (strcmp(pass,"(NULL)")==0) pass = db_pass(user);
u = auth_find(user);
if (strcmp(pass,"(DELETE)")==0) dodel = TRUE;
if (u!=NULL) {
if (dodel) {
dmsg("debug: blanking user field {%s}\n",u->user);
strcpy(u->user,"");
return;
}
dmsg("debug: modified user {%s} passsword or details\n",u->user);
zstrfree(u->pass);
zstrfree(u->info);
u->pass = zstrdup(pass);
u->info = zstrdup(info);
return;
}
if (dodel) return;
dmsg("debug: adding slot for {%s}\n",user);
u = malloc(sizeof(User));
u->user = zstrdup(user);
u->pass = zstrdup(pass);
u->info = zstrdup(info);
h = str_hash(u->user,MAX_HASH);
u->next = users[h];
users[h] = u;
}
int f_size(FILE *f)
{
struct stat st;
fstat(fileno(f),&st);
return st.st_size;
}
void check_add(void)
{
FILE *f;
static int last_size;
int n=0;
char bf[BFSZ];
char user[BFSZ];
char pass[BFSZ];
char info[BFSZ];
char *s;
done_check_add=TRUE;
f = fopen(FILE_ADD,"r"); if (f==NULL) return;
if (f_size(f)==last_size) goto doreturn;
last_size = f_size(f);
/* Reread the file, and apply all changes */
for (;!feof(f);) {
if (fgets(bf,BFSZ-1,f)==NULL) break;
s = strtok(bf,":\n \t"); if (s==NULL) continue;
strlwr(s); /* Store usernames in lowercase */
ncpy(user,s,100);
s = strtok(NULL,":\n \t"); if (s==NULL) continue;
ncpy(pass,s,100);
s = strtok(NULL,"\n"); if (s==NULL) s = "";
ncpy(info,s,BFSZ-1);
n++;
auth_fixup(user,pass,info);
}
doreturn:
fclose(f);
}
char *str_encode(char *s)
{
char salt[BFSZ];
salt[0] = abs(rand() % 25) + 'a';
salt[1] = abs(rand() % 25) + 'a';
return crypt(s,salt);
}
char *value_encode(char *s)
{
static char bf[2000];
int i;
char *out=bf;
for (i=0; i<2000 && *s!=0;i++,s++) {
if (*s=='<') { strcpy(out,"<"); out += strlen(out); }
else if (*s=='>') { strcpy(out,">"); out += strlen(out); }
else if (*s=='&') { strcpy(out,"&"); out += strlen(out); }
else *out++ = *s;
}
*out++ = 0;
return bf;
}
int auth_set(char *user, char *pass, char *info)
{
/* Append to file */
FILE *f;
int rebuild = FALSE;
check_add(); /* Check for new/changed entries */
imsg("auth_set(%s,xxxx)\n",user);
f = fopen(FILE_NWAUTH,"r");
if (f!=NULL) fclose(f);
else {
f = fopen(FILE_NWAUTH,"w");
if (f!=NULL) fclose(f);
}
f = fopen(FILE_ADD,"a");
if (f==NULL) {
emsg("-ERR Could not append to %s %s\n",FILE_NWAUTH,strerror(errno));
return FALSE;
}
if (strcmp(pass,"(NULL)")==0) pass = db_pass(user);
else pass = str_encode(pass);
fprintf(f,"%s:%s:%s\n",user,pass,info);
auth_fixup(user,pass,info);
myprintf("+OK %s added to database\n",user);
if (rebuild_size<1) rebuild_size=DFLT_REBUILD_SIZE;
if (f_size(f)>rebuild_size) rebuild = TRUE;
fclose(f);
if (rebuild) {
remove(FILE_ADD);
auth_rebuild();
}
return TRUE;
}
int auth_set_old(char *user, char *pass, char *info)
{
/* Append to file */
FILE *f;
imsg("auth_set(%s,%s)\n",user,pass);
if (strcmp(pass,"(NULL)")==0) pass = db_pass(user);
else pass = str_encode(pass);
auth_del(user, TRUE);
f = fopen(FILE_NWAUTH,"a");
if (f==NULL) {
emsg("-ERR Could not append to %s %s\n",FILE_NWAUTH,strerror(errno));
return FALSE;
}
fprintf(f,"%s:%s:%s\n",user,pass,info);
myprintf("+OK %s added to database\n",user);
fclose(f);
return TRUE;
}
int auth_exists(char *user)/*used by wadduser to check if a user already
exists*/
{
char bf[1000];
if (db_check(user,NULL,bf)) return TRUE;
return FALSE;
}
int db_check(char *user, char *pass, char *info)
{
/* Use index to look up user */
char userlc[BFSZ];
int h;
User *u;
if (!done_build_index) build_index();
if (!done_check_add) check_add();
if (pass==NULL)
imsg("db_check(%s,'NULL')\n",user,pass);
else
imsg("db_check(%s,xxxx)\n",user);
strcpy(userlc,user);
strlwr(userlc);
h = str_hash(userlc,MAX_HASH);
for (u=users[h];u!=NULL;u=u->next) {
if (strcmp(u->user,userlc)==0) {
strncpy(info,u->info,BFSZ-1);
info[BFSZ-1] = 0;
if (pass==NULL) { return TRUE;}
if (strcmp(u->pass,crypt(pass,u->pass))==0) return TRUE;
imsg("Password wrong (%s) (%s)!=(%s)\n",user,u->pass,pass);
return FALSE;
}
}
imsg("User not found (%s)\n",user);
return FALSE;
}
User *auth_find(char *user)
{
/* Use index to look up user */
char userlc[BFSZ];
int h;
User *u;
strcpy(userlc,user);
strlwr(userlc);
h = str_hash(userlc,MAX_HASH);
for (u=users[h];u!=NULL;u=u->next) {
if (strcmp(u->user,userlc)==0) {
return u;
}
}
return NULL;
}
char * db_pass(char *user)
{
/* Use index to look up user */
char userlc[BFSZ];
int h;
User *u;
strcpy(userlc,user);
strlwr(userlc);
h = str_hash(userlc,MAX_HASH);
for (u=users[h];u!=NULL;u=u->next) {
if (strcmp(u->user,userlc)==0) {
return u->pass;
}
}
return "none";
}
int auth_del(char *user, int silent)
{
/* Append to file */
FILE *f;
imsg("auth_del(%s,%d)\n",user,silent);
f = fopen(FILE_ADD,"a");
if (f==NULL) {
emsg("-ERR Could not append to %s %s\n",FILE_NWAUTH,strerror(errno));
return FALSE;
}
fprintf(f,"%s:(DELETE):(DELETE)\n",user);
auth_fixup(user,"(DELETE)","(DELETE)");
if (!silent) myprintf("+OK Deleted user successfully\n");
fclose(f);
return TRUE;
}
int auth_rebuild(void)
{
/* write new file, rename. */
FILE *fout;
char fname[BFSZ];
int ndel = 0;
int i;
int n=0;
User *u;
strcpy(fname,FILE_NWAUTH);
fout = fopen(FILE_TMP,"w");
if (fout==NULL) {
emsg("Unable to open %s, %s\n",FILE_TMP,strerror(errno));
return FALSE;
}
for (i=0; inext) {
if (strlen(u->user)>0) {
if (fprintf(fout,"%s:%s:%s\n",u->user,u->pass,u->info)<=0) goto failed;
n++;
}
}
}
fclose(fout);
if (remove(fname)!=0) emsg("-ERR remove of %s failed %s\n",fname,strerror(errno));
if (rename(FILE_TMP,fname)) emsg("-ERR rename of %s failed %s\n",fname,strerror(errno));
return TRUE;
failed:
emsg("-ERR Error writing new file %s\n",strerror(errno));
fclose(fout);
return FALSE;
}
int str_hash(char *s, int max)
{
int total=0;
int r;
int i;
for (i=0;*s!=0;s++,i++) {
total += ((*s) * 8)*i;
}
r = total % max;
if (r<0) return -r;
return r;
}
#ifndef EXTERNAL_LOG
void emsg(char * arg_list, ...)
{
va_list arg_ptr;
char *format;
char output[2000];
int len;
va_start(arg_ptr, arg_list);
format = arg_list;
len = vsprintf(output, format, arg_ptr);
myprintf("%s",output);
log_file(output);
}
void imsg(char * arg_list, ...)
{
va_list arg_ptr;
char *format;
char output[2000];
int len;
va_start(arg_ptr, arg_list);
format = arg_list;
len = vsprintf(output, format, arg_ptr);
if (isdebug) {
myprintf("%s",output);
log_file(output);
}
else if (islog) {
log_file(output);
}
}
void log_file(char *s)
{
FILE *f;
time_t stamp;
char bf[BFSZ];
char *p;
if (!islog && !isdebug)
f = fopen(file_config("nwauth.log"),"w");/*log last error only*/
else
f = fopen(file_config("nwauth.log"),"a");
if (f==NULL) return;
/*fprintf(f,"%s",s);
fclose(f);*/
time(&stamp);
strcpy(bf,ctime(&stamp));
if ((p=strchr(bf,'\n'))!=NULL) *p=0;/*chop off cr*/
fprintf(f,"%d %s %s",pid,bf,s);
fclose(f);
}
#endif
#ifdef WIN32
char *crypt(char *key, char *salt)
{
/* One way encryption of key using salt to perterb */
/* This function is only intended to make stealing passwords difficult, the password file should still be protected */
static char result[BFSZ];
int i;
int start = salt[0] + salt[1]*255;
result[0] = salt[0];
result[1] = salt[1];
for (i=0; i<(int) strlen(key); i++) {
result[i+2] = ((key[i] * (start+1)) % 40) + 'A';
start += key[i];
start *= 3;
start = start % 32000;
}
result[strlen(key)+2] = 0;
return result;
}
#endif
#ifndef WIN32
char *strlwr(char *s)
{
char *ss=s;
for (;*s!=0;s++) if (isupper(*s)) if (*s>0) *s = tolower(*s);
return ss;
}
#endif
typedef struct MLIST {char *data; struct MLIST *next;} Mlist;
static int zleft,zupto;
static Mlist *mlist,*mcur;
char *zmalloc(int sz)
{
Mlist *m;
char *s;
if (sz>=zleft) {
m = malloc(sizeof(Mlist));
m->data = malloc(10000);
zleft = 10000;
zupto = 0;
m->next = NULL;
if (mcur==NULL) {
mlist = mcur = m;
} else {
mcur->next = m;
mcur = m;
}
}
s = mcur->data + zupto;
zupto += sz;
zleft -= sz;
return s;
}
char *zstrdup(char *s)
{
char *n;
n = zmalloc(strlen(s)+1);
strcpy(n,s);
return n;
}
void zstrfree(char *s)
{
/* Do nothing */
}
void zfreeall(void)
{
Mlist *m,*mnext;
for (m=mlist;m!=NULL;m=mnext) {
mnext = m->next;
free(m->data);
free(m);
}
mlist = NULL;
mcur = NULL;
zleft = 0;
zupto = 0;
}
static char *ncpy(char *dst, char *src, int len)
{
char *xdst = dst;
int xlen = len;
for (;(*src !=0) && (len>0); ) {*dst++ = *src++; len--;}
*dst++ = 0;
xdst[xlen] = 0;
return xdst;
}
static const unsigned char charmap[] = {
0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027,
0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037,
0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047,
0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057,
0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077,
0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137,
0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177,
0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377
};
int zstrcmpnc(char *s1, char *s2) {
const unsigned char *cm = charmap,
*us1 = (const unsigned char *)s1,
*us2 = (const unsigned char *)s2;
while (cm[*us1] == cm[*us2++])
if (*us1++ == '\0')
return (0);
return (cm[*us1] - cm[*--us2]);
}
int zstrncmpnc(char *s1, char *s2, int n) {
const unsigned char *cm = charmap,
*us1 = (const unsigned char *)s1,
*us2 = (const unsigned char *)s2;
while (cm[*us1] == cm[*us2++]) {
if (*us1++ == '\0') return (0);
n--;
if (n<=0) return 0;
}
return (cm[*us1] - cm[*--us2]);
}
char *zstrstrnc(char *s1, char *s2)
{
const unsigned char *cm = charmap;
char *s;
int n = strlen(s2);
for (s=s1;*s!=0;s++) {
if (zstrncmpnc(s,s2,n)==0) return s;
}
return NULL;
}