ソースを参照

Add mg_modify_passwords_file_ha1

This new function makes it possible to add an entry to the password
file without making the plain-text password known to civetweb (in
fact, the caller may not even know it). Instead, the HA1 hash that's
stored in the password file is passed as a parameter directly.
Wolfram Rösler 4 年 前
コミット
40e286450f

+ 1 - 0
docs/APIReference.md

@@ -88,6 +88,7 @@ The content of both structures is not defined in the interface - they are only u
 * [`mg_send_digest_access_authentication_request( conn, realm );`](api/mg_send_digest_access_authentication_request.md)
 * [`mg_check_digest_access_authentication( conn, realm, filename );`](api/mg_check_digest_access_authentication.md)
 * [`mg_modify_passwords_file( passwords_file_name, realm, user, password );`](api/mg_modify_passwords_file.md)
+* [`mg_modify_passwords_file_ha1( passwords_file_name, realm, user, ha1 );`](api/mg_modify_passwords_file_ha1.md)
 
 * [`mg_get_request_info( conn );`](api/mg_get_request_info.md)
 * [`mg_get_request_link( conn, buf, buflen );`](api/mg_get_request_link.md)

+ 1 - 0
docs/api/mg_modify_passwords_file.md

@@ -27,6 +27,7 @@ The function returns 1 when successful and 0 if an error occurs.
 
 ### See Also
 
+* [`mg_modify_passwords_file_ha1();`](mg_modify_passwords_file_ha1.md)
 * [`mg_check_digest_access_authentication();`](mg_check_digest_access_authentication.md)
 * [`mg_send_digest_access_authentication_request();`](mg_send_digest_access_authentication_request.md)
 

+ 37 - 0
docs/api/mg_modify_passwords_file_ha1.md

@@ -0,0 +1,37 @@
+# Civetweb API Reference
+
+### `mg_modify_passwords_file_ha1( passwords_file_name, domain, user, ha1 );`
+
+### Parameters
+
+| Parameter | Type | Description |
+| :--- | :--- | :--- |
+|**`passwords_file_name`**|`const char *`|The path to the passwords file|
+|**`realm`**|`const char *`|The authentication realm (domain) of the user record|
+|**`user`**|`const char *`|Username of the record to be added, changed or deleted|
+|**`ha1`**|`const char *`|HA1 hash of "user:realm:password"|
+
+### Return Value
+
+| Type | Description |
+| :--- | :--- |
+|`int`|Success or error code|
+
+### Description
+
+The function `mg_modify_passwords_file_ha1()` is similar to `mg_modify_passwords_file()`, but the password is not specified in plain text and thus is not revealed to the civetweb library. Instead of the password, a hash ("HA1") is specified which is constructed by the caller as the MD5 checksum (in lower-case hex digits) of the string `user:realm:password`.
+
+For example, if the user name is `myuser`, the realm is `myrealm`, and the password is `secret`, then the HA1 is `e67fd3248b58975c3e89ff18ecb75e2f`:
+
+```
+$ echo -n "myuser:myrealm:secret" | md5sum
+e67fd3248b58975c3e89ff18ecb75e2f  -
+```
+
+The function returns 1 when successful and 0 if an error occurs.
+
+### See Also
+
+* [`mg_modify_passwords_file();`](mg_modify_passwords_file.md)
+
+

+ 15 - 0
include/civetweb.h

@@ -797,6 +797,21 @@ CIVETWEB_API int mg_modify_passwords_file(const char *passwords_file_name,
                                           const char *password);
 
 
+/* Same as mg_modify_passwords_file, but instead of the plain-text
+ * password, the HA1 hash is specified. The plain-text password is
+ * not made known to civetweb.
+ *
+ * The HA1 hash is the MD5 checksum of a "user:realm:password" string
+ * in lower-case hex format. For example, if the user name is "myuser",
+ * the realm is "myrealm", and the password is "secret", then the HA1 is
+ * e67fd3248b58975c3e89ff18ecb75e2f.
+ */
+CIVETWEB_API int mg_modify_passwords_file_ha1(const char *passwords_file_name,
+                                              const char *realm,
+                                              const char *user,
+                                              const char *ha1);
+
+
 /* Return information associated with the request.
  * Use this function to implement a server and get data about a request
  * from a HTTP/HTTPS client.

+ 38 - 10
src/civetweb.c

@@ -8798,14 +8798,15 @@ is_authorized_for_put(struct mg_connection *conn)
 #endif
 
 
-int
-mg_modify_passwords_file(const char *fname,
-                         const char *domain,
-                         const char *user,
-                         const char *pass)
+static int
+modify_passwords_file(const char *fname,
+                      const char *domain,
+                      const char *user,
+                      const char *pass,
+                      const char *ha1)
 {
 	int found, i;
-	char line[512], u[512] = "", d[512] = "", ha1[33], tmp[UTF8_PATH_MAX + 8];
+	char line[512], u[512] = "", d[512] = "", ha1buf[33], tmp[UTF8_PATH_MAX + 8];
 	FILE *fp, *fp2;
 
 	found = 0;
@@ -8884,7 +8885,9 @@ mg_modify_passwords_file(const char *fname,
 		if (!strcmp(u, user) && !strcmp(d, domain)) {
 			found++;
 			if (pass != NULL) {
-				mg_md5(ha1, user, ":", domain, ":", pass, NULL);
+				mg_md5(ha1buf, user, ":", domain, ":", pass, NULL);
+				fprintf(fp2, "%s:%s:%s\n", user, domain, ha1buf);
+			} else if (ha1 != NULL) {
 				fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
 			}
 		} else {
@@ -8893,9 +8896,14 @@ mg_modify_passwords_file(const char *fname,
 	}
 
 	/* If new user, just add it */
-	if (!found && (pass != NULL)) {
-		mg_md5(ha1, user, ":", domain, ":", pass, NULL);
-		fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
+	if (!found) {
+		if (pass != NULL) {
+			mg_md5(ha1buf, user, ":", domain, ":", pass, NULL);
+			fprintf(fp2, "%s:%s:%s\n", user, domain, ha1buf);
+		}
+		else if (ha1 != NULL) {
+			fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
+		}
 	}
 
 	/* Close files */
@@ -8910,6 +8918,26 @@ mg_modify_passwords_file(const char *fname,
 }
 
 
+int
+mg_modify_passwords_file(const char *fname,
+                         const char *domain,
+                         const char *user,
+                         const char *pass)
+{
+	return modify_passwords_file(fname, domain, user, pass, NULL);
+}
+
+
+int
+mg_modify_passwords_file_ha1(const char *fname,
+                         const char *domain,
+                         const char *user,
+                         const char *ha1)
+{
+	return modify_passwords_file(fname, domain, user, NULL, ha1);
+}
+
+
 static int
 is_valid_port(unsigned long port)
 {