10 #include <sys/types.h>
18 #include "sysdep_decls.h"
19 #include "citserver.h"
22 #include "dynloader.h"
32 struct usersupp vrfy_buffer;
43 #define SMTP ((struct citsmtp *)CtdlGetUserData(SYM_SMTP))
49 * Here's where our SMTP session begins its happy day.
51 void smtp_greeting(void) {
53 strcpy(CC->cs_clientname, "Citadel SMTP");
54 CtdlAllocUserData(SYM_SMTP, sizeof(struct citsmtp));
56 cprintf("220 Welcome to the Citadel/UX ESMTP server at %s\n",
62 * Implement HELO and EHLO commands.
64 void smtp_hello(char *argbuf, int is_esmtp) {
67 cprintf("250 Greetings and joyous salutations.\n");
70 cprintf("250-Greetings and joyous salutations.\n");
71 cprintf("250-HELP\n");
72 cprintf("250-SIZE %ld\n", config.c_maxmsglen);
73 cprintf("250 AUTH=LOGIN\n");
79 * Implement HELP command.
81 void smtp_help(void) {
82 cprintf("214-Here's the frequency, Kenneth:\n");
83 cprintf("214- EHLO\n");
84 cprintf("214- EXPN\n");
85 cprintf("214- HELO\n");
86 cprintf("214- HELP\n");
87 cprintf("214- NOOP\n");
88 cprintf("214- QUIT\n");
89 cprintf("214- VRFY\n");
90 cprintf("214 I could tell you more, but then I'd have to kill you.\n");
97 void smtp_get_user(char *argbuf) {
101 decode_base64(username, argbuf);
102 lprintf(9, "Trying <%s>\n", username);
103 if (CtdlLoginExistingUser(username) == login_ok) {
104 encode_base64(buf, "Password:");
105 cprintf("334 %s\n", buf);
106 SMTP->command_state = smtp_password;
109 cprintf("500 No such user.\n");
110 SMTP->command_state = smtp_command;
118 void smtp_get_pass(char *argbuf) {
121 decode_base64(password, argbuf);
122 lprintf(9, "Trying <%s>\n", password);
123 if (CtdlTryPassword(password) == pass_ok) {
124 cprintf("235 Authentication successful.\n");
125 lprintf(9, "SMTP auth login successful\n");
128 cprintf("500 Authentication failed.\n");
130 SMTP->command_state = smtp_command;
137 void smtp_auth(char *argbuf) {
140 if (strncasecmp(argbuf, "login", 5) ) {
141 cprintf("500 We only support LOGIN authentication.\n");
145 if (strlen(argbuf) >= 7) {
146 smtp_get_user(&argbuf[6]);
150 encode_base64(buf, "Username:");
151 cprintf("334 %s\n", buf);
152 SMTP->command_state = smtp_user;
158 * Return 0 if a given string fuzzy-matches a Citadel user account
160 * FIX ... this needs to be updated to match any and all ways of addressing
161 * a user. It may even be appropriate to move this out of SMTP and
162 * into the server core.
164 int fuzzy_match(struct usersupp *us, char *matchstring) {
167 for (a=0; a<strlen(us->fullname); ++a) {
168 if (!strncasecmp(&us->fullname[a],
169 matchstring, strlen(matchstring))) {
178 * Back end for smtp_vrfy() command
180 void smtp_vrfy_backend(struct usersupp *us) {
182 if (!fuzzy_match(us, SMTP->vrfy_match)) {
184 memcpy(&SMTP->vrfy_buffer, us, sizeof(struct usersupp));
190 * Implements the VRFY (verify user name) command.
191 * Performs fuzzy match on full user names.
193 void smtp_vrfy(char *argbuf) {
194 SMTP->vrfy_count = 0;
195 strcpy(SMTP->vrfy_match, argbuf);
196 ForEachUser(smtp_vrfy_backend);
198 if (SMTP->vrfy_count < 1) {
199 cprintf("550 String does not match anything.\n");
201 else if (SMTP->vrfy_count == 1) {
202 cprintf("250 %s <cit%ld@%s>\n",
203 SMTP->vrfy_buffer.fullname,
204 SMTP->vrfy_buffer.usernum,
207 else if (SMTP->vrfy_count > 1) {
208 cprintf("553 Request ambiguous: %d users matched.\n",
217 * Back end for smtp_expn() command
219 void smtp_expn_backend(struct usersupp *us) {
221 if (!fuzzy_match(us, SMTP->vrfy_match)) {
223 if (SMTP->vrfy_count >= 1) {
224 cprintf("250-%s <cit%ld@%s>\n",
225 SMTP->vrfy_buffer.fullname,
226 SMTP->vrfy_buffer.usernum,
231 memcpy(&SMTP->vrfy_buffer, us, sizeof(struct usersupp));
237 * Implements the EXPN (expand user name) command.
238 * Performs fuzzy match on full user names.
240 void smtp_expn(char *argbuf) {
241 SMTP->vrfy_count = 0;
242 strcpy(SMTP->vrfy_match, argbuf);
243 ForEachUser(smtp_expn_backend);
245 if (SMTP->vrfy_count < 1) {
246 cprintf("550 String does not match anything.\n");
248 else if (SMTP->vrfy_count >= 1) {
249 cprintf("250 %s <cit%ld@%s>\n",
250 SMTP->vrfy_buffer.fullname,
251 SMTP->vrfy_buffer.usernum,
259 * Main command loop for SMTP sessions.
261 void smtp_command_loop(void) {
265 memset(cmdbuf, 0, sizeof cmdbuf); /* Clear it, just in case */
266 if (client_gets(cmdbuf) < 1) {
267 lprintf(3, "SMTP socket is broken. Ending session.\n");
271 lprintf(5, "citserver[%3d]: %s\n", CC->cs_pid, cmdbuf);
272 while (strlen(cmdbuf) < 5) strcat(cmdbuf, " ");
274 if (SMTP->command_state == smtp_user) {
275 smtp_get_user(cmdbuf);
278 else if (SMTP->command_state == smtp_password) {
279 smtp_get_pass(cmdbuf);
282 else if (!strncasecmp(cmdbuf, "AUTH", 4)) {
283 smtp_auth(&cmdbuf[5]);
286 else if (!strncasecmp(cmdbuf, "EHLO", 4)) {
287 smtp_hello(&cmdbuf[5], 1);
290 else if (!strncasecmp(cmdbuf, "EXPN", 4)) {
291 smtp_expn(&cmdbuf[5]);
294 else if (!strncasecmp(cmdbuf, "HELO", 4)) {
295 smtp_hello(&cmdbuf[5], 0);
298 else if (!strncasecmp(cmdbuf, "HELP", 4)) {
302 else if (!strncasecmp(cmdbuf, "NOOP", 4)) {
303 cprintf("250 This command successfully did nothing.\n");
306 else if (!strncasecmp(cmdbuf, "QUIT", 4)) {
307 cprintf("221 Goodbye...\n");
312 else if (!strncasecmp(cmdbuf, "VRFY", 4)) {
313 smtp_vrfy(&cmdbuf[5]);
317 cprintf("500 I'm afraid I can't do that, Dave.\n");
324 char *Dynamic_Module_Init(void)
326 SYM_SMTP = CtdlGetDynamicSymbol();
327 CtdlRegisterServiceHook(25,