Re: [Dovecot] Linux should be as easy as Windows

2010-08-18 Thread Alain Williams
On Thu, Aug 19, 2010 at 12:39:49AM +0300, Uldis Pakuls wrote:

> I have used a lots of differer OS. First one was Solars, the IBM OS/2,
> then AIX, Then came "a shock therapy" - DOS. For a long time I can't
> believe that someone developed OS on which you can run only one program
> in same time.:) Then graphical GUI appeared for DOS - Windows 3.x - 9x

Blame that on IBM, to save a few dollars on cost it used a 16 bit CPU w/out 
memory
protection. If they had used a motorola m68k (32 bit) CPU & an MMU chip
we would all have been saved an enormous amount of agony. Although Bill
G would have had to write DOS from scratch rather than buy it in.
But then: IBM thought that it was only going to sell 50,000 of these
machines so it wasn't really worth the bother to get the design right :-(

-- 
Alain Williams
Linux/GNU Consultant - Mail systems, Web sites, Networking, Programmer, IT 
Lecturer.
+44 (0) 787 668 0256  http://www.phcomp.co.uk/
Parliament Hill Computers Ltd. Registration Information: 
http://www.phcomp.co.uk/contact.php
Past chairman of UKUUG: http://www.ukuug.org/
#include 


Re: [Dovecot] Bug in driver-mysql.c + fix

2010-03-10 Thread Alain Williams
On Wed, Mar 10, 2010 at 04:18:19PM +0200, Timo Sirainen wrote:

> On Fri, 2010-03-05 at 23:44 +0000, Alain Williams wrote:
...
> > This failed with the message:
> > User query failed: PROCEDURE imap.user_info can't return a result set 
> > in the given context
> 
> I thought it was possible to avoid that error by implementing the MySQL
> procedure in a specific way?..

I have tried ... see another thread.

See:
http://dev.mysql.com/doc/refman/5.1/en/mysql-real-connect.html

Just under the table near the top it says:

If your program uses CALL statements to execute stored procedures, the 
CLIENT_MULTI_RESULTS flag must be enabled.

> > The root of this problem is that mysql_real_connect() needs to be called 
> > with option CLIENT_MULTI_RESULTS
> 
> The problem with doing that is that 1) it's not normally necessary and
> more importantly 2) doing that makes any potential SQL injection
> security holes a lot easier to exploit. So I'm not all that eager in
> adding such code, especially if it can be worked around another way..

CLIENT_MULTI_STATEMENTS allows multiple statements in one call (you separate by 
',').
CLIENT_MULTI_RESULTS does not imply CLIENT_MULTI_STATEMENTS.
Is this what you were concerned about ?

Look at the URL above for details.

> > I am looking to use mysql procedures, there are some interesting things 
> > that can be done.
> > Two suggestions that I have will help with this:
> > 
> > 1) There be variable (say) %o - this be the obscured password, ie what 
> > password_query returns.
> > 
> > 2) that dovecot look for either ''password_query'' as above, or 
> > ''password_check''.
> >password_check would NOT return a password, but would be given %o and 
> > determine
> >itself if the password is correct.
> >It would return the other values (user, userdb_home, ...) and auth_result
> >that would encode success/retry/fail (0, 1, 2 - or maybe more structured 
> > [**])
> >and auth_reason some human readable reason.
> >The ''nologin'' value encodes some of this.
> > 
> > The motivation for this is that my stored procedure will record the number 
> > of successive
> > login failures and lock the account after 3 of them. It would also be 
> > possible to
> > do time based restrictions & the such.
> > 
> > Also: by passing %o the password is not sent in plain to the database 
> > server - which
> > will increase security.
> 
> So what kind of obscuring where you thinking about? You could already
> use "%Mw", which gives you MD5 of the password.

That is not how I store passwords - I keep them as DIGEST-MD5, this is:
md5('username:domain:password')
So I want %o to be that value. Squirrelmail should be able to deduce that from
the line in the dovecot-sql.conf:
default_pass_scheme="DIGEST-MD5"

> And password_query can already do basically what you were thinking about
> with password_check:
> 
> password_query = select NULL as password, 'Y' as nopassword FROM users
> WHERE username = '%u' and password = '%w'
> 
> or something. The main problem with that is that it can't differentiate
> between "wrong password" and "user doesn't exist", so it logs all
> password failures as "user doesn't exist".

I am trying to find a definition of the API to plugins, ...
if the SQL stored procedure can return arbitrary variables that can then be used
by PHP plugins then I can do things like issuing a warning about the password
about to expire, number of failed login attempts since the last success, ...
Ie all sorts of things that the authentication stored procedures could store
and manage.

-- 
Alain Williams
Linux/GNU Consultant - Mail systems, Web sites, Networking, Programmer, IT 
Lecturer.
+44 (0) 787 668 0256  http://www.phcomp.co.uk/
Parliament Hill Computers Ltd. Registration Information: 
http://www.phcomp.co.uk/contact.php
Past chairman of UKUUG: http://www.ukuug.org/
#include 


Re: [Dovecot] Bug in driver-mysql.c + fix

2010-03-10 Thread Alain Williams
On Wed, Mar 10, 2010 at 04:23:23PM +0200, Timo Sirainen wrote:
> On Wed, 2010-03-10 at 16:18 +0200, Timo Sirainen wrote:
> > >   password_query = CALL user_pass_check('%n', '%d', '%w')
> > > 
> > >   user_query = CALL user_info('%n', '%d')
> > > 
> > > This failed with the message:
> > >   User query failed: PROCEDURE imap.user_info can't return a result set 
> > > in the given context
> > 
> > I thought it was possible to avoid that error by implementing the MySQL
> > procedure in a specific way?..
> 
> "Statements that return a result set can be used within a stored
> procedcure but not within a stored function. This prohibition includes
> SELECT statements that do not have an INTO var_list clause and other
> statements such as SHOW, EXPLAIN, and CHECK TABLE."
> 
> Sounds like if you used SELECT .. INTO and returned those variables, it
> would work?

I tried that just now, with my patch not implemented and get the error about 
'context' above
Unfortunately that does not seem to work.

The SQL that I am using is below, if someone can make it work without my patch
I would be grateful.

DROP PROCEDURE IF EXISTS user_pass_check_t !!

CREATE PROCEDURE user_pass_check_t(local_part TEXT, in_domain TEXT, test_pass 
TEXT)
NOT DETERMINISTIC  -- login state of the user may change
COMMENT "Return user information as needed by dovecot"
BEGIN
DECLARE usr_addr   VARCHAR(128);
DECLARE usr_pass   VARCHAR(64);
DECLARE usr_home   VARCHAR(256);
DECLARE usr_uidINTEGER;
DECLARE usr_gidINTEGER;

SELECT CONCAT(userid, '@', domain), CONCAT('{DIGEST-MD5}', password), home, 
uid, gid \
  INTO usr_addr, usr_pass, usr_home, usr_uid, usr_gid
      FROM imap.users WHERE userid = local_part AND domain = in_domain;

SELECT usr_addr AS user, usr_pass AS password, usr_home AS userdb_home, 
usr_uid AS userdb_uid, usr_gid AS userdb_gid;
END !!




-- 
Alain Williams
Linux/GNU Consultant - Mail systems, Web sites, Networking, Programmer, IT 
Lecturer.
+44 (0) 787 668 0256  http://www.phcomp.co.uk/
Parliament Hill Computers Ltd. Registration Information: 
http://www.phcomp.co.uk/contact.php
Past chairman of UKUUG: http://www.ukuug.org/
#include 


[Dovecot] Bug in driver-mysql.c + fix

2010-03-05 Thread Alain Williams
I tried to use MySQL stored procedures from dovecot:

password_query = CALL user_pass_check('%n', '%d', '%w')

user_query = CALL user_info('%n', '%d')

This failed with the message:
User query failed: PROCEDURE imap.user_info can't return a result set 
in the given context

The root of this problem is that mysql_real_connect() needs to be called with 
option CLIENT_MULTI_RESULTS
and mysql_next_result() called to retrieve extra results (that will not exist 
in the way that we use it).
I attach a patch that fixes this problem -- the patch is against dovecot-1.2.10.
This works for me ... but could probably do with testing by other people.

BTW: I got the same problem with exim this morning, wrote a patch that has now 
been accepted.
The dovecot patch is similar.


I am looking to use mysql procedures, there are some interesting things that 
can be done.
Two suggestions that I have will help with this:

1) There be variable (say) %o - this be the obscured password, ie what 
password_query returns.

2) that dovecot look for either ''password_query'' as above, or 
''password_check''.
   password_check would NOT return a password, but would be given %o and 
determine
   itself if the password is correct.
   It would return the other values (user, userdb_home, ...) and auth_result
   that would encode success/retry/fail (0, 1, 2 - or maybe more structured 
[**])
   and auth_reason some human readable reason.
   The ''nologin'' value encodes some of this.

The motivation for this is that my stored procedure will record the number of 
successive
login failures and lock the account after 3 of them. It would also be possible 
to
do time based restrictions & the such.

Also: by passing %o the password is not sent in plain to the database server - 
which
will increase security.

I will publish my stored procedures when done.

Regards

[**] eg taking ideas from the HTTP codes:
200 - OK
300 5 - try again in 5 minutes
301 2 9 - try again on tuesday at 9am
400 - Login forbidden, no reason given
401 - bad username and/or password
402 - account locked administratively
403 - too many failed login attempts
500 - authentication system error
The above would allow a native language version of auth_reason to be produced

-- 
Alain Williams
Linux/GNU Consultant - Mail systems, Web sites, Networking, Programmer, IT 
Lecturer.
+44 (0) 787 668 0256  http://www.phcomp.co.uk/
Parliament Hill Computers Ltd. Registration Information: 
http://www.phcomp.co.uk/contact.php
Past chairman of UKUUG: http://www.ukuug.org/
#include 
--- driver-mysql.c  2010-03-05 19:38:10.512212871 +
+++ driver-mysql.c  2010-03-05 19:38:17.0 +
@@ -132,9 +132,10 @@
}
 
alarm(MYSQL_CONNECT_FAILURE_TIMEOUT);
+   /* CLIENT_MULTI_RESULTS allows the use of stored procedures */
failed = mysql_real_connect(conn->mysql, host, db->user, db->password,
db->dbname, db->port, unix_socket,
-   db->client_flags) == NULL;
+   db->client_flags | CLIENT_MULTI_RESULTS) == 
NULL;
alarm(0);
if (failed) {
if (conn->connect_failure_count > 0) {
@@ -429,6 +430,7 @@
struct mysql_db *db = (struct mysql_db *)_db;
struct mysql_connection *conn;
struct mysql_result *result;
+   int nr;
 
result = i_new(struct mysql_result, 1);
result->api = driver_mysql_result;
@@ -442,6 +444,17 @@
case 1:
/* query ok */
result->result = mysql_store_result(conn->mysql);
+   while((nr = mysql_next_result(conn->mysql)) >= 0) {
+   /* more results? -1 = no, >0 = error, 0 = yes
+* Because of the CLIENT_MULTI_RESULTS on 
mysql_real_connect()
+* we need to read extra results - there should not be 
any.
+*/
+   if(nr == 0)   /* Just ignore more results */
+   continue;
+
+   result->api = driver_mysql_error_result;
+   goto off;
+   }
if (result->result != NULL || mysql_errno(conn->mysql) == 0)
break;
/* fallback */
@@ -451,6 +464,7 @@
break;
}
 
+off:
result->conn = conn;
return &result->api;
 }