home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1999 March B
/
SCO_CASTOR4RRT.iso
/
nsfast
/
root.9
/
usr
/
ns-home
/
extras
/
database
/
changepw.c
/
changepw
Wrap
Text File
|
1998-08-19
|
11KB
|
397 lines
/*
* Copyright (c) 1994, 1995, 1996. Netscape Communications Corporation.
* All rights reserved.
*
* Use of this software is governed by the terms of the license agreement
* for the Netscape Enterprise or Netscape Personal Server between the
* parties.
*
*/
/* ------------------------------------------------------------------------ */
/*
* changepw - Allow a user to change his password. See also changepw.html.
*
*/
#define BIG_LINE 1024
/*
* #define's you may want to change
*/
/* Define SERVER_ROOT to be the path for your server root directory. */
#define SERVER_ROOT "/usr/ns-home"
/*
* The default database to try. You can define this if you don't want to
* use a hidden form element on the page (and would rather keep the database
* name in the binary.
*
* Remember *not* to use a filename extension - just the file name, no .dir
* or .pag on there.
*/
/* #define DEFAULT_DB "/usr/ns-home/authdb/default" */
/* The text reported to the user upon errors. */
#define NO_DATABASE "Could not determine which database to use."
#define USER_NOT_FOUND "Could not find the user <b>%s</b> in the database."
#define BAD_PASSWORD "Your old password is incorrect. Please reenter it."
#define DBM_ERROR_INSERTING \
"An error occurred while trying to add your new password."
#define DBM_WONT_OPEN "An error occurred while trying to open the database."
#define CANT_VERIFY_PW "An error occurred while trying to verify your password."
#define CANT_CHANGE_PW "An error occurred while trying to change your password."
/* Errors when the user didn't give enough info. */
#define NO_SVRROOT \
"The server root is not available. Please modify the form or changepw to provide it."
#define NO_USERNAME \
"Could not determine your username. Please enter it on the form provided."
#define NO_OLDPW "You need to enter your old password for verification."
#define NO_PASSWORD "Be sure to enter your password."
#define NO_MATCH \
"The new passwords you gave did not match. Please enter them again."
/* Yay, it worked */
#define VICTORY_MSG \
"Your password has been changed. The change should take effect immediately."
/* Prototypes and includes ---------------------------------------------- */
/* ---------------------------------------------------------------------- */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <fcntl.h>
#include <ctype.h>
/* Form handling functions. */
static char **input;
void report_error(char *error);
void form_unescape(char *str);
void post_begin(FILE *in);
char **string_to_vec(char *in);
char *get_cgi_var(char *varname);
char *escape_for_shell(char *cmd);
/* crypt() functions for encrypting and comparing the password. */
char *crypt(const char *key, const char *salt);
char *pw_enc(char *pw);
int pw_cmp(char *pw, char *enc);
/* Database manipulation routines -------------------------------------- */
/* --------------------------------------------------------------------- */
/* The command to send to verify a database */
#define VERIFY_CMD "%s/extras/database/shuser %s %s"
void verify_password(char * svrroot, char *db, char *user, char *pw)
{
/* Escape all shell-specific characters before we execute
* the local program, and encrypt the password.
*/
char *escroot=escape_for_shell(svrroot);
char *escdb=escape_for_shell(db);
char *escuser=escape_for_shell(user);
char *t=NULL;
char *dbpw=NULL;
char *cmd=(char *)malloc(strlen(VERIFY_CMD)+
strlen(escroot)+
strlen(escuser)+
strlen(escdb)+2);
FILE *c;
char buf[1024];
sprintf(cmd, VERIFY_CMD, escroot, escuser, escdb);
if( !(c=popen(cmd, "r")) )
report_error(CANT_VERIFY_PW);
while(fgets(buf, 1024, c)) {
if(!strncmp(buf, "Password:", strlen("Password:"))) {
t = buf+(strlen("Password:"));
while(isspace(*t)) t++;
(void) strtok(t, "\r\n:");
dbpw=strdup(t);
}
}
pclose(c);
if(!dbpw) report_error(CANT_VERIFY_PW);
if(pw_cmp(pw, dbpw)) report_error(BAD_PASSWORD);
}
/* The command to send to verify a database */
#define CHANGE_CMD "%s/extras/database/chuser -p %s %s %s 2>&1"
void change_password(char * svrroot, char *db, char *user, char *password)
{
/* Escape all shell-specific characters before we execute
* the local program, and encrypt the password.
*/
char *escroot=escape_for_shell(svrroot);
char *escdb=escape_for_shell(db);
char *escuser=escape_for_shell(user);
char *cpw=pw_enc(password);
char *cmd=(char *) malloc(strlen(CHANGE_CMD)+
strlen(escroot)+
strlen(cpw)+
strlen(escuser)+
strlen(escdb)+2);
FILE *c;
char buf[1024];
sprintf(cmd, CHANGE_CMD, escroot, cpw, escuser, escdb);
if( !(c=popen(cmd, "r")) )
report_error(CANT_VERIFY_PW);
while(fgets(buf, 1024, c)) {
char *t=strchr(buf, ':');
if(!t) continue;
*t++='\0';
if(isspace(*t)) *t++='\0';
if(strncmp(t, "user ", strlen("user "))) {
report_error(CANT_CHANGE_PW);
}
}
pclose(c);
return;
}
/* Interpret the form and do the change. ---------------------------------- */
/* ------------------------------------------------------------------------ */
int main(int argc, char *argv[])
{
char *m = getenv("REQUEST_METHOD");
fprintf(stdout, "Content-type: text/html\n\n");
if(!strcmp(m, "GET")) {
report_error("You should only use the POST method with this program.");
} else {
char *database;
char *user;
char *old_pw;
char *new_pw1;
char *new_pw2;
char *svrroot;
post_begin(stdin);
#ifndef SERVER_ROOT
svrroot = get_cgi_var("svrroot");
if (!svrroot) {
report_error(NO_SVRROOT);
}
#else
svrroot = strdup(SERVER_ROOT);
#endif
database = get_cgi_var("database");
if(!database) {
#ifdef DEFAULT_DB
database = strdup(DEFAULT_DB);
#else
report_error(NO_DATABASE);
#endif
}
user = get_cgi_var("user");
if(!user) {
user = getenv("REMOTE_USER");
if(!user)
report_error(NO_USERNAME);
}
old_pw = get_cgi_var("old_pw");
if(!old_pw)
report_error(NO_OLDPW);
new_pw1 = get_cgi_var("new_pw1");
if(!new_pw1)
report_error(NO_PASSWORD);
new_pw2 = get_cgi_var("new_pw2");
if(!new_pw2)
report_error(NO_PASSWORD);
if(strcmp(new_pw1, new_pw2))
report_error(NO_MATCH);
verify_password(svrroot, database, user, old_pw);
change_password(svrroot, database, user, new_pw1);
fprintf(stdout,
"<hr width=50%%><h1 align=center>Success!</h1><hr width=50%%>\n");
fprintf(stdout,"<p align=center>%s</p>\n", VICTORY_MSG);
}
return 0;
}
/* Form handling happiness ------------------------------------------------ */
/* ------------------------------------------------------------------------ */
/* Tell the user about an unfortunate occurrence. */
void report_error(char *error)
{
fprintf(stdout, "<hr size=3><h1 align=center>Error</h1><hr size=3>\n");
fprintf(stdout, "<b>Error:</b>%s\n", error);
exit(1);
}
/* Unescape the %xx variables as they're sent in. */
void form_unescape(char *str)
{
register int x = 0, y = 0;
int l = strlen(str);
char digit;
while(x < l) {
if((str[x] == '%') && (x < (l - 2))) {
++x;
digit = (str[x] >= 'A' ?
((str[x] & 0xdf) - 'A')+10 : (str[x] - '0'));
digit *= 16;
++x;
digit += (str[x] >= 'A' ?
((str[x] & 0xdf) - 'A')+10 : (str[x] - '0'));
str[y] = digit;
}
else if(str[x] == '+') {
str[y] = ' ';
} else {
str[y] = str[x];
}
x++;
y++;
}
str[y] = '\0';
}
/* Read in the variables from stdin, unescape them, and then put them in
* the static vector. */
void post_begin(FILE *in)
{
char *vars = NULL, *tmp = NULL;
int cl;
if(!(tmp = getenv("CONTENT_LENGTH")))
report_error("Your browser sent no content length with a POST command."
" Please be sure to use a fully compliant browser.");
cl = atoi(tmp);
vars = (char *)malloc(cl+1);
if( !(fread(vars, 1, cl, in)) )
report_error("The POST variables could not be read from stdin.");
vars[cl] = '\0';
input = string_to_vec(vars);
}
/* Convert the input from stdin to a usable variable vector. */
char **string_to_vec(char *in)
{
char **ans;
int vars = 0;
register int x = 0;
char *tmp;
while(in[x])
if(in[x++]=='=')
vars++;
ans = (char **) malloc((sizeof(char *)) * (vars+1));
x=0;
tmp = strtok(in, "&");
ans[x]=strdup(tmp);
form_unescape(ans[x++]);
while((tmp = strtok(NULL, "&"))) {
ans[x] = strdup(tmp);
form_unescape(ans[x++]);
}
return(ans);
}
/* Return the value of a POSTed variable, or NULL if none was sent. */
char *get_cgi_var(char *varname)
{
register int x = 0;
int len = strlen(varname);
char *ans = NULL;
while(input[x]) {
/* We want to get rid of the =, so len, len+1 */
if((!strncmp(input[x], varname, len)) && (*(input[x]+len) == '=')) {
ans = strdup(input[x] + len + 1);
if(!strcmp(ans, ""))
ans = NULL;
break;
} else
x++;
}
return ans;
}
/* Escape any shell-specific characters with a "\" */
char *escape_for_shell(char *cmd) {
register int x,y,l;
char *ans=(char *)malloc(2*strlen(cmd)+2);
strcpy(ans, cmd);
l=strlen(ans);
for(x=0;ans[x];x++) {
if(strchr(" &;`'\"|*!?~<>^()[]{}$\\",ans[x])){
for(y=l+1;y>x;y--)
ans[y] = ans[y-1];
l++; /* length has been increased */
ans[x] = '\\';
x++; /* skip the character */
}
}
return ans;
}
/* Dealing with password encryption --------------------------------------- */
/* ------------------------------------------------------------------------ */
static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
/* Encrypt a password. */
char *pw_enc(char *pw)
{
char *cpw, salt[3];
long v;
srand((int)time(NULL));
v = rand();
salt[0] = itoa64[v & 0x3f];
v >>= 6;
salt[1] = itoa64[v & 0x3f];
cpw = crypt(pw, salt);
return cpw;
}
/* Compare an unencrypted password (pw) to an encrypted version, and return
* 1 if they match. */
int pw_cmp(char *pw, char *enc)
{
char *cpw = crypt(pw, enc); /* use salt from enc */
return strcmp(enc, cpw);
}