]> eyrie.org Git - kerberos/krb5-strength.git/blobdiff - plugin/sqlite.c
Merge branch 'debian' into squeeze
[kerberos/krb5-strength.git] / plugin / sqlite.c
index 56f8d2c89c396e7637c1af071e051e2c2ad54a5b..83ec900f7a00b3131d9a6877727deec22568c10f 100644 (file)
@@ -62,7 +62,7 @@
 /*
  * Stub for strength_init_sqlite if not built with SQLite support.
  */
-#ifndef HAVE_SQLITE3
+#ifndef HAVE_SQLITE
 krb5_error_code
 strength_init_sqlite(krb5_context ctx, krb5_pwqual_moddata data UNUSED)
 {
@@ -83,29 +83,30 @@ strength_init_sqlite(krb5_context ctx, krb5_pwqual_moddata data UNUSED)
 
 
 /* Skip the rest of this file if SQLite is not available. */
-#ifdef HAVE_SQLITE3
+#ifdef HAVE_SQLITE
 
 /*
- * 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, ...)
+error_sqlite(krb5_context ctx, krb5_pwqual_moddata data, const char *format,
+             ...)
 {
     va_list args;
     ssize_t length;
     char *message;
-    const char *errstr;
+    const char *errmsg;
     
-    errstr = sqlite3_errstr(status);
+    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;
 }
@@ -154,25 +155,52 @@ common_prefix_length(const char *a, const char *b)
  * the first two column texts, determine whether this password is a match
  * within edit distance one.
  *
- * It will be a match if the length of the common prefix of the passwod and
+ * It will be a match if the length of the common prefix of the password and
  * word plus the length of the common prefix of the reversed password and the
- * reversed word (which is the length of the common suffix) is within 1 of the
- * length of the password.
+ * reversed word (which is the length of the common suffix) is greater than or
+ * equal to the length of the password minus one.
+ *
+ * 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
+ * suffix length may be greater than the length of the password if the
+ * password is an exact match for the word or 
  */
 static bool
 match(size_t length, const char *password, const char *drowssap,
       sqlite3_stmt *query)
 {
     const char *word, *drow;
-    size_t prefix_length, suffix_length;
+    size_t prefix_length, suffix_length, match_length, word_length;
 
+    /* Discard all words whose length is too different. */
     word = (const char *) sqlite3_column_text(query, 0);
-    drow = (const char *) sqlite3_column_text(query, 1);
+    word_length = strlen(word);
+    if (length > word_length + 1 || length + 1 < word_length)
+        return false;
+
+    /*
+     * Get the common prefix length and check if the password is an exact
+     * match.
+     */
     prefix_length = common_prefix_length(password, word);
     if (prefix_length == length)
         return true;
+
+    /*
+     * Ensure there aren't too many different characters for this to be a
+     * match.  If the common prefix and the common suffix together have a
+     * length that's more than one character shorter than the password length,
+     * this is different by at least edit distance two.  The sum of the
+     * lengths of the common prefix and suffix can be greater than length in
+     * cases of an edit in the middle of repeated passwords, such as the
+     * password "baaab" and the word "baab", but those are all matches.
+     */
+    drow = (const char *) sqlite3_column_text(query, 1);
     suffix_length = common_prefix_length(drowssap, drow);
-    return (length - prefix_length - suffix_length <= 1);
+    match_length = prefix_length + suffix_length;
+    return (match_length > length || length - match_length <= 1);
 }
 
 
@@ -197,19 +225,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;
 }
 
@@ -261,14 +290,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);
     if (status != SQLITE_OK) {
-        code = error_sqlite(ctx, status, "cannot bind prefix end");
+        code = error_sqlite(ctx, data, "cannot bind prefix end");
         goto fail;
     }
 
@@ -283,12 +312,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)
@@ -298,7 +327,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]++;
@@ -306,7 +335,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;
     }
 
@@ -321,12 +350,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 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)
@@ -363,7 +392,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_SQLITE */