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
Text File  |  1998-08-19  |  11KB  |  397 lines

  1. /*
  2.  * Copyright (c) 1994, 1995, 1996.  Netscape Communications Corporation.
  3.  * All rights reserved.
  4.  * 
  5.  * Use of this software is governed by the terms of the license agreement
  6.  * for the Netscape Enterprise or Netscape Personal Server between the
  7.  * parties.
  8.  *
  9.  */
  10.  
  11.  
  12. /* ------------------------------------------------------------------------ */
  13.  
  14.  
  15. /* 
  16.  * changepw - Allow a user to change his password.  See also changepw.html.
  17.  *
  18.  */
  19.  
  20. #define BIG_LINE 1024
  21.  
  22. /*
  23.  * #define's you may want to change
  24.  */
  25.  
  26. /* Define SERVER_ROOT to be the path for your server root directory. */
  27. #define SERVER_ROOT "/usr/ns-home"
  28.  
  29. /*
  30.  * The default database to try.  You can define this if you don't want to 
  31.  * use a hidden form element on the page (and would rather keep the database
  32.  * name in the binary.
  33.  *
  34.  * Remember *not* to use a filename extension - just the file name, no .dir
  35.  * or .pag on there.
  36.  */
  37. /* #define DEFAULT_DB "/usr/ns-home/authdb/default" */
  38.  
  39. /* The text reported to the user upon errors. */
  40. #define NO_DATABASE "Could not determine which database to use."
  41. #define USER_NOT_FOUND "Could not find the user <b>%s</b> in the database."
  42. #define BAD_PASSWORD "Your old password is incorrect.  Please reenter it."
  43. #define DBM_ERROR_INSERTING \
  44.           "An error occurred while trying to add your new password."
  45. #define DBM_WONT_OPEN "An error occurred while trying to open the database."
  46. #define CANT_VERIFY_PW "An error occurred while trying to verify your password."
  47. #define CANT_CHANGE_PW "An error occurred while trying to change your password."
  48.  
  49. /* Errors when the user didn't give enough info. */
  50. #define NO_SVRROOT \
  51.    "The server root is not available.  Please modify the form or changepw to provide it."
  52. #define NO_USERNAME \
  53.    "Could not determine your username.  Please enter it on the form provided."
  54. #define NO_OLDPW "You need to enter your old password for verification."
  55. #define NO_PASSWORD "Be sure to enter your password."
  56. #define NO_MATCH \
  57.        "The new passwords you gave did not match.  Please enter them again."
  58.  
  59. /* Yay, it worked */
  60. #define VICTORY_MSG \
  61.   "Your password has been changed.  The change should take effect immediately."
  62.  
  63.  
  64. /* Prototypes and includes ---------------------------------------------- */
  65. /* ---------------------------------------------------------------------- */
  66.  
  67. #include <stdio.h>
  68. #include <stdlib.h>
  69. #include <string.h>
  70. #include <errno.h>
  71. #include <sys/types.h>
  72. #include <fcntl.h>
  73. #include <ctype.h>
  74.  
  75. /* Form handling functions. */
  76. static char **input;
  77.  
  78. void report_error(char *error);
  79. void form_unescape(char *str);
  80. void post_begin(FILE *in);
  81. char **string_to_vec(char *in);
  82. char *get_cgi_var(char *varname);
  83. char *escape_for_shell(char *cmd);
  84.  
  85. /* crypt() functions for encrypting and comparing the password. */
  86. char *crypt(const char *key, const char *salt);
  87. char *pw_enc(char *pw);
  88. int pw_cmp(char *pw, char *enc);
  89.  
  90.  
  91. /* Database manipulation routines -------------------------------------- */
  92. /* --------------------------------------------------------------------- */
  93.  
  94. /* The command to send to verify a database */
  95. #define VERIFY_CMD "%s/extras/database/shuser %s %s"
  96. void verify_password(char * svrroot, char *db, char *user, char *pw)
  97. {
  98.     /* Escape all shell-specific characters before we execute 
  99.      * the local program, and encrypt the password. 
  100.      */
  101.     char *escroot=escape_for_shell(svrroot);
  102.     char *escdb=escape_for_shell(db);
  103.     char *escuser=escape_for_shell(user);
  104.     char *t=NULL;
  105.     char *dbpw=NULL;
  106.     
  107.     char *cmd=(char *)malloc(strlen(VERIFY_CMD)+
  108.                              strlen(escroot)+
  109.                              strlen(escuser)+
  110.                              strlen(escdb)+2);
  111.     FILE *c;
  112.     char buf[1024];
  113.  
  114.     sprintf(cmd, VERIFY_CMD, escroot, escuser, escdb);
  115.     if( !(c=popen(cmd, "r")) )
  116.         report_error(CANT_VERIFY_PW);
  117.     while(fgets(buf, 1024, c))  {
  118.         if(!strncmp(buf, "Password:", strlen("Password:")))  {
  119.             t = buf+(strlen("Password:"));
  120.             while(isspace(*t)) t++;
  121.             (void) strtok(t, "\r\n:");
  122.             dbpw=strdup(t);
  123.         }
  124.     }
  125.     pclose(c);
  126.     if(!dbpw) report_error(CANT_VERIFY_PW);
  127.     if(pw_cmp(pw, dbpw)) report_error(BAD_PASSWORD);
  128. }
  129.  
  130. /* The command to send to verify a database */
  131. #define CHANGE_CMD "%s/extras/database/chuser -p %s %s %s 2>&1"
  132. void change_password(char * svrroot, char *db, char *user, char *password)
  133. {
  134.     /* Escape all shell-specific characters before we execute 
  135.      * the local program, and encrypt the password. 
  136.      */
  137.     char *escroot=escape_for_shell(svrroot);
  138.     char *escdb=escape_for_shell(db);
  139.     char *escuser=escape_for_shell(user);
  140.     char *cpw=pw_enc(password);
  141.  
  142.     char *cmd=(char *) malloc(strlen(CHANGE_CMD)+
  143.                               strlen(escroot)+
  144.                               strlen(cpw)+
  145.                               strlen(escuser)+
  146.                               strlen(escdb)+2);
  147.  
  148.     FILE *c;
  149.     char buf[1024];
  150.  
  151.     sprintf(cmd, CHANGE_CMD, escroot, cpw, escuser, escdb);
  152.     if( !(c=popen(cmd, "r")) )
  153.         report_error(CANT_VERIFY_PW);
  154.     while(fgets(buf, 1024, c))  {
  155.         char *t=strchr(buf, ':');
  156.         if(!t) continue;
  157.         *t++='\0';
  158.         if(isspace(*t)) *t++='\0';
  159.         if(strncmp(t, "user ", strlen("user ")))  {
  160.             report_error(CANT_CHANGE_PW);
  161.         }
  162.     }
  163.     pclose(c);
  164.     return;
  165. }
  166.  
  167. /* Interpret the form and do the change. ---------------------------------- */
  168. /* ------------------------------------------------------------------------ */
  169.  
  170. int main(int argc, char *argv[])
  171. {
  172.     char *m = getenv("REQUEST_METHOD");
  173.     
  174.     fprintf(stdout, "Content-type: text/html\n\n");
  175.  
  176.     if(!strcmp(m, "GET"))  {
  177.         report_error("You should only use the POST method with this program.");
  178.     }  else  {
  179.         char *database;
  180.         char *user;
  181.         char *old_pw;
  182.         char *new_pw1;
  183.         char *new_pw2;
  184.         char *svrroot;
  185.  
  186.         post_begin(stdin);
  187.  
  188. #ifndef SERVER_ROOT
  189.         svrroot = get_cgi_var("svrroot");
  190.         if (!svrroot) {
  191.             report_error(NO_SVRROOT);
  192.         }
  193. #else
  194.         svrroot = strdup(SERVER_ROOT);
  195. #endif
  196.  
  197.         database = get_cgi_var("database");
  198.         if(!database)  {
  199. #ifdef DEFAULT_DB
  200.             database = strdup(DEFAULT_DB);
  201. #else
  202.             report_error(NO_DATABASE);
  203. #endif
  204.         }
  205.  
  206.         user = get_cgi_var("user");
  207.         if(!user)  {
  208.             user = getenv("REMOTE_USER");
  209.             if(!user)
  210.                 report_error(NO_USERNAME);
  211.         }
  212.  
  213.         old_pw = get_cgi_var("old_pw");
  214.         if(!old_pw)
  215.             report_error(NO_OLDPW);
  216.         new_pw1 = get_cgi_var("new_pw1");
  217.         if(!new_pw1)
  218.             report_error(NO_PASSWORD);
  219.  
  220.         new_pw2 = get_cgi_var("new_pw2");
  221.         if(!new_pw2)
  222.             report_error(NO_PASSWORD);
  223.  
  224.         if(strcmp(new_pw1, new_pw2))  
  225.             report_error(NO_MATCH);
  226.  
  227.         verify_password(svrroot, database, user, old_pw);
  228.         change_password(svrroot, database, user, new_pw1);
  229.  
  230.         fprintf(stdout, 
  231.               "<hr width=50%%><h1 align=center>Success!</h1><hr width=50%%>\n");
  232.         fprintf(stdout,"<p align=center>%s</p>\n", VICTORY_MSG);
  233.     } 
  234.     return 0;
  235. }
  236.  
  237. /* Form handling happiness ------------------------------------------------ */
  238. /* ------------------------------------------------------------------------ */
  239.  
  240. /* Tell the user about an unfortunate occurrence. */
  241. void report_error(char *error) 
  242. {
  243.     fprintf(stdout, "<hr size=3><h1 align=center>Error</h1><hr size=3>\n");
  244.     fprintf(stdout, "<b>Error:</b>%s\n", error);
  245.     exit(1);
  246. }
  247.  
  248. /* Unescape the %xx variables as they're sent in. */
  249. void form_unescape(char *str) 
  250. {
  251.     register int x = 0, y = 0;
  252.     int l = strlen(str);
  253.     char digit;
  254.  
  255.     while(x < l)  {
  256.         if((str[x] == '%') && (x < (l - 2)))  {
  257.             ++x;
  258.             digit = (str[x] >= 'A' ? 
  259.                          ((str[x] & 0xdf) - 'A')+10 : (str[x] - '0'));
  260.             digit *= 16;
  261.  
  262.             ++x;
  263.             digit += (str[x] >= 'A' ? 
  264.                          ((str[x] & 0xdf) - 'A')+10 : (str[x] - '0'));
  265.  
  266.             str[y] = digit;
  267.         } 
  268.         else if(str[x] == '+')  {
  269.             str[y] = ' ';
  270.         } else {
  271.             str[y] = str[x];
  272.         }
  273.         x++;
  274.         y++;
  275.     }
  276.     str[y] = '\0';
  277. }
  278.  
  279. /* Read in the variables from stdin, unescape them, and then put them in 
  280.  * the static vector. */
  281. void post_begin(FILE *in) 
  282. {
  283.     char *vars = NULL, *tmp = NULL;
  284.     int cl;
  285.  
  286.     if(!(tmp = getenv("CONTENT_LENGTH")))
  287.         report_error("Your browser sent no content length with a POST command."
  288.                      "  Please be sure to use a fully compliant browser.");
  289.         
  290.     cl = atoi(tmp);
  291.  
  292.     vars = (char *)malloc(cl+1);
  293.  
  294.     if( !(fread(vars, 1, cl, in)) )
  295.         report_error("The POST variables could not be read from stdin.");
  296.  
  297.     vars[cl] = '\0';
  298.  
  299.     input = string_to_vec(vars);
  300. }
  301.  
  302. /* Convert the input from stdin to a usable variable vector. */
  303. char **string_to_vec(char *in)
  304. {
  305.     char **ans;
  306.     int vars = 0;
  307.     register int x = 0;
  308.     char *tmp;
  309.     
  310.     while(in[x])
  311.         if(in[x++]=='=')
  312.             vars++;
  313.     
  314.     ans = (char **) malloc((sizeof(char *)) * (vars+1));
  315.   
  316.     x=0;
  317.     tmp = strtok(in, "&");
  318.     ans[x]=strdup(tmp);
  319.     form_unescape(ans[x++]);
  320.  
  321.     while((tmp = strtok(NULL, "&")))  {
  322.         ans[x] = strdup(tmp);
  323.         form_unescape(ans[x++]);
  324.     }
  325.     return(ans);
  326. }
  327.  
  328. /* Return the value of a POSTed variable, or NULL if none was sent. */
  329. char *get_cgi_var(char *varname)
  330. {
  331.     register int x = 0;
  332.     int len = strlen(varname);
  333.     char *ans = NULL;
  334.    
  335.     while(input[x])  {
  336.     /*  We want to get rid of the =, so len, len+1 */
  337.         if((!strncmp(input[x], varname, len)) && (*(input[x]+len) == '='))  {
  338.             ans = strdup(input[x] + len + 1);
  339.             if(!strcmp(ans, ""))
  340.                 ans = NULL;
  341.             break;
  342.         }  else
  343.             x++;
  344.     }
  345.     return ans;
  346. }
  347.  
  348. /* Escape any shell-specific characters with a "\" */
  349. char *escape_for_shell(char *cmd) {
  350.     register int x,y,l;
  351.     char *ans=(char *)malloc(2*strlen(cmd)+2);
  352.  
  353.     strcpy(ans, cmd);
  354.     l=strlen(ans);
  355.     for(x=0;ans[x];x++) {
  356.         if(strchr(" &;`'\"|*!?~<>^()[]{}$\\",ans[x])){
  357.             for(y=l+1;y>x;y--)
  358.                 ans[y] = ans[y-1];
  359.             l++; /* length has been increased */
  360.             ans[x] = '\\';
  361.             x++; /* skip the character */
  362.         }
  363.     }
  364.     return ans;
  365. }
  366.  
  367. /* Dealing with password encryption --------------------------------------- */
  368. /* ------------------------------------------------------------------------ */
  369.  
  370. static unsigned char itoa64[] =         /* 0 ... 63 => ascii - 64 */
  371.         "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  372.  
  373. /* Encrypt a password. */
  374. char *pw_enc(char *pw)
  375. {
  376.     char *cpw, salt[3];
  377.     long v;
  378.  
  379.     srand((int)time(NULL));
  380.     v = rand();
  381.  
  382.     salt[0] = itoa64[v & 0x3f];
  383.     v >>= 6;
  384.     salt[1] = itoa64[v & 0x3f];
  385.     cpw = crypt(pw, salt);
  386.     return cpw;
  387. }
  388.  
  389. /* Compare an unencrypted password (pw) to an encrypted version, and return
  390.  * 1 if they match. */
  391. int pw_cmp(char *pw, char *enc)
  392. {
  393.     char *cpw = crypt(pw, enc); /* use salt from enc */
  394.  
  395.     return strcmp(enc, cpw);
  396. }
  397.