mod_auth_dovecot/mod_auth_dovecot.lua
changeset 269 74846ec9c29f
parent 268 cfcd4efb0fa4
child 270 853ae6ae87bf
equal deleted inserted replaced
268:cfcd4efb0fa4 269:74846ec9c29f
    17 
    17 
    18 function new_default_provider(host)
    18 function new_default_provider(host)
    19 	local provider = { name = "dovecot", c = nil };
    19 	local provider = { name = "dovecot", c = nil };
    20 	log("debug", "initializing dovecot authentication provider for host '%s'", host);
    20 	log("debug", "initializing dovecot authentication provider for host '%s'", host);
    21 	
    21 	
       
    22 	-- Closes the socket
       
    23 	function provider.close(self)
       
    24 		if (provider.c ~= nil) then
       
    25 			provider.c:close();
       
    26 		end
       
    27 		provider.c = nil;
       
    28 	end
       
    29 	
    22 	-- The following connects to a new socket and send the handshake
    30 	-- The following connects to a new socket and send the handshake
    23 	function provider.connect(self)
    31 	function provider.connect(self)
    24 		-- Destroy old socket
    32 		-- Destroy old socket
    25 		if (provider.c ~= nil) then
    33 		provider:close();
    26 			provider.c:close();
       
    27 		end
       
    28 		
    34 		
    29 		provider.c = socket.unix();
    35 		provider.c = socket.unix();
    30 		
    36 		
    31 		-- Create a connection to dovecot socket
    37 		-- Create a connection to dovecot socket
    32 		local socket = "/var/run/dovecot/auth-login";
    38 		local socket = "/var/run/dovecot/auth-login";
    33 		local r, e = provider.c:connect(socket);
    39 		local r, e = provider.c:connect(socket);
    34 		if (not r) then
    40 		if (not r) then
    35 			log("warn", "error connecting to dovecot socket at '%s'. error was '%s'. check permissions", socket, e);
    41 			log("warn", "error connecting to dovecot socket at '%s'. error was '%s'. check permissions", socket, e);
       
    42 			provider:close();
    36 			return false;
    43 			return false;
    37 		end
    44 		end
    38 		
    45 		
    39 		-- Send our handshake
    46 		-- Send our handshake
    40 		local pid = pposix.getpid();
    47 		local pid = pposix.getpid();
    60 				local v1 = parts();
    67 				local v1 = parts();
    61 				local v2 = parts();
    68 				local v2 = parts();
    62 				
    69 				
    63 				if (not (v1 == "1" and v2 == "1")) then
    70 				if (not (v1 == "1" and v2 == "1")) then
    64 					log("warn", "server version is not 1.1. it is %s.%s", v1, v2);
    71 					log("warn", "server version is not 1.1. it is %s.%s", v1, v2);
       
    72 					provider:close();
    65 					return false;
    73 					return false;
    66 				end
    74 				end
    67 			elseif (first == "MECH") then
    75 			elseif (first == "MECH") then
    68 				-- Mechanisms should include PLAIN
    76 				-- Mechanisms should include PLAIN
    69 				local ok = false;
    77 				local ok = false;
    72 						ok = true;
    80 						ok = true;
    73 					end
    81 					end
    74 				end
    82 				end
    75 				if (not ok) then
    83 				if (not ok) then
    76 					log("warn", "server doesn't support PLAIN mechanism. It supports '%s'", l);
    84 					log("warn", "server doesn't support PLAIN mechanism. It supports '%s'", l);
       
    85 					provider:close();
    77 					return false;
    86 					return false;
    78 				end
    87 				end
    79 			elseif (first == "DONE") then
    88 			elseif (first == "DONE") then
    80 				done = true;
    89 				done = true;
    81 			end
    90 			end
    82 		end
    91 		end
    83 		return true;
    92 		return true;
    84 	end
    93 	end
    85 	
    94 	
       
    95 	-- Wrapper for send(). Handles errors
    86 	function provider.send(self, data)
    96 	function provider.send(self, data)
    87 		local r, e = provider.c:send(data);
    97 		local r, e = provider.c:send(data);
    88 		if (not r) then
    98 		if (not r) then
    89 			log("warn", "error sending '%s' to dovecot. error was '%s'", data, e);
    99 			log("warn", "error sending '%s' to dovecot. error was '%s'", data, e);
       
   100 			provider:close();
    90 			return false;
   101 			return false;
    91 		end
   102 		end
    92 		return true;
   103 		return true;
    93 	end
   104 	end
    94 	
   105 	
       
   106 	-- Wrapper for receive(). Handles errors
    95 	function provider.receive(self)
   107 	function provider.receive(self)
    96 		local r, e = provider.c:receive();
   108 		local r, e = provider.c:receive();
    97 		if (not r) then
   109 		if (not r) then
    98 			log("warn", "error receiving data from dovecot. error was '%s'", socket, e);
   110 			log("warn", "error receiving data from dovecot. error was '%s'", socket, e);
       
   111 			provider:close();
    99 			return false;
   112 			return false;
   100 		end
   113 		end
   101 		return r;
   114 		return r;
   102 	end
   115 	end
   103 	
   116 	
   104 	function provider.test_password(username, password)
   117 	function provider.test_password(username, password)
   105 		log("debug", "test password '%s' for user %s at host %s", password, username, module.host);
   118 		log("debug", "test password '%s' for user %s at host %s", password, username, module.host);
   106 		
   119 		
   107 		if (not provider:connect()) then
   120 		local tries = 0;
   108 			return nil, "Auth failed. Dovecot communications error";
   121 		
       
   122 		if (provider.c == nil or tries > 0) then
       
   123 			if (not provider:connect()) then
       
   124 				return nil, "Auth failed. Dovecot communications error";
       
   125 			end
   109 		end
   126 		end
   110 		
   127 		
   111 		-- Send auth data
   128 		-- Send auth data
   112 		username = username .. "@" .. module.host; -- FIXME: this is actually a hack for my server
   129 		username = username .. "@" .. module.host; -- FIXME: this is actually a hack for my server
   113 		local b64 = base64.encode(username .. "\0" .. username .. "\0" .. password);
   130 		local b64 = base64.encode(username .. "\0" .. username .. "\0" .. password);
   128 			return true;
   145 			return true;
   129 		else
   146 		else
   130 			return nil, "Auth failed. Invalid username or password.";
   147 			return nil, "Auth failed. Invalid username or password.";
   131 		end
   148 		end
   132 	end
   149 	end
   133 	
   150 
   134 	function provider.get_password(username)
   151 	function provider.get_password(username)
   135 		return nil, "Cannot get_password in dovecot backend.";
   152 		return nil, "Cannot get_password in dovecot backend.";
   136 	end
   153 	end
   137 	
   154 	
   138 	function provider.set_password(username, password)
   155 	function provider.set_password(username, password)
   139 		return nil, "Cannot set_password in dovecot backend.";
   156 		return nil, "Cannot set_password in dovecot backend.";
   140 	end
   157 	end
   141 	
   158 
   142 	function provider.user_exists(username)
   159 	function provider.user_exists(username)
   143 		--TODO: Send an auth request. If it returns FAIL <id> user=<user> then user exists.
   160 		--TODO: Send an auth request. If it returns FAIL <id> user=<user> then user exists.
   144 				return nil, "user_exists not yet implemented in dovecot backend.";
   161 		return nil, "user_exists not yet implemented in dovecot backend.";
   145 	end
   162 	end
   146 	
   163 
   147 	function provider.create_user(username, password)
   164 	function provider.create_user(username, password)
   148 		return nil, "Cannot create_user in dovecot backend.";
   165 		return nil, "Cannot create_user in dovecot backend.";
   149 	end
   166 	end
   150 	
   167 
   151 	function provider.get_sasl_handler()
   168 	function provider.get_sasl_handler()
   152 		local realm = module:get_option("sasl_realm") or module.host;
   169 		local realm = module:get_option("sasl_realm") or module.host;
   153 		local getpass_authentication_profile = {
   170 		local getpass_authentication_profile = {
   154 			plain_test = function(username, password, realm)
   171 			plain_test = function(username, password, realm)
   155 			local prepped_username = nodeprep(username);
   172 			local prepped_username = nodeprep(username);
   157 				log("debug", "NODEprep failed on username: %s", username);
   174 				log("debug", "NODEprep failed on username: %s", username);
   158 				return "", nil;
   175 				return "", nil;
   159 			end
   176 			end
   160 			return usermanager.test_password(prepped_username, realm, password), true;
   177 			return usermanager.test_password(prepped_username, realm, password), true;
   161 		end
   178 		end
   162 	};
   179 		};
   163 	return new_sasl(realm, getpass_authentication_profile);
   180 		return new_sasl(realm, getpass_authentication_profile);
   164 end
   181 	end
   165 
   182 	
   166 return provider;
   183 	return provider;
   167 end
   184 end
   168 
   185 
   169 module:add_item("auth-provider", new_default_provider(module.host));
   186 module:add_item("auth-provider", new_default_provider(module.host));
   170