#include #include #include #include #define _XOPEN_SOURCE #include #include #include #include "cgl.h" #define BUFFER_SIZE 100 // Generate a html message void HTMLMessage(const char* msg) { //First Headers printf("Content-type: text/html\n"); printf("\n"); //Body of html printf("\n"); printf("Thank You"); printf("\n"); printf("

%s


\n", msg); //printf("

Home

\n"); printf("\n"); return; } // Generate a html message, and then exit void HTMLErrorMessage(const char* msg) { HTMLMessage(msg); exit(1); } int main(int argc, char **argv) { char *oldpasswd, *passwd, *passwd2, *username; int lock_fd; FILE *passwd_fp, *tmp_fp; char buf[BUFFER_SIZE], tmp_filename[BUFFER_SIZE]; char *pos; int done, len; //Initialize cgl's data structures if (cgl_init() == -1) HTMLErrorMessage("Something is wrong."); //Extract form data username = cgl_getvalue("username"); oldpasswd = cgl_getvalue("oldpasswd"); passwd = cgl_getvalue("passwd"); passwd2 = cgl_getvalue("passwd2"); if (!username || !isValidUsername(username)) HTMLErrorMessage("You must enter a valid username to register."); if (!passwd || !passwd2 || strcmp(passwd, passwd2)) HTMLErrorMessage("Please input your password twice."); //Open the lock file and lock it lock_fd = syncOpen(".htpasswd.lock", O_WRONLY | O_CREAT); if (lock_fd == -1) HTMLErrorMessage("Can't open the lock file."); //Open the real passwd file passwd_fp = fopen(".htpasswd", "a+"); if ((passwd_fp == NULL) || (fseek(passwd_fp, 0, SEEK_SET) == -1)) HTMLErrorMessage("Can't open the passwd file."); //Open a temp passwd file sprintf(tmp_filename, "htpasswd.%d", getpid()); tmp_fp = fopen(tmp_filename, "w"); if (tmp_fp == NULL) HTMLErrorMessage("Can't create the temporary passwd file."); //Main loop, try to see whether this username has been registered before while (fgets(buf, BUFFER_SIZE - 1, passwd_fp)) { len = strlen(buf); if (buf[len - 1] != '\n') { //Unlikely, unless the passwd file is edited by hand buf[len] = '\n'; len++; } pos = strchr(buf, ':'); if (!pos) HTMLErrorMessage("This is impossible."); if (!strncmp(buf, username, (pos - buf))) { //found a match *pos = 0; buf[len - 1] = 0; pos++; if (!oldpasswd || !isRightPasswd(oldpasswd, pos)) { fclose(tmp_fp); unlink(tmp_filename); //delete the temp file HTMLErrorMessage("The old passwd is wrong."); } } else { //copy this line to the temp passwd file fwrite(buf, len, 1, tmp_fp); } } //Add one line in the end for the user with the new passwd pos = crypt(passwd, "Zz"); // Better to randomize "Zz" fprintf(tmp_fp, "%s:%s\n", username, pos); //Close all files and move the temp passwd to the real passwd file fflush(tmp_fp); fclose(tmp_fp); fclose(passwd_fp); chmod(tmp_filename, S_IRUSR | S_IWUSR | S_IROTH); if (rename(tmp_filename, ".htpasswd") == -1) { unlink(tmp_filename); HTMLErrorMessage("Can't update htpasswd file."); } close(lock_fd); //Everything works out. Generate the reply HTML HTMLMessage("Registration succeeded. You can now start to use my auction site."); //Free data structures used by cgl cgl_freeall(); } /***********************/ /* Utility functions */ /***********************/ // Check whether a username is valid int isValidUsername(const char* username) { int i; char *c; int len = strlen(username); if (len == 0) return 0; for (i = 0, c = username; i < len; i++, c++) if (!isalnum(*c)) return 0; return 1; } // Check whether a passwd is the right one int isRightPasswd(const char* passwd, const char* encryptedPasswd) { char *str = crypt(passwd, encryptedPasswd); if (!strcmp(str, encryptedPasswd)) return 1; else return 0; } // Open a file and put a lock on it. This function will block // if someone else is holding an incompatible lock of this file // Return the file descriptor int syncOpen(const char *pathname, int flags) { int fd, res; struct flock *lock; //Open the file if (flags & O_CREAT) fd = open(pathname, flags, 0600); else fd = open(pathname, flags); if (fd == -1) return -1; //Create the flock structure lock = (struct flock *)malloc(sizeof(struct flock)); if (!lock) { close(fd); return -1; } if ((flags & O_WRONLY) || (flags & O_RDWR)) { lock->l_type = F_WRLCK; // get a write lock } else { lock->l_type = F_RDLCK; // else, get a read lock } lock->l_whence = SEEK_SET; lock->l_start = 0; lock->l_len = 0; //Use fcntl to lock the file //This lock will be released when the process terminates or all file // descriptors referring to this file have been closed //So, we don't provide a syncClose() res = fcntl(fd, F_SETLKW, lock); if (res == -1) { close(fd); fd = -1; } free(lock); return fd; }