* internet_addressing.c: added. (Internet address to Citadel mapping)
[citadel.git] / citadel / serv_smtp.c
1 /* $Id$ */
2
3 #define SMTP_PORT       2525
4
5 #include "sysdep.h"
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <stdio.h>
9 #include <fcntl.h>
10 #include <signal.h>
11 #include <pwd.h>
12 #include <errno.h>
13 #include <sys/types.h>
14 #include <sys/time.h>
15 #include <sys/wait.h>
16 #include <string.h>
17 #include <limits.h>
18 #include "citadel.h"
19 #include "server.h"
20 #include <time.h>
21 #include "sysdep_decls.h"
22 #include "citserver.h"
23 #include "support.h"
24 #include "config.h"
25 #include "dynloader.h"
26 #include "room_ops.h"
27 #include "user_ops.h"
28 #include "policy.h"
29 #include "database.h"
30 #include "msgbase.h"
31 #include "tools.h"
32 #include "internet_addressing.h"
33
34 struct citsmtp {
35         int command_state;
36         struct usersupp vrfy_buffer;
37         int vrfy_count;
38         char vrfy_match[256];
39 };
40
41 enum {
42         smtp_command,
43         smtp_user,
44         smtp_password
45 };
46
47 #define SMTP ((struct citsmtp *)CtdlGetUserData(SYM_SMTP))
48
49 long SYM_SMTP;
50
51
52 /*
53  * Here's where our SMTP session begins its happy day.
54  */
55 void smtp_greeting(void) {
56
57         strcpy(CC->cs_clientname, "Citadel SMTP");
58         CtdlAllocUserData(SYM_SMTP, sizeof(struct citsmtp));
59
60         cprintf("220 Welcome to the Citadel/UX ESMTP server at %s\n",
61                 config.c_fqdn);
62 }
63
64
65 /*
66  * Implement HELO and EHLO commands.
67  */
68 void smtp_hello(char *argbuf, int is_esmtp) {
69
70         if (!is_esmtp) {
71                 cprintf("250 Greetings and joyous salutations.\n");
72         }
73         else {
74                 cprintf("250-Greetings and joyous salutations.\n");
75                 cprintf("250-HELP\n");
76                 cprintf("250-SIZE %ld\n", config.c_maxmsglen);
77                 cprintf("250 AUTH=LOGIN\n");
78         }
79 }
80
81
82 /*
83  * Implement HELP command.
84  */
85 void smtp_help(void) {
86         cprintf("214-Here's the frequency, Kenneth:\n");
87         cprintf("214-    EHLO\n");
88         cprintf("214-    EXPN\n");
89         cprintf("214-    HELO\n");
90         cprintf("214-    HELP\n");
91         cprintf("214-    NOOP\n");
92         cprintf("214-    QUIT\n");
93         cprintf("214-    VRFY\n");
94         cprintf("214 I could tell you more, but then I'd have to kill you.\n");
95 }
96
97
98 /*
99  *
100  */
101 void smtp_get_user(char *argbuf) {
102         char buf[256];
103         char username[256];
104
105         decode_base64(username, argbuf);
106         lprintf(9, "Trying <%s>\n", username);
107         if (CtdlLoginExistingUser(username) == login_ok) {
108                 encode_base64(buf, "Password:");
109                 cprintf("334 %s\n", buf);
110                 SMTP->command_state = smtp_password;
111         }
112         else {
113                 cprintf("500 No such user.\n");
114                 SMTP->command_state = smtp_command;
115         }
116 }
117
118
119 /*
120  *
121  */
122 void smtp_get_pass(char *argbuf) {
123         char password[256];
124
125         decode_base64(password, argbuf);
126         lprintf(9, "Trying <%s>\n", password);
127         if (CtdlTryPassword(password) == pass_ok) {
128                 cprintf("235 Authentication successful.\n");
129                 lprintf(9, "SMTP auth login successful\n");
130         }
131         else {
132                 cprintf("500 Authentication failed.\n");
133         }
134         SMTP->command_state = smtp_command;
135 }
136
137
138 /*
139  *
140  */
141 void smtp_auth(char *argbuf) {
142         char buf[256];
143
144         if (strncasecmp(argbuf, "login", 5) ) {
145                 cprintf("550 We only support LOGIN authentication.\n");
146                 return;
147         }
148
149         if (strlen(argbuf) >= 7) {
150                 smtp_get_user(&argbuf[6]);
151         }
152
153         else {
154                 encode_base64(buf, "Username:");
155                 cprintf("334 %s\n", buf);
156                 SMTP->command_state = smtp_user;
157         }
158 }
159
160
161 /*
162  * Back end for smtp_vrfy() command
163  */
164 void smtp_vrfy_backend(struct usersupp *us) {
165
166         if (!fuzzy_match(us, SMTP->vrfy_match)) {
167                 ++SMTP->vrfy_count;
168                 memcpy(&SMTP->vrfy_buffer, us, sizeof(struct usersupp));
169         }
170 }
171
172
173 /* 
174  * Implements the VRFY (verify user name) command.
175  * Performs fuzzy match on full user names.
176  */
177 void smtp_vrfy(char *argbuf) {
178         SMTP->vrfy_count = 0;
179         strcpy(SMTP->vrfy_match, argbuf);
180         ForEachUser(smtp_vrfy_backend);
181
182         if (SMTP->vrfy_count < 1) {
183                 cprintf("550 String does not match anything.\n");
184         }
185         else if (SMTP->vrfy_count == 1) {
186                 cprintf("250 %s <cit%ld@%s>\n",
187                         SMTP->vrfy_buffer.fullname,
188                         SMTP->vrfy_buffer.usernum,
189                         config.c_fqdn);
190         }
191         else if (SMTP->vrfy_count > 1) {
192                 cprintf("553 Request ambiguous: %d users matched.\n",
193                         SMTP->vrfy_count);
194         }
195
196 }
197
198
199
200 /*
201  * Back end for smtp_expn() command
202  */
203 void smtp_expn_backend(struct usersupp *us) {
204
205         if (!fuzzy_match(us, SMTP->vrfy_match)) {
206
207                 if (SMTP->vrfy_count >= 1) {
208                         cprintf("250-%s <cit%ld@%s>\n",
209                                 SMTP->vrfy_buffer.fullname,
210                                 SMTP->vrfy_buffer.usernum,
211                                 config.c_fqdn);
212                 }
213
214                 ++SMTP->vrfy_count;
215                 memcpy(&SMTP->vrfy_buffer, us, sizeof(struct usersupp));
216         }
217 }
218
219
220 /* 
221  * Implements the EXPN (expand user name) command.
222  * Performs fuzzy match on full user names.
223  */
224 void smtp_expn(char *argbuf) {
225         SMTP->vrfy_count = 0;
226         strcpy(SMTP->vrfy_match, argbuf);
227         ForEachUser(smtp_expn_backend);
228
229         if (SMTP->vrfy_count < 1) {
230                 cprintf("550 String does not match anything.\n");
231         }
232         else if (SMTP->vrfy_count >= 1) {
233                 cprintf("250 %s <cit%ld@%s>\n",
234                         SMTP->vrfy_buffer.fullname,
235                         SMTP->vrfy_buffer.usernum,
236                         config.c_fqdn);
237         }
238 }
239
240
241
242 /* 
243  * Main command loop for SMTP sessions.
244  */
245 void smtp_command_loop(void) {
246         char cmdbuf[256];
247
248         time(&CC->lastcmd);
249         memset(cmdbuf, 0, sizeof cmdbuf); /* Clear it, just in case */
250         if (client_gets(cmdbuf) < 1) {
251                 lprintf(3, "SMTP socket is broken.  Ending session.\n");
252                 CC->kill_me = 1;
253                 return;
254         }
255         lprintf(5, "citserver[%3d]: %s\n", CC->cs_pid, cmdbuf);
256         while (strlen(cmdbuf) < 5) strcat(cmdbuf, " ");
257
258         if (SMTP->command_state == smtp_user) {
259                 smtp_get_user(cmdbuf);
260         }
261
262         else if (SMTP->command_state == smtp_password) {
263                 smtp_get_pass(cmdbuf);
264         }
265
266         else if (!strncasecmp(cmdbuf, "AUTH", 4)) {
267                 smtp_auth(&cmdbuf[5]);
268         }
269
270         else if (!strncasecmp(cmdbuf, "EHLO", 4)) {
271                 smtp_hello(&cmdbuf[5], 1);
272         }
273
274         else if (!strncasecmp(cmdbuf, "EXPN", 4)) {
275                 smtp_expn(&cmdbuf[5]);
276         }
277
278         else if (!strncasecmp(cmdbuf, "HELO", 4)) {
279                 smtp_hello(&cmdbuf[5], 0);
280         }
281
282         else if (!strncasecmp(cmdbuf, "HELP", 4)) {
283                 smtp_help();
284         }
285
286         else if (!strncasecmp(cmdbuf, "NOOP", 4)) {
287                 cprintf("250 This command successfully did nothing.\n");
288         }
289
290         else if (!strncasecmp(cmdbuf, "QUIT", 4)) {
291                 cprintf("221 Goodbye...\n");
292                 CC->kill_me = 1;
293                 return;
294                 }
295
296         else if (!strncasecmp(cmdbuf, "VRFY", 4)) {
297                 smtp_vrfy(&cmdbuf[5]);
298         }
299
300         else {
301                 cprintf("500 I'm afraid I can't do that, Dave.\n");
302         }
303
304 }
305
306
307
308 char *Dynamic_Module_Init(void)
309 {
310         SYM_SMTP = CtdlGetDynamicSymbol();
311         CtdlRegisterServiceHook(SMTP_PORT,
312                                 smtp_greeting,
313                                 smtp_command_loop);
314         return "$Id$";
315 }