Wadduser - Example Web User Administration

Wadduser is Netwin's example Web based User Administration Program.

NOTE: This has been replaced and improved considerably by NetAuth, which is also free with DMail. Please see, Setting Up a Web Based Email System with Auto Account Creation.

We have created this product primarily as an add on to our example External Authentication Module, NWAuth in order to allow people to set up a Hotmail-type system, where users can add themselves and choose an email address for a web based email system.

Note: We have now created a new product which is a replacement for wadduser, which is just as customisable, has more functionality, and does not require as much setup. It is called NetAuth, and is free with DMail. See the following overview for more details,
Users Adding Themselves - like Hotmail

Wadduser is linked to NWAuth at build time and, as such, is an extended NWAuth program which runs as a CGI.

On Windows platforms you will find nwauth.exe and wadduser.exe precompiled for immediate use in the distribution set which you download.

The Wadduser CGI is run from a normal web page, an example of which is provided in distribution sets on all platforms, wadduser.htm.

NB: You should modify wadduser.htm before use, in order to remove options which you will not want users to be able to do, e.g delete each other's accounts! :-) Click on this link to see an example wadduser page

For details on implementing Wadduser you should look at the following FAQs...
Technical setup details (How do I set up a 'Hotmail' type system?)
Adding fields to wadduser

Note: Because wadduser is linked into NWAuth, if you ever upgrade NWAuth you should also upgrade wadduser to the same version.

Below is the source for Wadduser - see the file wadduser.c in your distribution set for the source applicable to your build of wadduser.


/*
See the instructions on
https://netwinsite.com/dmail/faq.htm

Basic CGI program which allows users to be added/removed/searched

If using this for users to register themselves, you should remove the web_del function.

External functions (in nwauth.c), compile nwauth.c with NOAUTHMAIN defined

int auth_exists(char *user);
int auth_set(char *user, char *pass, char *info);
int auth_del(char *user, int quiet);
void auth_search(char *user);
*/


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#ifdef WIN32

#include <io.h>
#endif
#include <fcntl.h>

#ifndef TRUE
#define FALSE 0
#define TRUE (!FALSE)
#endif
#define BFSZ 300

char *lib_encode(char *kkkk);
char *value_encode(char *s);
char *mygetenv(char *v);
char *query_find(char *s);
int ispressed(char *s);
int query_get(void);
void getword(char *word, char *line, char stop) ;
char x2c(char *what) ;
char *email_name(char *email);
void unescape_url(char *url) ;
void plustospace(char *str) ;
void form_get(void);
int web_delete(void);
char *form_find(char *s);
char *ncpy(char *dst, char *src, int len);
int web_search(void);
void do_header(char *title);
int web_add(void);
void do_footer(void);
#include "nwauth.h"
char thisuser[200];
char method[200];
char *get_date(void);


int check_value(char *descr, char *symbol, char *dflt);
int main(int argc, char *argv[])
{
strcpy(thisuser,mygetenv("REMOTE_USER"));
strcpy(method,mygetenv("REQUEST_METHOD"));
form_get();
auth_init(); /* Init the NWAuth functions */
if (ispressed("web_add")) web_add();
else if (ispressed("web_search")) web_search();
else if (ispressed("web_delete")) web_delete();
else web_add();
return 0;
}
void showfile(char *fname)
{
FILE *f;
char bf[BFSZ];
f = fopen(fname,"r");
if (f==NULL) return;
for (;!feof(f);) {
if (fgets(bf,BFSZ-1,f)==NULL) break;
printf("%s",bf);
}
fclose(f);
}
int web_add(void)
{
FILE *f;
char username[BFSZ],password[BFSZ],name[BFSZ];
char bf[BFSZ];
/* Check the user has filled in the required fields */
if (!check_value("Name","name","")) return 0;
if (!check_value("Username","username","")) return 0;
if (!check_value("Password","password","")) return 0;

f = fopen("adduser.log","a");
if (f==NULL) { printf("Could not write file\n"); return 0;}
fprintf(f,"%s|Add|",get_date());
fprintf(f,"%s|",mygetenv("REMOTE_ADDR"));
fprintf(f,"%s|",form_find("username"));
fprintf(f,"%s|",form_find("name"));
/* These are optional form elements to record */
fprintf(f,"%s|",form_find("phone"));
fprintf(f,"%s|",form_find("fax"));
fprintf(f,"%s|",form_find("comments"));
fprintf(f,"\n");
fclose(f);

ncpy(username,form_find("username"),BFSZ-1);
ncpy(password,form_find("password"),BFSZ-1);
ncpy(name,form_find("name"),BFSZ-1);

strlwr(username); /* Only allow lower case usernames */
do_header("Adding user");
printf("<pre>");
if (auth_exists(username)) {
printf("Sorry, a user by that name already exists\n");
} else {
sprintf(bf,"name=\"%s\"",name);
auth_set(username,password,bf);
showfile("added.htm");
}
printf("</pre>");
do_footer();
return 0;
}

int web_delete(void)
{
FILE *f;
char username[BFSZ];
/* Check the user has filled in the required fields */
if (!check_value("Username","username","")) return 0;

f = fopen("adduser.log","a");
if (f==NULL) { printf("Could not write file\n"); return 0;}
fprintf(f,"%s|Delete",get_date());
fprintf(f,"%s|",mygetenv("REMOTE_ADDR"));
fprintf(f,"%s|",form_find("username"));
fprintf(f,"\n");
fclose(f);

ncpy(username,form_find("username"),BFSZ-1);

strlwr(username); /* Only allow lower case usernames */
do_header("Deleting user");
printf("<pre>");
auth_del(username,FALSE);
printf("</pre>");
do_footer();
return 0;
}
int web_search(void)
{
char search[BFSZ];
/* Check the user has filled in the required fields */
if (!check_value("Search string","search","")) return 0;

ncpy(search,form_find("search"),BFSZ-1);
do_header("Search complete");
printf("<pre>");
auth_search(search);
printf("</pre>");
do_footer();
return 0;
}


/*--------- Worker routines -------------------------------------*/

void do_header(char *title)
{
printf("Content-type: text/html\n\n");
printf("<html>\n");
printf("<head>\n");
printf("<title>%s</title>\n",title);
printf("</head>\n");
printf("<body>\n<h3>%s</h3>\n",title);
}
void do_footer(void)
{
printf("</body>\n");
}

int check_value(char *descr, char *symbol, char *dflt)
{
if (strcmp(form_find(symbol),dflt)==0) {
fail:
do_header("Required field missing");
printf("Sorry, you must fill in all fields, you missed out <b>(%s)</b><p>\n",descr);
printf("Please click on 'back' and fill in the other fields, thanks.<p>\n");
do_footer();
return FALSE;
}
if (strcmp(symbol,"email")==0) if (strchr(form_find(symbol),'@')==NULL) goto fail;
return TRUE;
}

/* ------------------ library of stuff for web --------------------*/
char *get_date(void)
{
time_t t;
static char tstr[30];
t = time(NULL);
strcpy(tstr,ctime(&t));
tstr[13] = 0;
return tstr;
}

static char *query_name[1000];
static char *query_val[1000];
static int nquery;
/* Query string */
char *lib_encode(char *s)
{
char *ss=s;
for (;*s!=0;s++) {
if (isspace(*s)) *s = '+';
}
return ss;
}
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;
}


char *mygetenv(char *v)
{
char *s = getenv(v);
if (s==NULL) return "";
return s;
}
char *query_find(char *s)
{
int i;
for (i=0; i<nquery; i++) if (strcmp(query_name[i],s)==0) return query_val[i];
return "";
}
int query_get(void)
{
char *q;
char *cl;
char bf[10000],val[2000],name[BFSZ];
int x;

q = mygetenv("QUERY_STRING");
if (q==NULL) return FALSE;
strcpy(bf,q); cl = bf;
for(x=0;cl[0] != '\0';x++) {
getword(val,cl,'&');
plustospace(val);
unescape_url(val);
getword(name,val,'=');
query_name[x] = strdup(name);
query_val[x] = strdup(val);
/*printf("[%d] {%s} = {%s} \n",x,query_name[x],query_val[x]);*/
}
nquery = x;
return TRUE;
}
void getword(char *word, char *line, char stop)
{
int x = 0,y;

for(x=0;((line[x]) && (line[x] != stop));x++)
word[x] = line[x];

word[x] = '\0';
if(line[x]) ++x;
y=0;

while(line[y++] = line[x++]);
}
char x2c(char *what)
{
register char digit;

digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
digit *= 16;
digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));
return(digit);
}

void unescape_url(char *url)
{
register int x,y;

for(x=0,y=0;url[y];++x,++y) {
if((url[x] = url[y]) == '%') {
url[x] = x2c(&url[y+1]);
y+=2;
}
}
url[x] = '\0';
}

void plustospace(char *str)
{
register int x;

for(x=0;str[x];x++) if(str[x] == '+') str[x] = ' ';
}


static char *form_name[1000];
static char *form_val[1000];
static int nform;
char *makeword(char *line, char stop) ;
char *fmakeword(FILE *f, char stop, int *cl);
void convert_crlf(char *s); /* turn crlf into lf's */
void form_get(void)
{
int x,cl;
char *s = mygetenv("CONTENT_LENGTH");
if (s==NULL) return;
cl = atoi(s);
for(x=0;cl && (!feof(stdin));x++) {
form_val[x]= fmakeword(stdin,'&',&cl);
plustospace(form_val[x]);
unescape_url(form_val[x]);
form_name[x] = makeword(form_val[x],'=');
convert_crlf(form_val[x]);
}
nform = x;
}
void convert_crlf(char *s)
{
char *out=s;
for (;*s!=0;s++) {
if (*s == '\015') s++;
*out++ = *s;
}
*out++ = 0;
}
char *makeword(char *line, char stop)
{
int x = 0,y;
char *word = (char *) malloc(sizeof(char) * (strlen(line) + 1));

for(x=0;((line[x]) && (line[x] != stop));x++)
word[x] = line[x];

word[x] = '\0';
if(line[x]) ++x;
y=0;

while(line[y++] = line[x++]);
return word;
}

char *fmakeword(FILE *f, char stop, int *cl)
{
int wsize;
char *word;
int ll;

wsize = 8024;
ll=0;
word = (char *) malloc(sizeof(char) * (wsize + 1));

while(1) {
word[ll] = (char)fgetc(f);
if(ll==wsize) {
word[ll+1] = '\0';
wsize+=8024;
word = (char *)realloc(word,sizeof(char)*(wsize+1));
}
--(*cl);
if((word[ll] == stop) || (feof(f)) || (!(*cl))) {
if(word[ll] != stop) ll++;
word[ll] = '\0';
return word;
}
++ll;
}
}


char *form_find(char *s)
{
int i;
for (i=0; i<nform; i++) if (strcmp(form_name[i],s)==0) return form_val[i];
return "";
}
char *form_find_i(char *s, int i)
{
char bf[BFSZ];
sprintf(bf,"%s%d",s,i); s = bf;
for (i=0; i<nform; i++) if (strcmp(form_name[i],s)==0) return form_val[i];
return "";
}

char *email_name(char *email)
{
static char bf[BFSZ];
char *s2;
char *s;
s = strchr(email,'(');
if (s!=NULL) {
strcpy(bf,s+1);
s = strchr(bf,')');
if (s!=NULL) *s = 0;
}
ncpy(bf,email,BFSZ-1);
s = strchr(bf,'@');
s2 = strchr(bf,' ');
if (s==NULL) s = s2;
if (s2!=NULL) if (s2<s) s = s2;
if (s!=NULL) *s = 0;
return bf;
}



char *towww(char *s)
{
static char bf[BFSZ],*out;
for (out=bf;*s!=0;s++) {
if (isspace(*s)) *s = '+';
if (*s=='+') {sprintf(out,"%%%x",*s); out += strlen(out);}
else if (*s=='&') {sprintf(out,"%%%x",*s); out += strlen(out);}
else *out++ = *s;
}
*out++ = 0;
return bf;
}
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;
}
int ispressed(char *s)
{
char bf[BFSZ];
if (strlen(form_find(s))>0) {
return TRUE;
}
sprintf(bf,"%s.x",s);
if (strlen(form_find(bf))>0) {
return TRUE;
}

return FALSE;
}