浏览代码

Dialog to add and delete users and reset user passwords for Windows

bel 11 年之前
父节点
当前提交
3a9aa9b80e
共有 2 个文件被更改,包括 232 次插入19 次删除
  1. 21 2
      src/civetweb.c
  2. 211 17
      src/main.c

+ 21 - 2
src/civetweb.c

@@ -3215,8 +3215,8 @@ static int is_authorized_for_put(struct mg_connection *conn)
 int mg_modify_passwords_file(const char *fname, const char *domain,
                              const char *user, const char *pass)
 {
-    int found;
-    char line[512], u[512] = "", d[512] ="", ha1[33], tmp[PATH_MAX+1];
+    int found, i;
+    char line[512], u[512] = "", d[512] ="", ha1[33], tmp[PATH_MAX+8];
     FILE *fp, *fp2;
 
     found = 0;
@@ -3227,6 +3227,25 @@ int mg_modify_passwords_file(const char *fname, const char *domain,
         pass = NULL;
     }
 
+    /* Other arguments must not be empty */
+    if (fname == NULL || domain == NULL || user == NULL) return 0;
+
+    /* Using the given file format, user name and domain must not contain ':' */
+    if (strchr(user, ':') != NULL) return 0;
+    if (strchr(domain, ':') != NULL) return 0;
+
+    /* Do not allow control characters like newline in user name and domain.
+       Do not allow excessively long names either. */
+    for (i=0; user[i]!=0 && i<255; i++) {
+        if (iscntrl(user[i])) return 0;
+    }
+    if (user[i]) return 0;
+    for (i=0; domain[i]!=0 && i<255; i++) {
+        if (iscntrl(domain[i])) return 0;
+    }
+    if (domain[i]) return 0;
+
+    /* Create a temporary file name */
     (void) snprintf(tmp, sizeof(tmp) - 1, "%s.tmp", fname);
     tmp[sizeof(tmp) - 1] = 0;
 

+ 211 - 17
src/main.c

@@ -83,11 +83,16 @@ static char *server_name;               /* Set by init_server_name() */
 static char *icon_name;                 /* Set by init_server_name() */
 static char config_file[PATH_MAX] = ""; /* Set by process_command_line_arguments() */
 static struct mg_context *ctx;          /* Set by start_civetweb() */
+static int guard = 0;                   /* test if any dialog is already open */
 
 #if !defined(CONFIG_FILE)
 #define CONFIG_FILE "civetweb.conf"
 #endif /* !CONFIG_FILE */
 
+#if !defined(PASSWORDS_FILE_NAME)
+#define PASSWORDS_FILE_NAME ".htpasswd"
+#endif
+
 /* backup config file */
 #if !defined(CONFIG_FILE2) && defined(LINUX)
 #define CONFIG_FILE2 "/usr/local/etc/civetweb.conf"
@@ -168,7 +173,7 @@ static void show_usage_and_exit(void)
 static const char *config_file_top_comment =
     "# Civetweb web server configuration file.\n"
     "# For detailed description of every option, visit\n"
-    "# https://github.com/sunsetbrew/civetweb/blob/master/docs/UserManual.md\n"
+    "# https://github.com/bel2125/civetweb/blob/master/docs/UserManual.md\n"
     "# Lines starting with '#' and empty lines are ignored.\n"
     "# To make a change, remove leading '#', modify option's value,\n"
     "# save this file and then restart Civetweb.\n\n";
@@ -575,9 +580,9 @@ static void start_civetweb(int argc, char *argv[])
 #ifdef _WIN32
 enum {
     ID_ICON = 100, ID_QUIT, ID_SETTINGS, ID_SEPARATOR, ID_INSTALL_SERVICE,
-    ID_REMOVE_SERVICE, ID_STATIC, ID_GROUP,
+    ID_REMOVE_SERVICE, ID_STATIC, ID_GROUP, ID_PASSWORD,
     ID_SAVE, ID_RESET_DEFAULTS, ID_RESET_FILE, ID_RESET_ACTIVE,
-    ID_STATUS, ID_CONNECT,
+    ID_STATUS, ID_CONNECT, ID_ADD_USER, ID_ADD_USER_NAME, ID_ADD_USER_REALM,
 
     /* All dynamically created text boxes for options have IDs starting from
        ID_CONTROLS, incremented by one. */
@@ -622,7 +627,6 @@ static void WINAPI ServiceMain(void)
     SetServiceStatus(hStatus, &ss);
 }
 
-
 static void show_error(void)
 {
     char buf[256];
@@ -667,7 +671,8 @@ static void save_config(HWND hDlg, FILE *fp)
     }
 }
 
-static BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
+
+static BOOL CALLBACK SettingsDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
 {
     FILE *fp;
     int i, j;
@@ -740,7 +745,7 @@ static BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
                     CheckDlgButton(hDlg, ID_CONTROLS + i, !strcmp(value, "yes") ?
                                    BST_CHECKED : BST_UNCHECKED);
                 } else {
-                    SetWindowText(GetDlgItem(hDlg, ID_CONTROLS + i), value);
+                    SetDlgItemText(hDlg, ID_CONTROLS + i, value == NULL ? "" : value);
                 }
             }
             break;
@@ -791,18 +796,73 @@ static BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
             free(title);
         }
         SetFocus(GetDlgItem(hDlg, ID_SAVE));
-        for (i = 0; default_options[i].name != NULL; i++) {
-            name = default_options[i].name;
-            value = mg_get_option(ctx, name);
-            if (default_options[i].type == CONFIG_TYPE_BOOLEAN) {
-                CheckDlgButton(hDlg, ID_CONTROLS + i, !strcmp(value, "yes") ?
-                               BST_CHECKED : BST_UNCHECKED);
-            } else {
-                SetDlgItemText(hDlg, ID_CONTROLS + i, value == NULL ? "" : value);
-            }
+
+        /* Init dialog with active settings */
+        SendMessage(hDlg, WM_COMMAND, ID_RESET_ACTIVE, 0);
+        /* alternative: SendMessage(hDlg, WM_COMMAND, ID_RESET_FILE, 0); */
+        break;
+
+    default:
+        break;
+    }
+
+    return FALSE;
+}
+
+static void GetPassword(char * password, unsigned maxlen)
+{
+    assert(maxlen>=255);
+    /* TODO: replace by a proper dialog */
+    strcpy(password, "12345");
+}
+
+static BOOL CALLBACK PasswordDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP)
+{
+    static const char *passfile = 0;
+    char domain[256], user[256], password[256];
+    WORD ctrlId;
+
+    switch (msg) {
+    case WM_CLOSE:
+        passfile = 0;
+        DestroyWindow(hDlg);
+        break;
+
+    case WM_COMMAND:
+        ctrlId = LOWORD(wParam);
+        if (ctrlId == ID_ADD_USER) {
+            /* Add user */
+            GetWindowText(GetDlgItem(hDlg, ID_ADD_USER_NAME), user, sizeof(user));
+            GetWindowText(GetDlgItem(hDlg, ID_ADD_USER_REALM), domain, sizeof(domain));
+            GetPassword(password, sizeof(password));
+            mg_modify_passwords_file(passfile, domain, user, password);
+            EndDialog(hDlg, IDOK);
+        } else if ((ctrlId>=(ID_CONTROLS + ID_FILE_BUTTONS_DELTA * 3)) &&
+                   (ctrlId<(ID_CONTROLS + ID_FILE_BUTTONS_DELTA * 4))) {
+            /* Modify password */
+            GetWindowText(GetDlgItem(hDlg, ctrlId - ID_FILE_BUTTONS_DELTA * 3), user, sizeof(user));
+            GetWindowText(GetDlgItem(hDlg, ctrlId - ID_FILE_BUTTONS_DELTA * 2), domain, sizeof(domain));
+            GetPassword(password, sizeof(password));
+            mg_modify_passwords_file(passfile, domain, user, password);
+            EndDialog(hDlg, IDOK);
+        } else if ((ctrlId>=(ID_CONTROLS + ID_FILE_BUTTONS_DELTA * 2)) &&
+                   (ctrlId<(ID_CONTROLS + ID_FILE_BUTTONS_DELTA * 3))) {
+            /* Remove user */
+            GetWindowText(GetDlgItem(hDlg, ctrlId - ID_FILE_BUTTONS_DELTA * 2), user, sizeof(user));
+            GetWindowText(GetDlgItem(hDlg, ctrlId - ID_FILE_BUTTONS_DELTA), domain, sizeof(domain));
+            mg_modify_passwords_file(passfile, domain, user, NULL);
+            EndDialog(hDlg, IDOK);
         }
         break;
 
+    case WM_INITDIALOG:
+        passfile = (const char *)lP;
+        SendMessage(hDlg, WM_SETICON,(WPARAM) ICON_SMALL, (LPARAM) hIcon);
+        SendMessage(hDlg, WM_SETICON,(WPARAM) ICON_BIG, (LPARAM) hIcon);
+        SetWindowText(hDlg, passfile);
+        SetFocus(GetDlgItem(hDlg, ID_ADD_USER_NAME));
+        break;
+
     default:
         break;
     }
@@ -855,7 +915,6 @@ static void show_settings_dialog()
     DWORD style;
     DLGTEMPLATE *dia = (DLGTEMPLATE *) mem;
     WORD i, cl, x, y, width, nelems = 0;
-    static int guard = 0; /* test if dialog is already open */
 
     static struct {
         DLGTEMPLATE template; /* 18 bytes */
@@ -939,8 +998,139 @@ static void show_settings_dialog()
     assert((int)p - (int)mem < sizeof(mem));
 
     dia->cy = ((nelems + 1) / 2 + 1) * HEIGHT + 30;
-    DialogBoxIndirectParam(NULL, dia, NULL, DlgProc, (LPARAM) NULL);
+    DialogBoxIndirectParam(NULL, dia, NULL, SettingsDlgProc, (LPARAM) NULL);
     guard--;
+
+#undef HEIGHT
+#undef WIDTH
+#undef LABEL_WIDTH
+}
+
+static void change_password_file()
+{
+#define HEIGHT 15
+#define WIDTH 320
+#define LABEL_WIDTH 90
+
+    OPENFILENAME of;
+    char path[PATH_MAX] = PASSWORDS_FILE_NAME;
+    char strbuf[256], u[256], d[256];
+    HWND hDlg = NULL;
+    FILE * f;
+    int y, nelems;
+    unsigned char mem[4096], *p;
+    DLGTEMPLATE *dia = (DLGTEMPLATE *) mem;
+    const char * domain = mg_get_option(ctx, "authentication_domain");
+
+    static struct {
+        DLGTEMPLATE template; /* 18 bytes */
+        WORD menu, class;
+        wchar_t caption[1];
+        WORD fontsiz;
+        wchar_t fontface[7];
+    } dialog_header = {{
+            WS_CAPTION | WS_POPUP | WS_SYSMENU | WS_VISIBLE |
+            DS_SETFONT | WS_DLGFRAME, WS_EX_TOOLWINDOW, 0, 200, 200, WIDTH, 0
+        },
+        0, 0, L"", 8, L"Tahoma"
+    };
+
+    if (guard == 0) {
+        guard++;
+    } else {
+        return;
+    }
+
+    memset(&of, 0, sizeof(of));
+    of.lStructSize = sizeof(of);
+    of.hwndOwner = (HWND) hDlg;
+    of.lpstrFile = path;
+    of.nMaxFile = sizeof(path);
+    of.lpstrInitialDir = mg_get_option(ctx, "document_root");
+    of.Flags = OFN_CREATEPROMPT | OFN_NOCHANGEDIR | OFN_HIDEREADONLY;
+
+    if (IDOK != GetSaveFileName(&of)) {
+        guard--;
+        return;
+    }
+
+    f = fopen(path, "a+");
+    if (f) {
+        fclose(f);
+    } else {
+        MessageBox(NULL, path, "Can not open file", MB_ICONERROR);
+        guard--;
+        return;
+    }
+
+    do {
+        (void) memset(mem, 0, sizeof(mem));
+        (void) memcpy(mem, &dialog_header, sizeof(dialog_header));
+        p = mem + sizeof(dialog_header);
+
+        f = fopen(path, "r+");
+        if (!f) {
+            MessageBox(NULL, path, "Can not open file", MB_ICONERROR);
+            guard--;
+            return;
+        }
+
+        nelems = 0;
+        while (fgets(strbuf, sizeof(strbuf), f)) {
+            if (sscanf(strbuf, "%255[^:]:%255[^:]:%*s", u, d) != 2) {
+                continue;
+            }
+            u[255]=0;
+            d[255]=0;
+            y = (nelems + 1) * HEIGHT + 5;
+            add_control(&p, dia, 0x80, ID_CONTROLS + nelems + ID_FILE_BUTTONS_DELTA * 3,
+                WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP,
+                10, y, 65, 12, "Modify password");
+            add_control(&p, dia, 0x80, ID_CONTROLS + nelems + ID_FILE_BUTTONS_DELTA * 2,
+                WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP,
+                80, y, 55, 12, "Remove user");
+            add_control(&p, dia, 0x81, ID_CONTROLS + nelems + ID_FILE_BUTTONS_DELTA,
+                WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | WS_DISABLED,
+                245, y, 60, 12, d);
+            add_control(&p, dia, 0x81, ID_CONTROLS + nelems,
+                WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | WS_DISABLED,
+                140, y, 100, 12, u);
+
+            nelems++;
+            assert((int)p - (int)mem < sizeof(mem));
+        }
+        fclose(f);
+
+        y = (WORD) ((nelems + 1) * HEIGHT + 10);
+        add_control(&p, dia, 0x80, ID_ADD_USER,
+            WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP,
+            80, y, 55, 12, "Add user");
+        add_control(&p, dia, 0x81, ID_ADD_USER_REALM,
+            WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL,
+            245, y, 60, 12, domain);
+        add_control(&p, dia, 0x81, ID_ADD_USER_NAME,
+            WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL,
+            140, y, 100, 12, "");
+
+        y = (WORD) ((nelems + 2) * HEIGHT + 10);
+        add_control(&p, dia, 0x80, ID_GROUP, WS_CHILD | WS_VISIBLE |
+            BS_GROUPBOX, 5, 5, WIDTH - 10, y, " Users ");
+
+        y += HEIGHT;
+        add_control(&p, dia, 0x82, ID_STATIC,
+            WS_CHILD | WS_VISIBLE | WS_DISABLED,
+            5, y, 100, 12, server_base_name);
+
+        assert((int)p - (int)mem < sizeof(mem));
+
+        dia->cy = y + 20;
+    } while (IDOK == DialogBoxIndirectParam(NULL, dia, NULL, PasswordDlgProc, (LPARAM) path));
+
+    guard--;
+
+#undef HEIGHT
+#undef WIDTH
+#undef LABEL_WIDTH
 }
 
 static int manage_service(int action)
@@ -1022,6 +1212,9 @@ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
         case ID_SETTINGS:
             show_settings_dialog();
             break;
+        case ID_PASSWORD:
+            change_password_file();
+            break;
         case ID_INSTALL_SERVICE:
         case ID_REMOVE_SERVICE:
             manage_service(LOWORD(wParam));
@@ -1053,6 +1246,7 @@ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
             AppendMenu(hMenu, MF_SEPARATOR, ID_SEPARATOR, "");
             AppendMenu(hMenu, MF_STRING, ID_CONNECT, "Start browser");
             AppendMenu(hMenu, MF_STRING, ID_SETTINGS, "Edit settings");
+            AppendMenu(hMenu, MF_STRING, ID_PASSWORD, "Modify password file");
             AppendMenu(hMenu, MF_SEPARATOR, ID_SEPARATOR, "");
             AppendMenu(hMenu, MF_STRING, ID_QUIT, "Exit");
             GetCursorPos(&pt);