]> eyrie.org Git - kerberos/krb5-strength.git/blobdiff - plugin/sqlite.c
Update util/xmalloc.c from rra-c-util
[kerberos/krb5-strength.git] / plugin / sqlite.c
index c6fd2d6b40d8f14618764a8045bf73109dd9358d..fae8a630547804773e8a41c5be96f225ba10e1b2 100644 (file)
  *
  * Written by Russ Allbery <eagle@eyrie.org>
  * Based on work by David Mazières
+ * Copyright 2016, 2020, 2023 Russ Allbery <eagle@eyrie.org>
  * Copyright 2014
  *     The Board of Trustees of the Leland Stanford Junior University
  *
- * See LICENSE for licensing terms.
+ * SPDX-License-Identifier: MIT
  */
 
 #include <config.h>
@@ -41,7 +42,7 @@
 #include <portable/system.h>
 
 #ifdef HAVE_SQLITE3_H
-# include <sqlite3.h>
+#    include <sqlite3.h>
 #endif
 
 #include <plugin/internal.h>
  * prefix and the prefix with the last character incremented; the suffix query
  * gets the same, but the suffix should be reversed.
  */
+/* clang-format off */
 #define PREFIX_QUERY \
     "SELECT password, drowssap FROM passwords WHERE password BETWEEN ? AND ?;"
 #define SUFFIX_QUERY \
     "SELECT password, drowssap FROM passwords WHERE drowssap BETWEEN ? AND ?;"
+/* clang-format on */
 
 
 /*
@@ -71,12 +74,13 @@ strength_init_sqlite(krb5_context ctx, krb5_pwqual_moddata data UNUSED)
     /* Get CDB dictionary path from krb5.conf. */
     strength_config_string(ctx, "password_dictionary_sqlite", &path);
 
-    /* If it was set, report an error, since we don't have CDB support. */
+    /* If it was set, report an error, since we don't have SQLite support. */
     if (path == NULL)
         return 0;
     free(path);
-    krb5_set_error_message(ctx, KADM5_BAD_SERVER_PARAMS, "SQLite dictionary"
-                           " requested but not built with SQLite support");
+    krb5_set_error_message(ctx, KADM5_BAD_SERVER_PARAMS,
+                           "SQLite dictionary requested but not built with"
+                           " SQLite support");
     return KADM5_BAD_SERVER_PARAMS;
 }
 #endif
@@ -86,26 +90,27 @@ strength_init_sqlite(krb5_context ctx, krb5_pwqual_moddata data UNUSED)
 #ifdef HAVE_SQLITE3
 
 /*
- * Report a SQLite error.  Takes the SQLite error code and the Kerberos
- * context, stores the resulting error in the Kerberos context, and returns
- * the generic KADM5_FAILURE code, since there doesn't appear to be anything
- * better.
+ * Report a SQLite error.  Takes the module data (used to access the SQLite
+ * object) and the Kerberos context, stores the SQLite error in the Kerberos
+ * context, and returns the generic KADM5_FAILURE code, since there doesn't
+ * appear to be anything better.
  */
-static krb5_error_code
-error_sqlite(krb5_context ctx, int status, const char *format, ...)
+static krb5_error_code __attribute__((__format__(printf, 3, 4)))
+error_sqlite(krb5_context ctx, krb5_pwqual_moddata data, const char *format,
+             ...)
 {
     va_list args;
     ssize_t length;
     char *message;
-    const char *errstr;
-    
-    errstr = sqlite3_errstr(status);
+    const char *errmsg;
+
+    errmsg = sqlite3_errmsg(data->sqlite);
     va_start(args, format);
     length = vasprintf(&message, format, args);
     va_end(args);
     if (length < 0)
         return strength_error_system(ctx, "cannot allocate memory");
-    krb5_set_error_message(ctx, KADM5_FAILURE, "%s: %s", message, errstr);
+    krb5_set_error_message(ctx, KADM5_FAILURE, "%s: %s", message, errmsg);
     free(message);
     return KADM5_FAILURE;
 }
@@ -142,7 +147,7 @@ common_prefix_length(const char *a, const char *b)
 {
     size_t i;
 
-    for (i = 0; a[i] == b[i] && a[i] != '\0' && b[i] != '\0'; i++)
+    for (i = 0; a[i] == b[i] && a[i] != '\0'; i++)
         ;
     return i;
 }
@@ -161,10 +166,10 @@ common_prefix_length(const char *a, const char *b)
  *
  * To see why the sum of the prefix and suffix length can be longer than the
  * length of the password when the password doesn't match the word, consider
- * the password "aaaa" and the word "aaaaaaaaa"
- * (The prefix length plus the
+ * the password "aaaa" and the word "aaaaaaaaa".  The prefix length plus the
  * suffix length may be greater than the length of the password if the
- * password is an exact match for the word or 
+ * password is an exact match for the word or an initial or final substring of
+ * the word.
  */
 static bool
 match(size_t length, const char *password, const char *drowssap,
@@ -224,19 +229,20 @@ strength_init_sqlite(krb5_context ctx, krb5_pwqual_moddata data)
     /* Open the database. */
     status = sqlite3_open_v2(path, &data->sqlite, SQLITE_OPEN_READONLY, NULL);
     if (status != 0)
-        return error_sqlite(ctx, status, "cannot open dictionary %s", path);
+        return error_sqlite(ctx, data, "cannot open dictionary %s", path);
 
     /* Precompile the queries we'll use. */
     status = sqlite3_prepare_v2(data->sqlite, PREFIX_QUERY, -1,
                                 &data->prefix_query, NULL);
     if (status != 0)
-        return error_sqlite(ctx, status, "cannot prepare prefix query");
+        return error_sqlite(ctx, data, "cannot prepare prefix query");
     status = sqlite3_prepare_v2(data->sqlite, SUFFIX_QUERY, -1,
                                 &data->suffix_query, NULL);
     if (status != 0)
-        return error_sqlite(ctx, status, "cannot prepare suffix query");
+        return error_sqlite(ctx, data, "cannot prepare suffix query");
 
     /* Finished.  Return success. */
+    free(path);
     return 0;
 }
 
@@ -252,7 +258,8 @@ strength_check_sqlite(krb5_context ctx, krb5_pwqual_moddata data,
                       const char *password)
 {
     krb5_error_code code;
-    size_t length, prefix_length, suffix_length;
+    size_t length;
+    int prefix_length, suffix_length;
     char *prefix = NULL;
     char *drowssap = NULL;
     bool found = false;
@@ -266,13 +273,14 @@ strength_check_sqlite(krb5_context ctx, krb5_pwqual_moddata data,
      * Determine the length of the prefix and suffix into which we'll divide
      * the string.  Passwords shorter than two characters cannot be
      * meaningfully checked using this method and cause boundary condition
-     * problems.
+     * problems.  Passwords longer than INT_MAX cannot be passed to the SQLite
+     * library.
      */
     length = strlen(password);
-    if (length < 2)
+    if (length < 2 || length > INT_MAX)
         return 0;
-    prefix_length = length / 2;
-    suffix_length = length - prefix_length;
+    prefix_length = (int) length / 2;
+    suffix_length = (int) length - prefix_length;
 
     /* Obtain the reversed password, used for suffix checks. */
     drowssap = reverse_string(password);
@@ -288,14 +296,14 @@ strength_check_sqlite(krb5_context ctx, krb5_pwqual_moddata data,
     status = sqlite3_bind_text(data->prefix_query, 1, password, prefix_length,
                                NULL);
     if (status != SQLITE_OK) {
-        code = error_sqlite(ctx, status, "cannot bind prefix start");
+        code = error_sqlite(ctx, data, "cannot bind prefix start");
         goto fail;
     }
     prefix[prefix_length - 1]++;
-    status = sqlite3_bind_text(data->prefix_query, 2, prefix, prefix_length,
-                               NULL);
+    status =
+        sqlite3_bind_text(data->prefix_query, 2, prefix, prefix_length, NULL);
     if (status != SQLITE_OK) {
-        code = error_sqlite(ctx, status, "cannot bind prefix end");
+        code = error_sqlite(ctx, data, "cannot bind prefix end");
         goto fail;
     }
 
@@ -310,12 +318,12 @@ strength_check_sqlite(krb5_context ctx, krb5_pwqual_moddata data,
             break;
         }
     if (status != SQLITE_DONE && status != SQLITE_ROW) {
-        code = error_sqlite(ctx, status, "error searching by password prefix");
+        code = error_sqlite(ctx, data, "error searching by password prefix");
         goto fail;
     }
     status = sqlite3_reset(data->prefix_query);
     if (status != SQLITE_OK) {
-        code = error_sqlite(ctx, status, "error resetting prefix query");
+        code = error_sqlite(ctx, data, "error resetting prefix query");
         goto fail;
     }
     if (found)
@@ -325,7 +333,7 @@ strength_check_sqlite(krb5_context ctx, krb5_pwqual_moddata data,
     status = sqlite3_bind_text(data->suffix_query, 1, drowssap, suffix_length,
                                SQLITE_TRANSIENT);
     if (status != SQLITE_OK) {
-        code = error_sqlite(ctx, status, "cannot bind suffix start");
+        code = error_sqlite(ctx, data, "cannot bind suffix start");
         goto fail;
     }
     drowssap[prefix_length - 1]++;
@@ -333,7 +341,7 @@ strength_check_sqlite(krb5_context ctx, krb5_pwqual_moddata data,
                                SQLITE_TRANSIENT);
     drowssap[prefix_length - 1]--;
     if (status != SQLITE_OK) {
-        code = error_sqlite(ctx, status, "cannot bind suffix end");
+        code = error_sqlite(ctx, data, "cannot bind suffix end");
         goto fail;
     }
 
@@ -348,20 +356,20 @@ strength_check_sqlite(krb5_context ctx, krb5_pwqual_moddata data,
             break;
         }
     if (status != SQLITE_DONE && status != SQLITE_ROW) {
-        code = error_sqlite(ctx, status, "error searching by password suffix");
+        code = error_sqlite(ctx, data, "error searching by password suffix");
         goto fail;
     }
     status = sqlite3_reset(data->suffix_query);
     if (status != SQLITE_OK) {
-        code = error_sqlite(ctx, status, "error resetting suffix query");
+        code = error_sqlite(ctx, data, "error resetting suffix query");
         goto fail;
     }
     if (found)
         goto found;
 
     /* No match.  Clean up and return success. */
-    memset(prefix, 0, length);
-    memset(drowssap, 0, length);
+    explicit_bzero(prefix, length);
+    explicit_bzero(drowssap, length);
     free(prefix);
     free(drowssap);
     return 0;
@@ -371,8 +379,9 @@ found:
     code = strength_error_dict(ctx, ERROR_DICT);
 
 fail:
-    memset(prefix, 0, length);
-    memset(drowssap, 0, length);
+    if (prefix != NULL)
+        explicit_bzero(prefix, length);
+    explicit_bzero(drowssap, length);
     free(prefix);
     free(drowssap);
     return code;
@@ -390,7 +399,7 @@ strength_close_sqlite(krb5_context ctx UNUSED, krb5_pwqual_moddata data)
     if (data->suffix_query != NULL)
         sqlite3_finalize(data->suffix_query);
     if (data->sqlite != NULL)
-        sqlite3_close_v2(data->sqlite);
+        sqlite3_close(data->sqlite);
 }
 
-#endif /* HAVE_CDB */
+#endif /* HAVE_SQLITE3 */