Integration of Jira User Management with Apache

If you use MySQL as your Jira backend for user management, it is possible to configure Apache to use the very same authentication you use for Jira.

This might be useful (for example) if Subversion is installed on the same host, and you want (somehow) to allow your users to change their Subversion passwords when changing their Jira one.

The additional benefit (of course) is that "for free" you get a nice tool to centrally manage all users tied to specific projects, sharing the same authentication on Jira, Subversion, Confluence and all other HTTP-based tools you might have.

The "problem" related to the Jira user database is that passwords are encoded (by OpenSymphony) in the SHA-512 algorithm (for security, of course, but given that SHA-512 is not very widespread, you can't get it in the standard modules coming with MySQL or Apache). The "culprit" class performing the SHA-512 hashing is the OpenSymphony Password Digester.

The Apache MySQL Authentication Module provides support for a quite-large number of encryption mechanisms, but (unfortunately) does not provide an implementation of SHA-512.

That said, there are plenty of free/open SHA-512 implementation out there (just look at Google to see what's in the Linux Kernel, for instance).

This code can easily be integrated with the Apache MySQL Authentication Module to provide full integration between Apache and Jira in terms of user management. The following patch has been prepared by integrating the SHA-512 implementation written by Jean-Luc Cooke for the Linux Kernel with the Apache MySQL Authentication Module (at time of writing, version 2.8.1).

Patching the MySQL Module to support SHA-512

The patch is attached at the end of this document, use patch command with --ignore-whitespace to apply it to the source of the Apache MySQL Authentication Module.

# patch -p0 --ignore-whitespace < mod_auth_mysql-sha512.patch
patching mod_auth_mysql-2.8.1/mod_auth_mysql.c
#

Compiling the Module

You can use apxs to compile and install the new mod_auth_mysql module. Just remember to specify the -D_SHA512 parameter on the command line so that the new encryption algorithm gets compiled in:

# /usr/local/apache2/bin apxs -D_SHA512 -ci mod_auth_mysql.c

More information on how apxs works can be found in its manpage (man apxs) and in the Apache documentation. You can also check out the Apache MySQL Authentication Module Configuration Page.

Configuring Apache to work with Jira

First of all make sure that Apache has the following line in its configuration file to load-up the MySQL Authentication Module:

LoadModule mysql_auth_module modules/mod_auth_mysql.so

Then, in any of the <Directory ...>, <Location ...> or <VirtualHost ...> sections of your httpd.conf file, you can start configuring the Jira/MySQL based authentication:

# This will enable authentication and make sure that the MySQL plugin is
# called to validate users

AuthName                     "Simple Jira-based authentication"
AuthType                     Basic
AuthMySQLEnable              on

# Details of the connection to the MySQL database, you can normally use a UNIX
# socket or a TCP socket.

# For TCP/IP
AuthMySQLHost                localhost
AuthMySQLPort                3306

# For UNIX sockets
#AuthMySQLSocket             /tmp/mysql.sock

# The user name and password below are used by Apache to connect to MySQL,
# you should specify the ones you supplied during your Jira installation

AuthMySQLUser                jira-user
AuthMySQLPassword            jira-password
AuthMySQLDB                  jiradb

# Here follows a description of the OpenSymphony user database layout (as
# used by Jira):
#
# - userbase: is the user database table
#   - fields: username/password_hash: 
#
# - groupbase: is the group database table
#   - fields: groupname
#
# - membershipbase: associates users to groups
#   - fields: group_name, user_name
#
# The long AuthMySQLGroupCondition string is used to join those three tables
# together as there is no way to specify different user name fields in the
# mod_auth_mysql configuration for user and group tables.

AuthMySQLUserTable           userbase
AuthMySQLGroupTable          userbase,groupbase,membershipbase

AuthMySQLGroupCondition      "username=user_name and groupname=group_name"

AuthMySQLNameField           username
AuthMySqlGroupField          groupname
AuthMySQLPasswordField       password_hash

# Force the encryption algorighm used for passwords to be SHA-512, the one
# used by Jira and OpenSymphony when relying on a JDBC backend

AuthMySQLPwEncryption        SHA512

# Make sure that MySQL/Jira authentication is authoritative (no other
# modules will be able to authenticate users)

AuthMySQLAuthoritative       On

# Keep the connection between Apache and MySQL alive (useful on TCP/IP based
# connections, but buggy on Apache 2)

AuthMySQLKeepAlive           On

# Restrict access to this resource by specifying the different Require
# directives. Both users and groups from Jira are supported at this poing,
# see <http://httpd.apache.org/docs-2.0/mod/core.html#require>

Require group                jira-admins

Of course the different levels of access given by Apache to the users is dependant on the set of Require directives configured in httpd.conf. The Apache documentation gives a better outline of the Require directive.

Apache MySQL Authentication Module Patch

--- mod_auth_mysql-2.8.1-orig/mod_auth_mysql.c  2004-12-14 22:15:41.000000000 +0000
+++ mod_auth_mysql-2.8.1/mod_auth_mysql.c       2005-01-13 15:13:43.759385968 +0000
@@ -50,7 +50,6 @@
  *
  */

-
 /*
  * Module definition information - the part between the -START and -END
  * lines below is used by Configure. This could be stored in a separate
@@ -246,6 +245,266 @@
   #include <my_aes.h>
 #endif

+#ifdef _SHA512
+/*
+ * SHA-512 code by Jean-Luc Cooke <jlcooke@certainkey.com>
+ *
+ * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com>
+ * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
+ * Copyright (c) 2003 Kyle McMartin <kyle@debian.org>
+ */
+
+#define SHA512_DIGEST_SIZE 64
+
+#define H0    0x6a09e667f3bcc908ULL
+#define H1    0xbb67ae8584caa73bULL
+#define H2    0x3c6ef372fe94f82bULL
+#define H3    0xa54ff53a5f1d36f1ULL
+#define H4    0x510e527fade682d1ULL
+#define H5    0x9b05688c2b3e6c1fULL
+#define H6    0x1f83d9abfb41bd6bULL
+#define H7    0x5be0cd19137e2179ULL
+
+#define e0(x) (ROR(x,28) ^ ROR(x,34) ^ ROR(x,39))
+#define e1(x) (ROR(x,14) ^ ROR(x,18) ^ ROR(x,41))
+#define s0(x) (ROR(x, 1) ^ ROR(x, 8) ^ (x >> 7))
+#define s1(x) (ROR(x,19) ^ ROR(x,61) ^ (x >> 6))
+
+typedef struct sha512_ctx {
+    uint64_t state[JIRACOM:8];
+    uint32_t count[JIRACOM:4];
+    uint8_t buf[JIRACOM:128];
+} sha512_ctx;
+
+static inline uint64_t CH(uint64_t x, uint64_t y, uint64_t z) {
+    return ((x & y) ^ (~x & z));
+}
+
+static inline uint64_t MAJ(uint64_t x, uint64_t y, uint64_t z) {
+    return ((x & y) ^ (x & z) ^ (y & z));
+}
+
+static inline uint64_t ROR(uint64_t x, uint64_t y) {
+    return (x >> y) | (x << (64 - y));
+}
+
+static inline void LOA(int I, uint64_t *W, const uint8_t *input) {
+    uint64_t t1  = input[JIRACOM:(8*I)  ] & 0xff;
+    t1 <<= 8;
+    t1 |= input[JIRACOM:(8*I)+1] & 0xff;
+    t1 <<= 8;
+    t1 |= input[JIRACOM:(8*I)+2] & 0xff;
+    t1 <<= 8;
+    t1 |= input[JIRACOM:(8*I)+3] & 0xff;
+    t1 <<= 8;
+    t1 |= input[JIRACOM:(8*I)+4] & 0xff;
+    t1 <<= 8;
+    t1 |= input[JIRACOM:(8*I)+5] & 0xff;
+    t1 <<= 8;
+    t1 |= input[JIRACOM:(8*I)+6] & 0xff;
+    t1 <<= 8;
+    t1 |= input[JIRACOM:(8*I)+7] & 0xff;
+    W[JIRACOM:I] = t1;
+}
+
+static inline void MIX(int I, uint64_t *W) {
+    W[JIRACOM:I] = s1(W[JIRACOM:I-2]) + W[JIRACOM:I-7] + s0(W[JIRACOM:I-15]) + W[JIRACOM:I-16];
+}
+
+static const uint64_t sha512_K[JIRACOM:80] = {
+    0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
+    0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+    0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
+    0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+    0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
+    0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+    0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
+    0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+    0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
+    0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+    0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
+    0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+    0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
+    0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+    0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
+    0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+    0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
+    0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+    0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
+    0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+    0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
+    0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+    0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
+    0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+    0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
+    0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+    0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL,
+};
+
+
+static void _transform(uint64_t *state, const uint8_t *input) {
+    uint64_t a, b, c, d, e, f, g, h, t1, t2;
+    uint64_t W[JIRACOM:80];
+    int i;
+
+    /* load the input */
+    for (i = 0; i < 16; i++) LOA(i, W, input);
+    for (i = 16; i < 80; i++) MIX(i, W);
+
+    /* load the state into our registers */
+    a=state[JIRACOM:0];   b=state[JIRACOM:1];   c=state[JIRACOM:2];   d=state[JIRACOM:3];
+    e=state[JIRACOM:4];   f=state[JIRACOM:5];   g=state[JIRACOM:6];   h=state[JIRACOM:7];
+
+    /* now iterate */
+    for (i=0; i<80; i+=8) {
+        t1 = h + e1(e) + CH(e,f,g) + sha512_K[JIRACOM:i  ] + W[JIRACOM:i  ];
+        t2 = e0(a) + MAJ(a,b,c);    d+=t1;    h=t1+t2;
+        t1 = g + e1(d) + CH(d,e,f) + sha512_K[JIRACOM:i+1] + W[JIRACOM:i+1];
+        t2 = e0(h) + MAJ(h,a,b);    c+=t1;    g=t1+t2;
+        t1 = f + e1(c) + CH(c,d,e) + sha512_K[JIRACOM:i+2] + W[JIRACOM:i+2];
+        t2 = e0(g) + MAJ(g,h,a);    b+=t1;    f=t1+t2;
+        t1 = e + e1(b) + CH(b,c,d) + sha512_K[JIRACOM:i+3] + W[JIRACOM:i+3];
+        t2 = e0(f) + MAJ(f,g,h);    a+=t1;    e=t1+t2;
+        t1 = d + e1(a) + CH(a,b,c) + sha512_K[JIRACOM:i+4] + W[JIRACOM:i+4];
+        t2 = e0(e) + MAJ(e,f,g);    h+=t1;    d=t1+t2;
+        t1 = c + e1(h) + CH(h,a,b) + sha512_K[JIRACOM:i+5] + W[JIRACOM:i+5];
+        t2 = e0(d) + MAJ(d,e,f);    g+=t1;    c=t1+t2;
+        t1 = b + e1(g) + CH(g,h,a) + sha512_K[JIRACOM:i+6] + W[JIRACOM:i+6];
+        t2 = e0(c) + MAJ(c,d,e);    f+=t1;    b=t1+t2;
+        t1 = a + e1(f) + CH(f,g,h) + sha512_K[JIRACOM:i+7] + W[JIRACOM:i+7];
+        t2 = e0(b) + MAJ(b,c,d);    e+=t1;    a=t1+t2;
+    }
+
+    state[JIRACOM:0] += a; state[JIRACOM:1] += b; state[JIRACOM:2] += c; state[JIRACOM:3] += d;
+    state[JIRACOM:4] += e; state[JIRACOM:5] += f; state[JIRACOM:6] += g; state[JIRACOM:7] += h;
+
+    /* erase our data */
+    a = b = c = d = e = f = g = h = t1 = t2 = 0;
+    memset(W, 0, 80 * sizeof(uint64_t));
+}
+
+static void sha512_init(void *ctx) {
+    struct sha512_ctx *sctx = ctx;
+    sctx->state[JIRACOM:0] = H0;
+    sctx->state[JIRACOM:1] = H1;
+    sctx->state[JIRACOM:2] = H2;
+    sctx->state[JIRACOM:3] = H3;
+    sctx->state[JIRACOM:4] = H4;
+    sctx->state[JIRACOM:5] = H5;
+    sctx->state[JIRACOM:6] = H6;
+    sctx->state[JIRACOM:7] = H7;
+    sctx->count[JIRACOM:0] = sctx->count[JIRACOM:1] = sctx->count[JIRACOM:2] = sctx->count[JIRACOM:3] = 0;
+    memset(sctx->buf, 0, sizeof(sctx->buf));
+}
+
+static void sha512_update(void *ctx, const uint8_t *data, unsigned int len) {
+        struct sha512_ctx *sctx = ctx;
+        unsigned int i, index, part_len;
+
+        /* Compute number of bytes mod 128 */
+        index = (unsigned int)((sctx->count[JIRACOM:0] >> 3) & 0x7F);
+
+        /* Update number of bits */
+        if ((sctx->count[JIRACOM:0] += (len << 3)) < (len << 3)) {
+                if ((sctx->count[JIRACOM:1] += 1) < 1)
+                        if ((sctx->count[JIRACOM:2] += 1) < 1)
+                                sctx->count[JIRACOM:3]++;
+                sctx->count[JIRACOM:1] += (len >> 29);
+        }
+
+        part_len = 128 - index;
+
+        /* Transform as many times as possible. */
+        if (len >= part_len) {
+                memcpy(&sctx->buf[JIRACOM:index], data, part_len);
+                _transform(sctx->state, sctx->buf);
+
+                for (i = part_len; i + 127 < len; i+=128)
+                        _transform(sctx->state, &data[JIRACOM:i]);
+
+                index = 0;
+        } else {
+                i = 0;
+        }
+
+        /* Buffer remaining input */
+        memcpy(&sctx->buf[JIRACOM:index], &data[JIRACOM:i], len - i);
+}
+
+static void sha512_final(void *ctx, uint8_t *hash) {
+        struct sha512_ctx *sctx = ctx;
+        const static uint8_t padding[JIRACOM:128] = { 0x80, };
+
+        uint32_t t;
+        uint64_t t2;
+        uint8_t bits[JIRACOM:128];
+        unsigned int index, pad_len;
+        int i, j;
+
+        index = pad_len = t = i = j = 0;
+        t2 = 0;
+
+        /* Save number of bits */
+        t = sctx->count[JIRACOM:0];
+        bits[JIRACOM:15] = t; t>>=8;
+        bits[JIRACOM:14] = t; t>>=8;
+        bits[JIRACOM:13] = t; t>>=8;
+        bits[JIRACOM:12] = t;
+        t = sctx->count[JIRACOM:1];
+        bits[JIRACOM:11] = t; t>>=8;
+        bits[JIRACOM:10] = t; t>>=8;
+        bits[JIRACOM:9 ] = t; t>>=8;
+        bits[JIRACOM:8 ] = t;
+        t = sctx->count[JIRACOM:2];
+        bits[JIRACOM:7 ] = t; t>>=8;
+        bits[JIRACOM:6 ] = t; t>>=8;
+        bits[JIRACOM:5 ] = t; t>>=8;
+        bits[JIRACOM:4 ] = t;
+        t = sctx->count[JIRACOM:3];
+        bits[JIRACOM:3 ] = t; t>>=8;
+        bits[JIRACOM:2 ] = t; t>>=8;
+        bits[JIRACOM:1 ] = t; t>>=8;
+        bits[JIRACOM:0 ] = t;
+
+        /* Pad out to 112 mod 128. */
+        index = (sctx->count[JIRACOM:0] >> 3) & 0x7f;
+        pad_len = (index < 112) ? (112 - index) : ((128+112) - index);
+        sha512_update(sctx, padding, pad_len);
+
+        /* Append length (before padding) */
+        sha512_update(sctx, bits, 16);
+
+        /* Store state in digest */
+        for (i = j = 0; i < 8; i++, j += 8) {
+                t2 = sctx->state[JIRACOM:i];
+                hash[JIRACOM:j+7] = (char)t2 & 0xff; t2>>=8;
+                hash[JIRACOM:j+6] = (char)t2 & 0xff; t2>>=8;
+                hash[JIRACOM:j+5] = (char)t2 & 0xff; t2>>=8;
+                hash[JIRACOM:j+4] = (char)t2 & 0xff; t2>>=8;
+                hash[JIRACOM:j+3] = (char)t2 & 0xff; t2>>=8;
+                hash[JIRACOM:j+2] = (char)t2 & 0xff; t2>>=8;
+                hash[JIRACOM:j+1] = (char)t2 & 0xff; t2>>=8;
+                hash[JIRACOM:j  ] = (char)t2 & 0xff;
+        }
+
+        /* Zeroize sensitive information. */
+        memset(sctx, 0, sizeof(struct sha512_ctx));
+}
+
+static int sha512_hash(uint8_t *orig, int origlen, uint8_t *hash, int hashlen) {
+    sha512_ctx context;
+
+    if (hash == NULL) return -1;
+    if (hashlen < SHA512_DIGEST_SIZE) return -1;
+
+    sha512_init(&context);
+    sha512_update(&context, orig, origlen);
+    sha512_final(&context, hash);
+    return(SHA512_DIGEST_SIZE);
+}
+
+#endif //_SHA512
+
 /* Password encryption constants */
 #define PW_ENCRYPT_UNDEFINED -1
 #define PW_ENCRYPT_NONE       0
@@ -256,6 +515,9 @@
   #define PW_ENCRYPT_AES        4
 #endif
 #define PW_ENCRYPT_SHA1       5
+#ifdef _SHA512
+  #define PW_ENCRYPT_SHA512   6
+#endif

 /* Any other value is a string containing the column name */

@@ -286,6 +548,9 @@
   int  mysqlAES;               /* Are passwords AES? */
 #endif
   int  mysqlSHA1;              /* Are passwords SHA1? */
+#ifdef _SHA512
+  int  mysqlSHA512;            /* Are passwords SHA512? */
+#endif
   char *mysqlSaltField;                /* salt for scrambled password */
   int  mysqlKeepAlive;         /* keep connection persistent? */
   int  mysqlAuthoritative;     /* are we authoritative? */
@@ -438,6 +703,9 @@
   m->mysqlAES = 0;                                 /* passwords are not AES encrypted */
 #endif
   m->mysqlSHA1 = 0;                                /* passwords are not SHA1 encrypted */
+#ifdef _SHA512
+  m->mysqlSHA512 = 0;                              /* passwords are not SHA512 encrypted */
+#endif
   m->mysqlSaltField = _SALTFIELD;                  /* default is scramble password against itself */
   m->mysqlKeepAlive = _KEEPALIVE;                  /* do not keep persistent connection */
   m->mysqlAuthoritative = _AUTHORITATIVE;          /* we are authoritative source for users */
@@ -523,6 +791,12 @@
        (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlSHA1),
        OR_AUTHCFG, "mysql passwords are stored as SHA1 if On"),

+#ifdef _SHA512
+       AP_INIT_FLAG("AuthMySQLSHA512Passwords", ap_set_flag_slot,
+       (void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlSHA512),
+       OR_AUTHCFG, "mysql passwords are stored as SHA512 if On"),
+#endif
+
        AP_INIT_TAKE1("AuthMySQLSaltField", ap_set_string_slot,
        (void*) APR_XtOffsetOf(mysql_auth_config_rec, mysqlSaltField),
        OR_AUTHCFG, "mysql salfe field name within table"),
@@ -626,6 +900,12 @@
     (void*)XtOffsetOf(mysql_auth_config_rec, mysqlSHA1),
     OR_AUTHCFG, FLAG, "mysql passwords are stored as SHA1 if On" },

+#ifdef _SHA512
+  { "AuthMySQLSHA512Passwords", ap_set_flag_slot,
+    (void*)XtOffsetOf(mysql_auth_config_rec, mysqlSHA512),
+    OR_AUTHCFG, FLAG, "mysql passwords are stored as SHA512 if On" },
+#endif
+
   { "AuthMySQLSaltField", ap_set_string_slot,
     (void *)XtOffsetOf(mysql_auth_config_rec, mysqlSaltField),
     OR_AUTHCFG, TAKE1, "mysql salt field name within table" },
@@ -868,6 +1148,10 @@
 #endif
     else if (strcasecmp(sec->mysqlEncryptionField, "sha1") == 0)
       encryption_type = PW_ENCRYPT_SHA1;
+#ifdef _SHA512
+    else if (strcasecmp(sec->mysqlEncryptionField, "sha512") == 0)
+      encryption_type = PW_ENCRYPT_SHA512;
+#endif
     else {
       LOG_ERROR_1(APLOG_NOERRNO|APLOG_ERR, 0, r, "mysql invalid encryption method %s", sec->mysqlEncryptionField);
       ap_note_basic_auth_failure(r);
@@ -887,6 +1171,10 @@
 #endif
     else if (sec->mysqlSHA1 == 1)
       encryption_type = PW_ENCRYPT_SHA1;
+#ifdef _SHA512
+    else if (sec->mysqlSHA512 == 1)
+      encryption_type = PW_ENCRYPT_SHA512;
+#endif
     else
       encryption_type = PW_ENCRYPT_NONE;
   }
@@ -992,6 +1280,23 @@
       passwords_match = strcasecmp(bin2hex(r->pool, scrambled_sent_pw, enc_len), real_pw) == 0;
       break;

+#ifdef _SHA512
+    case PW_ENCRYPT_SHA512:
+      res = sha512_hash((uint8_t *)sent_pw, strlen(sent_pw), buffer, 128);
+      if (res != SHA512_DIGEST_SIZE) {
+        LOG_ERROR(APLOG_NOERRNO|APLOG_ERR, 0, r, "auth_mysql: "
+                    "Internal error: SHA512 invalid digest size");
+      } else {
+        enc_len = apr_base64_encode_len(SHA512_DIGEST_SIZE);
+        scrambled_sent_pw = PCALLOC(r->pool, enc_len);
+        enc_len = apr_base64_encode(scrambled_sent_pw, buffer, SHA512_DIGEST_SIZE);
+        if (enc_len > 0 && memcmp(real_pw, scrambled_sent_pw, enc_len) == 0) {
+             passwords_match = 1;
+           }
+         }
+      break;
+#endif
+
     case PW_ENCRYPT_NONE:
       if (strcmp(real_pw, sent_pw) == 0)
        passwords_match = 1;

Labels

plugin plugin Delete
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Jul 11, 2005

    björn eriksson says:

    Thanks. This (together with https) will hopefully be very useful to us. Has any...

    Thanks. This (together with https) will hopefully be very useful to us.

    Has anyone ported this to 'mod_auth_mysql-3.0.0'?

    I will look into doing that port and integrating 'authz_svn_module' with jira later.

  2. Jul 12, 2005

    björn eriksson says:

    /me wonders why jeff added "JIRACOM:" all over the place. I had to pipe it throu...

    /me wonders why jeff added "JIRACOM:" all over the place. I had to pipe it through s/JIRACOM://g

  3. Dec 02, 2005

    richard chang says:

    I have ported this to 'mod_auth_mysql-3.0.0' as following:  [root@Core mod...

    I have ported this to 'mod_auth_mysql-3.0.0' as following:

     [root@Core mod_auth_mysql-3.0.0]# patch --ignore-whitespace < mod_auth_mysl-sha512.patch
    -------------stdOut--------------------
    patching file mod_auth_mysql.c
    Reversed (or previously applied) patch detected!  Assume -R? [n] y
    Hunk #2 FAILED at 246.
    Hunk #3 FAILED at 256.
    Hunk #4 FAILED at 286.
    Hunk #5 FAILED at 438.
    Hunk #6 succeeded at 377 with fuzz 2 (offset -146 lines).
    Hunk #7 succeeded at 618 with fuzz 2 (offset -8 lines).
    Hunk #8 FAILED at 860.
    Hunk #9 FAILED at 879.
    Hunk #10 FAILED at 984.
    --------------end stdOut-------------------------------

    as above,I have failed to do that, Would anyone help me? thanks!

  4. Dec 11, 2005

    scud says:

    try this,but no guarantee,because i have not try it on my apache. --- mod...

    try this,but no guarantee,because i have not try it on my apache.

     
    
    --- mod_auth_mysql-3.0.0\mod_auth_mysql.c.old Thu Jun 23 00:17:46 2005
    \++\+ mod_auth_mysql-3.0.0\mod_auth_mysql.c Sun Dec 11 16:59:26 2005
    @@ \-271,6 \+270,269 @@
    \#include <my_aes.h>
    \#endif
    
    +
    \+#ifdef \_SHA512
    \+/\*
    + * SHA-512 code by Jean-Luc Cooke <jlcooke@certainkey.com>
    + *
    + * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com>
    + * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
    + * Copyright (c) 2003 Kyle McMartin <kyle@debian.org>
    + \*/
    +
    \+#define SHA512_DIGEST_SIZE 64
    +
    \+#define H0 0x6a09e667f3bcc908ULL
    \+#define H1 0xbb67ae8584caa73bULL
    \+#define H2 0x3c6ef372fe94f82bULL
    \+#define H3 0xa54ff53a5f1d36f1ULL
    \+#define H4 0x510e527fade682d1ULL
    \+#define H5 0x9b05688c2b3e6c1fULL
    \+#define H6 0x1f83d9abfb41bd6bULL
    \+#define H7 0x5be0cd19137e2179ULL
    +
    \+#define e0(x) (ROR(x,28) ^ ROR(x,34) ^ ROR(x,39))
    \+#define e1(x) (ROR(x,14) ^ ROR(x,18) ^ ROR(x,41))
    \+#define s0(x) (ROR(x, 1) ^ ROR(x, 8) ^ (x >> 7))
    \+#define s1(x) (ROR(x,19) ^ ROR(x,61) ^ (x >> 6))
    +
    \+typedef struct sha512_ctx {
    + uint64_t state[8];
    + uint32_t count[4];
    + uint8_t buf[128];
    \+} sha512_ctx;
    +
    \+static inline uint64_t CH(uint64_t x, uint64_t y, uint64_t z) {
    + return ((x & y) ^ (~x & z));
    \+}
    +
    \+static inline uint64_t MAJ(uint64_t x, uint64_t y, uint64_t z) {
    + return ((x & y) ^ (x & z) ^ (y & z));
    \+}
    +
    \+static inline uint64_t ROR(uint64_t x, uint64_t y) {
    + return (x >> y) \| (x << (64 - y));
    \+}
    +
    \+static inline void LOA(int I, uint64_t \*W, const uint8_t \*input) {
    + uint64_t t1 = input[(8*I)] & 0xff;
    + t1 <<= 8;
    + t1 \|= input[(8*I)+1] & 0xff;
    + t1 <<= 8;
    + t1 \|= input[(8*I)+2] & 0xff;
    + t1 <<= 8;
    + t1 \|= input[(8*I)+3] & 0xff;
    + t1 <<= 8;
    + t1 \|= input[(8*I)+4] & 0xff;
    + t1 <<= 8;
    + t1 \|= input[(8*I)+5] & 0xff;
    + t1 <<= 8;
    + t1 \|= input[(8*I)+6] & 0xff;
    + t1 <<= 8;
    + t1 \|= input[(8*I)+7] & 0xff;
    + W[I] = t1;
    \+}
    +
    \+static inline void MIX(int I, uint64_t \*W) {
    + W[I] = s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16];
    \+}
    +
    \+static const uint64_t sha512_K[80] = {
    + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
    + 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
    + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
    + 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
    + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
    + 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
    + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
    + 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
    + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
    + 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
    + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
    + 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
    + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
    + 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
    + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
    + 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
    + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
    + 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
    + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
    + 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
    + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
    + 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
    + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
    + 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
    + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
    + 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
    + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL,
    \+};
    +
    +
    \+static void \_transform(uint64_t \*state, const uint8_t \*input) {
    + uint64_t a, b, c, d, e, f, g, h, t1, t2;
    + uint64_t W[80];
    + int i;
    +
    + /\* load the input \*/
    + for (i = 0; i < 16; i++) LOA(i, W, input);
    + for (i = 16; i < 80; i++) MIX(i, W);
    +
    + /\* load the state into our registers \*/
    + a=state[0]; b=state[1]; c=state[2]; d=state[3];
    + e=state[4]; f=state[5]; g=state[6]; h=state[7];
    +
    + /\* now iterate \*/
    + for (i=0; i<80; i+=8) {
    + t1 = h + e1(e) + CH(e,f,g) + sha512_K[i] + W[i];
    + t2 = e0(a) + MAJ(a,b,c); d+=t1; h=t1+t2;
    + t1 = g + e1(d) + CH(d,e,f) + sha512_K[i+1] + W[i+1];
    + t2 = e0(h) + MAJ(h,a,b); c+=t1; g=t1+t2;
    + t1 = f + e1(c) + CH(c,d,e) + sha512_K[i+2] + W[i+2];
    + t2 = e0(g) + MAJ(g,h,a); b+=t1; f=t1+t2;
    + t1 = e + e1(b) + CH(b,c,d) + sha512_K[i+3] + W[i+3];
    + t2 = e0(f) + MAJ(f,g,h); a+=t1; e=t1+t2;
    + t1 = d + e1(a) + CH(a,b,c) + sha512_K[i+4] + W[i+4];
    + t2 = e0(e) + MAJ(e,f,g); h+=t1; d=t1+t2;
    + t1 = c + e1(h) + CH(h,a,b) + sha512_K[i+5] + W[i+5];
    + t2 = e0(d) + MAJ(d,e,f); g+=t1; c=t1+t2;
    + t1 = b + e1(g) + CH(g,h,a) + sha512_K[i+6] + W[i+6];
    + t2 = e0(c) + MAJ(c,d,e); f+=t1; b=t1+t2;
    + t1 = a + e1(f) + CH(f,g,h) + sha512_K[i+7] + W[i+7];
    + t2 = e0(b) + MAJ(b,c,d); e+=t1; a=t1+t2;
    + }
    +
    + state[0] \+= a; state[1] \+= b; state[2] \+= c; state[3] \+= d;
    + state[4] \+= e; state[5] \+= f; state[6] \+= g; state[7] \+= h;
    +
    + /\* erase our data \*/
    + a = b = c = d = e = f = g = h = t1 = t2 = 0;
    + memset(W, 0, 80 * sizeof(uint64_t));
    \+}
    +
    \+static void sha512_init(void \*ctx) {
    + struct sha512_ctx \*sctx = ctx;
    + sctx->state[0] = H0;
    + sctx->state[1] = H1;
    + sctx->state[2] = H2;
    + sctx->state[3] = H3;
    + sctx->state[4] = H4;
    + sctx->state[5] = H5;
    + sctx->state[6] = H6;
    + sctx->state[7] = H7;
    + sctx->count[0] = sctx->count[1] = sctx->count[2] = sctx->count[3] = 0;
    + memset(sctx->buf, 0, sizeof(sctx->buf));
    \+}
    +
    \+static void sha512_update(void \*ctx, const uint8_t \*data, unsigned int len) {
    + struct sha512_ctx \*sctx = ctx;
    + unsigned int i, index, part_len;
    +
    + /\* Compute number of bytes mod 128 \*/
    + index = (unsigned int)((sctx->count[0] >> 3) & 0x7F);
    +
    + /\* Update number of bits \*/
    + if ((sctx->count[0] \+= (len << 3)) < (len << 3)) {
    + if ((sctx->count[1] \+= 1) < 1)
    + if ((sctx->count[2] \+= 1) < 1)
    + sctx->count[3]\++;
    + sctx->count[1] \+= (len >> 29);
    + }
    +
    + part_len = 128 - index;
    +
    + /\* Transform as many times as possible. \*/
    + if (len >= part_len) {
    + memcpy(&sctx->buf[index], data, part_len);
    + \_transform(sctx->state, sctx->buf);
    +
    + for (i = part_len; i + 127 < len; i+=128)
    + \_transform(sctx->state, &data[i]);
    +
    + index = 0;
    + } else {
    + i = 0;
    + }
    +
    + /\* Buffer remaining input \*/
    + memcpy(&sctx->buf[index], &data[i], len - i);
    \+}
    +
    \+static void sha512_final(void \*ctx, uint8_t \*hash) {
    + struct sha512_ctx \*sctx = ctx;
    + const static uint8_t padding[128] =
    { 0x80, }
    ;
    +
    + uint32_t t;
    + uint64_t t2;
    + uint8_t bits[128];
    + unsigned int index, pad_len;
    + int i, j;
    +
    + index = pad_len = t = i = j = 0;
    + t2 = 0;
    +
    + /\* Save number of bits \*/
    + t = sctx->count[0];
    + bits[15] = t; t>>=8;
    + bits[14] = t; t>>=8;
    + bits[13] = t; t>>=8;
    + bits[12] = t;
    + t = sctx->count[1];
    + bits[11] = t; t>>=8;
    + bits[10] = t; t>>=8;
    + bits[9] = t; t>>=8;
    + bits[8] = t;
    + t = sctx->count[2];
    + bits[7] = t; t>>=8;
    + bits[6] = t; t>>=8;
    + bits[5] = t; t>>=8;
    + bits[4] = t;
    + t = sctx->count[3];
    + bits[3] = t; t>>=8;
    + bits[2] = t; t>>=8;
    + bits[1] = t; t>>=8;
    + bits[0] = t;
    +
    + /\* Pad out to 112 mod 128. \*/
    + index = (sctx->count[0] >> 3) & 0x7f;
    + pad_len = (index < 112) ? (112 - index) : ((128+112) - index);
    + sha512_update(sctx, padding, pad_len);
    +
    + /\* Append length (before padding) \*/
    + sha512_update(sctx, bits, 16);
    +
    + /\* Store state in digest \*/
    + for (i = j = 0; i < 8; i++, j \+= 8) {
    + t2 = sctx->state[i];
    + hash[j+7] = (char)t2 & 0xff; t2>>=8;
    + hash[j+6] = (char)t2 & 0xff; t2>>=8;
    + hash[j+5] = (char)t2 & 0xff; t2>>=8;
    + hash[j+4] = (char)t2 & 0xff; t2>>=8;
    + hash[j+3] = (char)t2 & 0xff; t2>>=8;
    + hash[j+2] = (char)t2 & 0xff; t2>>=8;
    + hash[j+1] = (char)t2 & 0xff; t2>>=8;
    + hash[j] = (char)t2 & 0xff;
    + }
    +
    + /\* Zeroize sensitive information. \*/
    + memset(sctx, 0, sizeof(struct sha512_ctx));
    \+}
    +
    \+static int sha512_hash(uint8_t \*orig, int origlen, uint8_t \*hash, int hashlen) {
    + sha512_ctx context;
    +
    + if (hash == NULL) return \-1;
    + if (hashlen < SHA512_DIGEST_SIZE) return \-1;
    +
    + sha512_init(&context);
    + sha512_update(&context, orig, origlen);
    + sha512_final(&context, hash);
    + return(SHA512_DIGEST_SIZE);
    \+}
    +
    \+#endif //_SHA512
    +
    +
    +
    \#ifndef SCRAMBLED_PASSWORD_CHAR_LENGTH /\* Ensure it is defined for older MySQL releases \*/
    \#define SCRAMBLED_PASSWORD_CHAR_LENGTH 32 /\* Big enough for the old method of scrambling \*/
    \#endif
    @@ \-287,6 \+549,10 @@
    \#if \_AES
    static short pw_aes(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt);
    \#endif
    \+#ifdef \_SHA512
    \+static short pw_sha512(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt);
    \+#endif
    +
    static short pw_sha1(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt);
    static short pw_plain(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt);
    @@ \-318,6 \+584,10 @@
    \#if \_AES
    
    {"aes", SALT_REQUIRED, pw_aes}
    ,
    \#endif
    \+#ifdef \_SHA512
    +
    {"sha512",NO_SALT,pw_sha512}
    ,
    \+#endif
    +
    {"sha1", NO_SALT, pw_sha1}};
    typedef struct { /\* User formatting patterns \*/
    char pattern; /\* Pattern to match \*/
    @@ \-836,6 \+1106,33 @@
    return enc_len > 0 && memcmp(real_pw, encrypted_sent_pw, enc_len) == 0;
    }
    \#endif
    +
    \+#ifdef \_SHA512
    \+/\* checks sha512 passwords \*/
    \+static short pw_sha512(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt) {
    + int res;
    + short enc_len = 0;
    + char \*scrambled_sent_pw, \*buffer=PCALLOC(pool, 128);
    +
    + res = sha512_hash((uint8_t \*)sent_pw, strlen(sent_pw), buffer, 128);
    + if (res \!= SHA512_DIGEST_SIZE)
    + {
    + LOG_ERROR(APLOG_NOERRNO\|APLOG_ERR, 0, r, "auth_mysql: "
    + "Internal error: SHA512 invalid digest size");
    + return (res == SHA512_DIGEST_SIZE );
    + }
    + else
    + {
    + enc_len = apr_base64_encode_len(SHA512_DIGEST_SIZE);
    + scrambled_sent_pw = PCALLOC(pool, enc_len);
    + enc_len = apr_base64_encode(scrambled_sent_pw, buffer, SHA512_DIGEST_SIZE);
    + return (enc_len > 0 && memcmp(real_pw, scrambled_sent_pw, enc_len) == 0)
    + }
    +
    \+}
    \+#endif
    +
    +
    /\* checks SHA1 passwords \*/
    static short pw_sha1(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt) {
    
    
  5. Feb 18, 2006

    Dwight Choi says:

    Thank you~. This will be helpful for us. Has anyone compiled on win32 platfo...

    Thank you~.

    This will be helpful for us.

    Has anyone compiled on win32 platform?

    I am looking for the mod_auth_mysql.so which is patched with SHA-512 on Windows XP.

    1. Feb 20, 2006

      Justin Koke says:

      Hi Dwight, Unfortunatley we are a java house here so I do not have Visual Studi...

      Hi Dwight,

      Unfortunatley we are a java house here so I do not have Visual Studio (or similar) to compile the mod_auth_mysql.so

      I found a quick HOWTO on doing it however here: http://www.rpmcenter.org/win32/HOWTO.Win32.txt

       Justin

  6. Mar 03, 2006

    Papick G. Taboada says:

    The patch for 3.0.0 ist not working for me. Patch tells me it is garbage, if I r...

    The patch for 3.0.0 ist not working for me. Patch tells me it is garbage, if I remove the backslashes I get the error it is malformed.

    Did anyone succeed in patching against 3.0.0 ?

    brgds

    Papick 

  7. Apr 06, 2006

    scud says:

    i am sorry. some mistake in above post. because i am not try that patch. you ca...

    i am sorry. some mistake in above post. because i am not try that patch.

    you can get a complete mod_auth_mysql.c from http://wiki.javascud.org/download/attachments/2946/mod_auth_mysql.c

    compiled with my apache 2.0.55.

    don't forgot use "-D_SHA512" parameter for apxs

  8. Jun 22, 2006

    Adrian Bridgett says:

    Here is a version against 4.3.9 (specifically the debian package in sarge). Oops...

    Here is a version against 4.3.9 (specifically the debian package in sarge).
    Oops - almost posted a version with debug "print the password" code in it!
    manually removed from diff.

    Enjoy

    --- ../mod_auth_mysql.c.orig	2006-06-22 14:00:30.000000000 +0000
    +++ mod_auth_mysql.c	2006-06-22 16:26:32.000000000 +0000
    @@ -50,9 +50,11 @@
     #include "http_request.h"   /* for ap_hook_(check_user_id | auth_checker)*/
     #include <apr_md5.h>
     #include <apr_sha1.h>
    +#include <apr_base64.h>
     #else
     #include <ap_md5.h>
     #include <ap_sha1.h>
    +#include <ap.h>
     #endif
     
     #include <mysql.h>
    @@ -102,6 +104,9 @@
     #define CRYPT_ENCRYPTION_FLAG		1<<5
     #endif
     #define SHA1SUM_ENCRYPTION_FLAG		1<<6
    +#ifdef _SHA512
    +#define SHA512_ENCRYPTION_FLAG	        1<<7
    +#endif
     
     static int check_no_encryption(const char *passwd, char *enc_passwd)
     {
    @@ -226,6 +231,283 @@
     	return (!strcmp(sha1_hex_hash(passwd), enc_passwd));
     }
     
    +#ifdef _SHA512
    +/*
    + * SHA-512 code by Jean-Luc Cooke <jlcooke@certainkey.com>
    + *
    + * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com>
    + * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
    + * Copyright (c) 2003 Kyle McMartin <kyle@debian.org>
    + */ 
    + 
    +#define SHA512_DIGESTSIZE 64 
    + 
    +#define H0    0x6a09e667f3bcc908ULL 
    +#define H1    0xbb67ae8584caa73bULL 
    +#define H2    0x3c6ef372fe94f82bULL 
    +#define H3    0xa54ff53a5f1d36f1ULL 
    +#define H4    0x510e527fade682d1ULL 
    +#define H5    0x9b05688c2b3e6c1fULL 
    +#define H6    0x1f83d9abfb41bd6bULL 
    +#define H7    0x5be0cd19137e2179ULL 
    + 
    +#define e0(x) (ROR(x,28) ^ ROR(x,34) ^ ROR(x,39)) 
    +#define e1(x) (ROR(x,14) ^ ROR(x,18) ^ ROR(x,41)) 
    +#define s0(x) (ROR(x, 1) ^ ROR(x, 8) ^ (x >> 7)) 
    +#define s1(x) (ROR(x,19) ^ ROR(x,61) ^ (x >> 6)) 
    + 
    +typedef struct sha512_ctx { 
    +    uint64_t state[8]; 
    +    uint32_t count[4]; 
    +    uint8_t buf[128]; 
    +} sha512_ctx; 
    + 
    +static inline uint64_t CH(uint64_t x, uint64_t y, uint64_t z) { 
    +    return ((x & y) ^ (~x & z)); 
    +} 
    + 
    +static inline uint64_t MAJ(uint64_t x, uint64_t y, uint64_t z) { 
    +    return ((x & y) ^ (x & z) ^ (y & z)); 
    +} 
    + 
    +static inline uint64_t ROR(uint64_t x, uint64_t y) { 
    +    return (x >> y) | (x << (64 - y)); 
    +} 
    + 
    +static inline void LOA(int I, uint64_t *W, const uint8_t *input) { 
    +    uint64_t t1  = input[(8*I)] & 0xff; 
    +    t1 <<= 8; 
    +    t1 |= input[(8*I)+1] & 0xff; 
    +    t1 <<= 8; 
    +    t1 |= input[(8*I)+2] & 0xff; 
    +    t1 <<= 8; 
    +    t1 |= input[(8*I)+3] & 0xff; 
    +    t1 <<= 8; 
    +    t1 |= input[(8*I)+4] & 0xff; 
    +    t1 <<= 8; 
    +    t1 |= input[(8*I)+5] & 0xff; 
    +    t1 <<= 8; 
    +    t1 |= input[(8*I)+6] & 0xff; 
    +    t1 <<= 8; 
    +    t1 |= input[(8*I)+7] & 0xff; 
    +    W[I] = t1; 
    +} 
    + 
    +static inline void MIX(int I, uint64_t *W) { 
    +    W[I] = s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16]; 
    +} 
    + 
    +static const uint64_t sha512_K[80] = { 
    +    0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 
    +    0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 
    +    0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, 
    +    0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 
    +    0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 
    +    0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 
    +    0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, 
    +    0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 
    +    0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 
    +    0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 
    +    0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, 
    +    0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, 
    +    0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 
    +    0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 
    +    0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, 
    +    0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 
    +    0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 
    +    0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 
    +    0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, 
    +    0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, 
    +    0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 
    +    0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 
    +    0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, 
    +    0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, 
    +    0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 
    +    0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 
    +    0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL, 
    +}; 
    + 
    + 
    +static void _transform(uint64_t *state, const uint8_t *input) { 
    +    uint64_t a, b, c, d, e, f, g, h, t1, t2; 
    +    uint64_t W[80]; 
    +    int i; 
    + 
    +    /* load the input */ 
    +    for (i = 0; i < 16; i++) LOA(i, W, input); 
    +    for (i = 16; i < 80; i++) MIX(i, W); 
    + 
    +    /* load the state into our registers */ 
    +    a=state[0];   b=state[1];   c=state[2];   d=state[3]; 
    +    e=state[4];   f=state[5];   g=state[6];   h=state[7]; 
    + 
    +    /* now iterate */ 
    +    for (i=0; i<80; i+=8) { 
    +        t1 = h + e1(e) + CH(e,f,g) + sha512_K[i] + W[i]; 
    +        t2 = e0(a) + MAJ(a,b,c);    d+=t1;    h=t1+t2; 
    +        t1 = g + e1(d) + CH(d,e,f) + sha512_K[i+1] + W[i+1]; 
    +        t2 = e0(h) + MAJ(h,a,b);    c+=t1;    g=t1+t2; 
    +        t1 = f + e1(c) + CH(c,d,e) + sha512_K[i+2] + W[i+2]; 
    +        t2 = e0(g) + MAJ(g,h,a);    b+=t1;    f=t1+t2; 
    +        t1 = e + e1(b) + CH(b,c,d) + sha512_K[i+3] + W[i+3]; 
    +        t2 = e0(f) + MAJ(f,g,h);    a+=t1;    e=t1+t2; 
    +        t1 = d + e1(a) + CH(a,b,c) + sha512_K[i+4] + W[i+4]; 
    +        t2 = e0(e) + MAJ(e,f,g);    h+=t1;    d=t1+t2; 
    +        t1 = c + e1(h) + CH(h,a,b) + sha512_K[i+5] + W[i+5]; 
    +        t2 = e0(d) + MAJ(d,e,f);    g+=t1;    c=t1+t2; 
    +        t1 = b + e1(g) + CH(g,h,a) + sha512_K[i+6] + W[i+6]; 
    +        t2 = e0(c) + MAJ(c,d,e);    f+=t1;    b=t1+t2; 
    +        t1 = a + e1(f) + CH(f,g,h) + sha512_K[i+7] + W[i+7]; 
    +        t2 = e0(b) + MAJ(b,c,d);    e+=t1;    a=t1+t2; 
    +    } 
    + 
    +    state[0] += a; state[1] += b; state[2] += c; state[3] += d; 
    +    state[4] += e; state[5] += f; state[6] += g; state[7] += h; 
    + 
    +    /* erase our data */ 
    +    a = b = c = d = e = f = g = h = t1 = t2 = 0; 
    +    memset(W, 0, 80 * sizeof(uint64_t)); 
    +} 
    + 
    +static void sha512_init(void *ctx) { 
    +    struct sha512_ctx *sctx = ctx; 
    +    sctx->state[0] = H0; 
    +    sctx->state[1] = H1; 
    +    sctx->state[2] = H2; 
    +    sctx->state[3] = H3; 
    +    sctx->state[4] = H4; 
    +    sctx->state[5] = H5; 
    +    sctx->state[6] = H6; 
    +    sctx->state[7] = H7; 
    +    sctx->count[0] = sctx->count[1] = sctx->count[2] = sctx->count[3] = 0; 
    +    memset(sctx->buf, 0, sizeof(sctx->buf)); 
    +} 
    + 
    +static void sha512_update(void *ctx, const uint8_t *data, unsigned int len) { 
    +        struct sha512_ctx *sctx = ctx; 
    +        unsigned int i, index, part_len; 
    + 
    +        /* Compute number of bytes mod 128 */ 
    +        index = (unsigned int)((sctx->count[0] >> 3) & 0x7F); 
    + 
    +        /* Update number of bits */ 
    +        if ((sctx->count[0] += (len << 3)) < (len << 3)) { 
    +                if ((sctx->count[1] += 1) < 1) 
    +                        if ((sctx->count[2] += 1) < 1) 
    +                                sctx->count[3]++; 
    +                sctx->count[1] += (len >> 29); 
    +        } 
    + 
    +        part_len = 128 - index; 
    + 
    +        /* Transform as many times as possible. */ 
    +        if (len >= part_len) { 
    +                memcpy(&sctx->buf[index], data, part_len); 
    +                _transform(sctx->state, sctx->buf); 
    + 
    +                for (i = part_len; i + 127 < len; i+=128) 
    +                        _transform(sctx->state, &data[i]); 
    + 
    +                index = 0; 
    +        } else { 
    +                i = 0; 
    +        } 
    + 
    +        /* Buffer remaining input */ 
    +        memcpy(&sctx->buf[index], &data[i], len - i); 
    +} 
    + 
    +static void sha512_final(uint8_t *hash, void * ctx) { 
    +        struct sha512_ctx *sctx = ctx; 
    +        const static uint8_t padding[128] = { 0x80, }; 
    + 
    +        uint32_t t; 
    +        uint64_t t2; 
    +        uint8_t bits[128]; 
    +        unsigned int index, pad_len; 
    +        int i, j; 
    + 
    +        index = pad_len = t = i = j = 0; 
    +        t2 = 0; 
    + 
    +        /* Save number of bits */ 
    +        t = sctx->count[0]; 
    +        bits[15] = t; t>>=8; 
    +        bits[14] = t; t>>=8; 
    +        bits[13] = t; t>>=8; 
    +        bits[12] = t; 
    +        t = sctx->count[1]; 
    +        bits[11] = t; t>>=8; 
    +        bits[10] = t; t>>=8; 
    +        bits[9 ] = t; t>>=8; 
    +        bits[8 ] = t; 
    +        t = sctx->count[2]; 
    +        bits[7 ] = t; t>>=8; 
    +        bits[6 ] = t; t>>=8; 
    +        bits[5 ] = t; t>>=8; 
    +        bits[4 ] = t; 
    +        t = sctx->count[3]; 
    +        bits[3 ] = t; t>>=8; 
    +        bits[2 ] = t; t>>=8; 
    +        bits[1 ] = t; t>>=8; 
    +        bits[0 ] = t; 
    + 
    +        /* Pad out to 112 mod 128. */ 
    +        index = (sctx->count[0] >> 3) & 0x7f; 
    +        pad_len = (index < 112) ? (112 - index) : ((128+112) - index); 
    +        sha512_update(sctx, padding, pad_len); 
    + 
    +        /* Append length (before padding) */ 
    +        sha512_update(sctx, bits, 16); 
    + 
    +        /* Store state in digest */ 
    +        for (i = j = 0; i < 8; i++, j += 8) { 
    +                t2 = sctx->state[i]; 
    +                hash[j+7] = (char)t2 & 0xff; t2>>=8; 
    +                hash[j+6] = (char)t2 & 0xff; t2>>=8; 
    +                hash[j+5] = (char)t2 & 0xff; t2>>=8; 
    +                hash[j+4] = (char)t2 & 0xff; t2>>=8; 
    +                hash[j+3] = (char)t2 & 0xff; t2>>=8; 
    +                hash[j+2] = (char)t2 & 0xff; t2>>=8; 
    +                hash[j+1] = (char)t2 & 0xff; t2>>=8; 
    +                hash[j  ] = (char)t2 & 0xff; 
    +        } 
    + 
    +        /* Zeroize sensitive information. */ 
    +        memset(sctx, 0, sizeof(struct sha512_ctx)); 
    +} 
    + 
    +static char * sha512_hex_hash(const char * passwd) {
    +	int enc_len;
    +
    +	sha512_ctx ct;
    +	char hash[SHA512_DIGESTSIZE];
    +	/* two extra - one for padding, one for \0 */
    +	static char real_hash[SHA512_DIGESTSIZE * 4 / 3 + 2];
    +
    +	sha512_init(&ct);
    +	sha512_update(&ct, passwd, strlen(passwd));
    +	sha512_final(hash, &ct);
    +
    +        /* base64 encode it */
    +#ifdef APACHE2
    +	enc_len = apr_base64_encode_len(SHA512_DIGESTSIZE);
    +	enc_len = apr_base64_encode(real_hash, hash, SHA512_DIGESTSIZE);
    +#else
    +	enc_len = ap_base64encode_len(SHA512_DIGESTSIZE);
    +	enc_len = ap_base64encode(real_hash, hash, SHA512_DIGESTSIZE);
    +#endif
    +
    +	return real_hash;
    +}
    +
    +static int check_SHA512_encryption(const char *passwd, char *enc_passwd)
    +{
    +	return (!strcmp(sha512_hex_hash(passwd), enc_passwd));
    +}
    +
    + 
    +#endif //_SHA512 
     
     static int check_mysql_encryption(const char *passwd, char *enc_passwd)
     {
    @@ -253,6 +535,7 @@
     	{ "Crypt",		check_crypt_encryption,			CRYPT_ENCRYPTION_FLAG },
     	{ "PHP_MD5",		check_PHP_MD5_encryption,		PHP_MD5_ENCRYPTION_FLAG	},
     	{ "SHA1Sum",	check_SHA1Sum_encryption, SHA1SUM_ENCRYPTION_FLAG},
    +	{ "SHA512",	check_SHA512_encryption, SHA512_ENCRYPTION_FLAG},
     	/* add additional encryption types below */
     	{ NULL,			NULL,					0 }
     };
    
  9. Sep 13, 2006

    Clint Hanson says:

    The command to compile for RHEL 4.0 using the source in the link provided by scu...

    The command to compile for RHEL 4.0 using the source in the link provided by scud above is

    apxs -D_SHA512 -lmysqlclient -I /usr/include/mysql -L /usr/lib/mysql -ci mod_auth_mysql.c

    This makes sure to grab the library for the client and was only way I could get apache 2 installed out of the box to recognize and start with the new module.

     NOTE make sure to keep a backup of your old mod_auth_mysql.so if you have any mysql controlled resources and you don't want to have to uninstall and reinstall the RPM. 

  10. Oct 13, 2006

    Volker Meyer-Simon says:

    In the last days, I've compiled the Version 3.0.0 with the sha512 patch included...

    In the last days, I've compiled the Version 3.0.0 with the sha512 patch included sucessfully against Apapche 2.2.x

    Here is the diff vor the 3.0.0 version of mod_auth_mysql, I removed the #ifdef _SHA512 statements

    --- mod_auth_mysql.c	2006-10-13 10:53:05.000000000 +0200
    +++ mod_auth_mysql_patched.c	2006-10-10 13:50:11.000000000 +0200
    @@ -50,7 +50,6 @@
      *
      */
     
    -
     /*
      * Module definition information - the part between the -START and -END
      * lines below is used by Configure. This could be stored in a separate
    @@ -206,7 +205,7 @@
       #define SNPRINTF apr_snprintf
       #define PSTRDUP apr_pstrdup
       #define PSTRNDUP apr_pstrndup
    -  #define STRCAT ap_pstrcat
    +  #define STRCAT apr_pstrcat
       #define POOL apr_pool_t
       #include "http_request.h"   /* for ap_hook_(check_user_id | auth_checker)*/
       #include "ap_compat.h"
    @@ -271,6 +270,267 @@
       #include <my_aes.h>
     #endif
     
    +
    +/*
    + * SHA-512 code by Jean-Luc Cooke <jlcooke@certainkey.com>
    + *
    + * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com>
    + * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
    + * Copyright (c) 2003 Kyle McMartin <kyle@debian.org>
    + */
    +
    +#define SHA512_DIGEST_SIZE 64
    +
    +#define H0    0x6a09e667f3bcc908ULL
    +#define H1    0xbb67ae8584caa73bULL
    +#define H2    0x3c6ef372fe94f82bULL
    +#define H3    0xa54ff53a5f1d36f1ULL
    +#define H4    0x510e527fade682d1ULL
    +#define H5    0x9b05688c2b3e6c1fULL
    +#define H6    0x1f83d9abfb41bd6bULL
    +#define H7    0x5be0cd19137e2179ULL
    +
    +#define e0(x) (ROR(x,28) ^ ROR(x,34) ^ ROR(x,39))
    +#define e1(x) (ROR(x,14) ^ ROR(x,18) ^ ROR(x,41))
    +#define s0(x) (ROR(x, 1) ^ ROR(x, 8) ^ (x >> 7))
    +#define s1(x) (ROR(x,19) ^ ROR(x,61) ^ (x >> 6))
    +
    +typedef struct sha512_ctx {
    +    uint64_t state[8];
    +    uint32_t count[4];
    +    uint8_t buf[128];
    +} sha512_ctx;
    +
    +static inline uint64_t CH(uint64_t x, uint64_t y, uint64_t z) {
    +    return ((x & y) ^ (~x & z));
    +}
    +
    +static inline uint64_t MAJ(uint64_t x, uint64_t y, uint64_t z) {
    +    return ((x & y) ^ (x & z) ^ (y & z));
    +}
    +
    +static inline uint64_t ROR(uint64_t x, uint64_t y) {
    +    return (x >> y) | (x << (64 - y));
    +}
    +
    +static inline void LOA(int I, uint64_t *W, const uint8_t *input) {
    +    uint64_t t1  = input[(8*I)  ] & 0xff;
    +    t1 <<= 8;
    +    t1 |= input[(8*I)+1] & 0xff;
    +    t1 <<= 8;
    +    t1 |= input[(8*I)+2] & 0xff;
    +    t1 <<= 8;
    +    t1 |= input[(8*I)+3] & 0xff;
    +    t1 <<= 8;
    +    t1 |= input[(8*I)+4] & 0xff;
    +    t1 <<= 8;
    +    t1 |= input[(8*I)+5] & 0xff;
    +    t1 <<= 8;
    +    t1 |= input[(8*I)+6] & 0xff;
    +    t1 <<= 8;
    +    t1 |= input[(8*I)+7] & 0xff;
    +    W[I] = t1;
    +}
    +
    +static inline void MIX(int I, uint64_t *W) {
    +    W[I] = s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16];
    +}
    +
    +static const uint64_t sha512_K[80] = {
    +    0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
    +    0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
    +    0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
    +    0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
    +    0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
    +    0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
    +    0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
    +    0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
    +    0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
    +    0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
    +    0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
    +    0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
    +    0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
    +    0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
    +    0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
    +    0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
    +    0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
    +    0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
    +    0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
    +    0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
    +    0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
    +    0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
    +    0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
    +    0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
    +    0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
    +    0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
    +    0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL,
    +};
    +
    +
    +static void _transform(uint64_t *state, const uint8_t *input) {
    +    uint64_t a, b, c, d, e, f, g, h, t1, t2;
    +    uint64_t W[80];
    +    int i;
    +
    +    /* load the input */
    +    for (i = 0; i < 16; i++) LOA(i, W, input);
    +    for (i = 16; i < 80; i++) MIX(i, W);
    +
    +    /* load the state into our registers */
    +    a=state[0];   b=state[1];   c=state[2];   d=state[3];
    +    e=state[4];   f=state[5];   g=state[6];   h=state[7];
    +
    +    /* now iterate */
    +    for (i=0; i<80; i+=8) {
    +        t1 = h + e1(e) + CH(e,f,g) + sha512_K[i  ] + W[i  ];
    +        t2 = e0(a) + MAJ(a,b,c);    d+=t1;    h=t1+t2;
    +        t1 = g + e1(d) + CH(d,e,f) + sha512_K[i+1] + W[i+1];
    +        t2 = e0(h) + MAJ(h,a,b);    c+=t1;    g=t1+t2;
    +        t1 = f + e1(c) + CH(c,d,e) + sha512_K[i+2] + W[i+2];
    +        t2 = e0(g) + MAJ(g,h,a);    b+=t1;    f=t1+t2;
    +        t1 = e + e1(b) + CH(b,c,d) + sha512_K[i+3] + W[i+3];
    +        t2 = e0(f) + MAJ(f,g,h);    a+=t1;    e=t1+t2;
    +        t1 = d + e1(a) + CH(a,b,c) + sha512_K[i+4] + W[i+4];
    +        t2 = e0(e) + MAJ(e,f,g);    h+=t1;    d=t1+t2;
    +        t1 = c + e1(h) + CH(h,a,b) + sha512_K[i+5] + W[i+5];
    +        t2 = e0(d) + MAJ(d,e,f);    g+=t1;    c=t1+t2;
    +        t1 = b + e1(g) + CH(g,h,a) + sha512_K[i+6] + W[i+6];
    +        t2 = e0(c) + MAJ(c,d,e);    f+=t1;    b=t1+t2;
    +        t1 = a + e1(f) + CH(f,g,h) + sha512_K[i+7] + W[i+7];
    +        t2 = e0(b) + MAJ(b,c,d);    e+=t1;    a=t1+t2;
    +    }
    +
    +    state[0] += a; state[1] += b; state[2] += c; state[3] += d;
    +    state[4] += e; state[5] += f; state[6] += g; state[7] += h;
    +
    +    /* erase our data */
    +    a = b = c = d = e = f = g = h = t1 = t2 = 0;
    +    memset(W, 0, 80 * sizeof(uint64_t));
    +}
    +
    +static void sha512_init(void *ctx) {
    +    struct sha512_ctx *sctx = ctx;
    +    sctx->state[0] = H0;
    +    sctx->state[1] = H1;
    +    sctx->state[2] = H2;
    +    sctx->state[3] = H3;
    +    sctx->state[4] = H4;
    +    sctx->state[5] = H5;
    +    sctx->state[6] = H6;
    +    sctx->state[7] = H7;
    +    sctx->count[0] = sctx->count[1] = sctx->count[2] = sctx->count[3] = 0;
    +    memset(sctx->buf, 0, sizeof(sctx->buf));
    +}
    +
    +static void sha512_update(void *ctx, const uint8_t *data, unsigned int len) {
    +        struct sha512_ctx *sctx = ctx;
    +        unsigned int i, index, part_len;
    +
    +        /* Compute number of bytes mod 128 */
    +        index = (unsigned int)((sctx->count[0] >> 3) & 0x7F);
    +
    +        /* Update number of bits */
    +        if ((sctx->count[0] += (len << 3)) < (len << 3)) {
    +                if ((sctx->count[1] += 1) < 1)
    +                        if ((sctx->count[2] += 1) < 1)
    +                                sctx->count[3]++;
    +                sctx->count[1] += (len >> 29);
    +        }
    +
    +        part_len = 128 - index;
    +
    +        /* Transform as many times as possible. */
    +        if (len >= part_len) {
    +                memcpy(&sctx->buf[index], data, part_len);
    +                _transform(sctx->state, sctx->buf);
    +
    +                for (i = part_len; i + 127 < len; i+=128)
    +                        _transform(sctx->state, &data[i]);
    +
    +                index = 0;
    +        } else {
    +                i = 0;
    +        }
    +
    +        /* Buffer remaining input */
    +        memcpy(&sctx->buf[index], &data[i], len - i);
    +}
    +
    +static void sha512_final(void *ctx, uint8_t *hash) {
    +        struct sha512_ctx *sctx = ctx;
    +        const static uint8_t padding[128] = { 0x80, };
    +
    +        uint32_t t;
    +        uint64_t t2;
    +        uint8_t bits[128];
    +        unsigned int index, pad_len;
    +        int i, j;
    +
    +        index = pad_len = t = i = j = 0;
    +        t2 = 0;
    +
    +        /* Save number of bits */
    +        t = sctx->count[0];
    +        bits[15] = t; t>>=8;
    +        bits[14] = t; t>>=8;
    +        bits[13] = t; t>>=8;
    +        bits[12] = t;
    +        t = sctx->count[1];
    +        bits[11] = t; t>>=8;
    +        bits[10] = t; t>>=8;
    +        bits[9 ] = t; t>>=8;
    +        bits[8 ] = t;
    +        t = sctx->count[2];
    +        bits[7 ] = t; t>>=8;
    +        bits[6 ] = t; t>>=8;
    +        bits[5 ] = t; t>>=8;
    +        bits[4 ] = t;
    +        t = sctx->count[3];
    +        bits[3 ] = t; t>>=8;
    +        bits[2 ] = t; t>>=8;
    +        bits[1 ] = t; t>>=8;
    +        bits[0 ] = t;
    +
    +        /* Pad out to 112 mod 128. */
    +        index = (sctx->count[0] >> 3) & 0x7f;
    +        pad_len = (index < 112) ? (112 - index) : ((128+112) - index);
    +        sha512_update(sctx, padding, pad_len);
    +
    +        /* Append length (before padding) */
    +        sha512_update(sctx, bits, 16);
    +
    +        /* Store state in digest */
    +        for (i = j = 0; i < 8; i++, j += 8) {
    +                t2 = sctx->state[i];
    +                hash[j+7] = (char)t2 & 0xff; t2>>=8;
    +                hash[j+6] = (char)t2 & 0xff; t2>>=8;
    +                hash[j+5] = (char)t2 & 0xff; t2>>=8;
    +                hash[j+4] = (char)t2 & 0xff; t2>>=8;
    +                hash[j+3] = (char)t2 & 0xff; t2>>=8;
    +                hash[j+2] = (char)t2 & 0xff; t2>>=8;
    +                hash[j+1] = (char)t2 & 0xff; t2>>=8;
    +                hash[j  ] = (char)t2 & 0xff;
    +        }
    +
    +        /* Zeroize sensitive information. */
    +        memset(sctx, 0, sizeof(struct sha512_ctx));
    +}
    +
    +static int sha512_hash(uint8_t *orig, int origlen, uint8_t *hash, int hashlen) {
    +    sha512_ctx context;
    +
    +    if (hash == NULL) return -1;
    +    if (hashlen < SHA512_DIGEST_SIZE) return -1;
    +
    +    sha512_init(&context);
    +    sha512_update(&context, orig, origlen);
    +    sha512_final(&context, hash);
    +    return(SHA512_DIGEST_SIZE);
    +}
    +
    +
    +
    +
     #ifndef SCRAMBLED_PASSWORD_CHAR_LENGTH /* Ensure it is defined for older MySQL releases */
       #define SCRAMBLED_PASSWORD_CHAR_LENGTH 32 /* Big enough for the old method of scrambling */
     #endif
    @@ -287,6 +547,8 @@
     #if _AES
     static short pw_aes(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt);
     #endif
    +static short pw_sha512(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt);
    +
     static short pw_sha1(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt);
     static short pw_plain(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt);
     
    @@ -318,6 +580,8 @@
     #if _AES
     					   {"aes", SALT_REQUIRED, pw_aes},
     #endif
    +					   {"sha512",NO_SALT,pw_sha512},
    +
     					   {"sha1", NO_SALT, pw_sha1}};
     typedef struct {		/* User formatting patterns */
       char pattern;			/* Pattern to match */
    @@ -589,87 +853,87 @@
     static
     command_rec mysql_auth_cmds[] = {
     	AP_INIT_TAKE1("AuthMySQLHost", ap_set_string_slot,
    -	(void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlhost),
    +	(void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlhost),
     	OR_AUTHCFG, "mysql server host name"),
     
     	AP_INIT_TAKE1("AuthMySQLPort", ap_set_int_slot,
    -	(void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlport),
    +	(void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlport),
     	OR_AUTHCFG, "mysql server port number"),
     
     	AP_INIT_TAKE1("AuthMySQLSocket", ap_set_string_slot,
    -	(void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlsocket),
    +	(void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlsocket),
     	OR_AUTHCFG, "mysql server socket path"),
     
     	AP_INIT_TAKE1("AuthMySQLUser", ap_set_string_slot,
    -	(void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqluser),
    +	(void *) APR_OFFSETOF(mysql_auth_config_rec, mysqluser),
     	OR_AUTHCFG, "mysql server user name"),
     
     	AP_INIT_TAKE1("AuthMySQLPassword", ap_set_string_slot,
    -	(void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlpasswd),
    +	(void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlpasswd),
     	OR_AUTHCFG, "mysql server user password"),
     
     	AP_INIT_TAKE1("AuthMySQLDB", ap_set_string_slot,
    -	(void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlDB),
    +	(void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlDB),
     	OR_AUTHCFG, "mysql database name"),
     
     	AP_INIT_TAKE1("AuthMySQLUserTable", ap_set_string_slot,
    -	(void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlpwtable),
    +	(void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlpwtable),
     	OR_AUTHCFG, "mysql user table name"),
     
     	AP_INIT_TAKE1("AuthMySQLGroupTable", ap_set_string_slot,
    -	(void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlgrptable),
    +	(void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlgrptable),
     	OR_AUTHCFG, "mysql group table name"),
     
     	AP_INIT_TAKE1("AuthMySQLNameField", ap_set_string_slot,
    -	(void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlNameField),
    +	(void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlNameField),
     	OR_AUTHCFG, "mysql User ID field name within User table"),
     
     	AP_INIT_TAKE1("AuthMySQLGroupField", ap_set_string_slot,
    -	(void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlGroupField),
    +	(void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlGroupField),
     	OR_AUTHCFG, "mysql Group field name within table"),
     
     	AP_INIT_TAKE1("AuthMySQLGroupUserNameField", ap_set_string_slot,
    -	(void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlGroupUserNameField),
    +	(void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlGroupUserNameField),
     	OR_AUTHCFG, "mysql User ID field name within Group table"),
     
     	AP_INIT_TAKE1("AuthMySQLPasswordField", ap_set_string_slot,
    -	(void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlPasswordField),
    +	(void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlPasswordField),
     	OR_AUTHCFG, "mysql Password field name within table"),
     
     	AP_INIT_TAKE1("AuthMySQLPwEncryption", ap_set_string_slot,
    -	(void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlEncryptionField),
    +	(void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlEncryptionField),
     	OR_AUTHCFG, "mysql password encryption method"),
     
     	AP_INIT_TAKE1("AuthMySQLSaltField", ap_set_string_slot,
    -	(void*) APR_XtOffsetOf(mysql_auth_config_rec, mysqlSaltField),
    +	(void*) APR_OFFSETOF(mysql_auth_config_rec, mysqlSaltField),
     	OR_AUTHCFG, "mysql salfe field name within table"),
     
     /*	AP_INIT_FLAG("AuthMySQLKeepAlive", ap_set_flag_slot,
    -	(void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlKeepAlive),
    +	(void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlKeepAlive),
     	OR_AUTHCFG, "mysql connection kept open across requests if On"),
     */
     	AP_INIT_FLAG("AuthMySQLAuthoritative", ap_set_flag_slot,
    -	(void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlAuthoritative),
    +	(void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlAuthoritative),
     	OR_AUTHCFG, "mysql lookup is authoritative if On"),
     
     	AP_INIT_FLAG("AuthMySQLNoPasswd", ap_set_flag_slot,
    -	(void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlNoPasswd),
    +	(void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlNoPasswd),
     	OR_AUTHCFG, "If On, only check if user exists; ignore password"),
     
     	AP_INIT_FLAG("AuthMySQLEnable", ap_set_flag_slot,
    -	(void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlEnable),
    +	(void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlEnable),
     	OR_AUTHCFG, "enable mysql authorization"),
     
     	AP_INIT_TAKE1("AuthMySQLUserCondition", ap_set_string_slot,
    -	(void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlUserCondition),
    +	(void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlUserCondition),
     	OR_AUTHCFG, "condition to add to user where-clause"),
     
     	AP_INIT_TAKE1("AuthMySQLGroupCondition", ap_set_string_slot,
    -	(void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlGroupCondition),
    +	(void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlGroupCondition),
     	OR_AUTHCFG, "condition to add to group where-clause"),
     
     	AP_INIT_TAKE1("AuthMySQLCharacterSet", ap_set_string_slot,
    -	(void *) APR_XtOffsetOf(mysql_auth_config_rec, mysqlCharacterSet),
    +	(void *) APR_OFFSETOF(mysql_auth_config_rec, mysqlCharacterSet),
     	OR_AUTHCFG, "mysql character set to be used"),
     
       { NULL }
    @@ -837,6 +1101,33 @@
     }
     #endif
     
    +/* checks sha512 passwords */
    +static short pw_sha512(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt) {
    +	int res;
    +	short enc_len = 0;
    +	char *scrambled_sent_pw, *buffer=PCALLOC(pool, 128);
    +	
    +    res = sha512_hash((uint8_t *)sent_pw, strlen(sent_pw), buffer, 128);
    +    if (res != SHA512_DIGEST_SIZE) 
    +    {
    +        /*
    +        LOG_ERROR(APLOG_NOERRNO|APLOG_ERR, 0, r, "auth_mysql: "
    +                    "Internal error: SHA512 invalid digest size");
    +        */            
    +        return (res == SHA512_DIGEST_SIZE );
    +    } 
    +    else 
    +    {
    +        enc_len = apr_base64_encode_len(SHA512_DIGEST_SIZE);
    +        scrambled_sent_pw = PCALLOC(pool, enc_len);
    +        enc_len = apr_base64_encode(scrambled_sent_pw, buffer, SHA512_DIGEST_SIZE);
    +        return (enc_len > 0 && memcmp(real_pw, scrambled_sent_pw, enc_len) == 0) ;
    +    }
    +	
    +}
    +
    +
    +
     /* checks SHA1 passwords */
     static short pw_sha1(POOL * pool, const char * real_pw, const char * sent_pw, const char * salt) {
       char *scrambled_sent_pw, *buffer=PCALLOC(pool, 128);
    @@ -1378,4 +1669,3 @@
     };
     #endif
     
    -
    

    Usage: patch -b -p0 --ignore-whitespace < mod_auth_mysql.diff to patch the original file

    Use the following Statements to config Apache 2.2

    
    # This will enable authentication and make sure that the MySQL plugin is
    # called to validate users
    
    AuthName                     "Simple Jira-based authentication"
    AuthType                     Basic
    # Importand to prevent errors from apache
    AuthBasicAuthoritative       Off
    AuthMySQLEnable              On
    
    # Details of the connection to the MySQL database, you can normally use a UNIX
    # socket or a TCP socket.
    
    # For TCP/IP
    AuthMySQLHost                localhost
    AuthMySQLPort                3306
    
    # For UNIX sockets
    AuthMySQLSocket             /var/lib/mysql/mysql.sock
    
    # The user name and password below are used by Apache to connect to MySQL,
    # you should specify the ones you supplied during your Jira installation
    
    AuthMySQLUser                <YOUR JIRA USER NAME>
    AuthMySQLPassword            <YOUR JIRA USER PASSWORD>
    AuthMySQLDB                  <YOUR JIRA DB NAME>
    
    # Here follows a description of the OpenSymphony user database layout (as
    # used by Jira):
    #
    # - userbase: is the user database table
    #   - fields: username/password_hash: 
    #
    # - groupbase: is the group database table
    #   - fields: groupname
    #
    # - membershipbase: associates users to groups
    #   - fields: group_name, user_name
    #
    # The long AuthMySQLGroupCondition string is used to join those three tables
    # together as there is no way to specify different user name fields in the
    # mod_auth_mysql configuration for user and group tables.
    
    AuthMySQLUserTable           userbase
    AuthMySQLGroupTable          userbase,groupbase,membershipbase
    
    AuthMySQLGroupCondition      "username=user_name and groupname=group_name"
    
    AuthMySQLNameField           username
    AuthMySqlGroupField          groupname
    AuthMySQLPasswordField       password_hash
    
    # Force the encryption algorighm used for passwords to be SHA-512, the one
    # used by Jira and OpenSymphony when relying on a JDBC backend
    
    AuthMySQLPwEncryption        sha512
    
    # Make sure that MySQL/Jira authentication is authoritative (no other
    # modules will be able to authenticate users)
    
    AuthMySQLAuthoritative       On
    
    # Keep the connection between Apache and MySQL alive (useful on TCP/IP based
    # connections, but buggy on Apache 2)
    
    #AuthMySQLKeepAlive           On
    
    # Restrict access to this resource by specifying the different Require
    # directives. Both users and groups from Jira are supported at this poing,
    # see <http://httpd.apache.org/docs-2.0/mod/core.html#require>
    
    Require group                jira-users
    

    Insert the

    LoadModule mysql_auth_module     modules/mod_auth_mysql.so
    

    before any other LoadModule directive

  11. Apr 14, 2008

    Thijs Wassenaar says:

    I'm havving some difficulties with installing the mod_auth_mysql.c When i input ...

    I'm havving some difficulties with installing the mod_auth_mysql.c
    When i input this command i get the following error in return.
     

    1. apxs -c -L/usr/lib/mysql -I/usr/include/mysql -lmysqlclient -lm -lz mod_auth_mysql.c
      /usr/lib/apr-1/build/libtool --silent --mode=compile gcc -prefer-pic -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=generic -fasynchronous-unwind-tables -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE -pthread -I/usr/include/httpd -I/usr/include/apr-1 -I/usr/include/apr-1 -I/usr/include/mysql -c -o mod_auth_mysql.lo mod_auth_mysql.c && touch mod_auth_mysql.slo
      mod_auth_mysql.c:591: warning: implicit declaration of function 'APR_XtOffsetOf'
      mod_auth_mysql.c:591: error: expected expression before 'mysql_auth_config_rec'
      mod_auth_mysql.c:591: error: initializer element is not constant
      mod_auth_mysql.c:591: error: (near initialization for 'mysql_auth_cmds[0].cmd_data')
      mod_auth_mysql.c:595: error: expected expression before 'mysql_auth_config_r