Remove watch before closing connection.
[cascardo/rnetproxy.git] / pop.c
1 /*
2 ** Copyright (C) 2006 Thadeu Lima de Souza Cascardo <cascardo@minaslivre.org>
3 ** Copyright (C) 2009 Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
4 **  
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **  
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 ** GNU General Public License for more details.
14 **  
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 **  
19 */
20
21 #include <glib.h>
22 #include <string.h>
23 #include "nethook.h"
24 #include "pop.h"
25 #include "usermap.h"
26
27 typedef struct
28 {
29   net_read orig_read;
30   gpointer orig_data;
31   GString *buffer;
32   GString *line;
33   gchar *user;
34 } pop_t;
35
36 static int
37 pop_check_user (pop_t *pop)
38 {
39   gchar *end;
40   gchar *s;
41   end = pop->line->str + pop->line->len;
42   s = pop->line->str;
43   while (s < end && *s == ' ') s++;
44   if (end - s < 5)
45     return -1;
46   if (g_ascii_strncasecmp (s, "USER ", 5) != 0)
47     return -1;
48   s += 5;
49   while (s < end && *s == ' ') s++;
50   if (s == end)
51     return -1;
52   end--;
53   while (end >= s && (*end == '\n' || *end == '\r')) end--;
54   if (end < s)
55     return -1;
56   if (pop->user)
57     g_free (pop->user);
58   pop->user = g_strndup (s, end - s + 2);
59   pop->user[end - s + 1] = 0;
60   return 0;
61 }
62
63 static int
64 pop_getline (pop_t *pop)
65 {
66   char * end;
67   size_t len;
68   if (pop->buffer->len == 0)
69     return -1;
70   end = memchr (pop->buffer->str, '\n', pop->buffer->len);
71   if (end == NULL)
72     return -1;
73   len = end - pop->buffer->str + 1;
74   g_string_truncate (pop->line, 0);
75   g_string_append_len (pop->line, pop->buffer->str, len);
76   g_string_erase (pop->buffer, 0, len);
77   return 0;
78 }
79
80 static void
81 pop_read (net_hook_t *hook, gchar *buffer, size_t len)
82 {
83   pop_t *pop = hook->data;
84   g_string_append_len (pop->buffer, buffer, len);
85   while (pop_getline (pop) == 0)
86     {
87       if (pop_check_user (pop) == 0)
88         {
89           g_message ("User is trying to authenticate as %s.", pop->user);
90           if (usermap_perm (pop->user) == ACCESS_DENY)
91             {
92               g_message ("Denying access to user %s.", pop->user);
93               pop_destroy (hook);
94               hc_conn_close (hook->conn);
95               return;
96             }
97         }
98       hook->data = pop->orig_data;
99       pop->orig_read (hook, pop->line->str, pop->line->len);
100       hook->data = pop;
101     }
102 }
103
104 net_hook_t *
105 pop_hook_new (net_hook_t *layer)
106 {
107   pop_t *pop;
108   pop = g_slice_new (pop_t);
109   pop->orig_read = layer->read;
110   pop->orig_data = layer->data;
111   pop->buffer = g_string_sized_new (4096);
112   pop->line = g_string_sized_new (4096);
113   pop->user = NULL;
114   layer->read = pop_read;
115   layer->data = pop;
116   return layer;
117 }
118
119 void
120 pop_destroy (net_hook_t *hook)
121 {
122   pop_t *pop = hook->data;
123   g_string_free (pop->buffer, TRUE);
124   g_string_free (pop->line, TRUE);
125   if (pop->user)
126     g_free (pop->user);
127   hook->read = pop->orig_read;
128   hook->data = pop->orig_data;
129   g_slice_free (net_hook_t, (gpointer) pop);
130 }