13 #include <sys/types.h>
21 #include "sysdep_decls.h"
22 #include "citserver.h"
25 #include "dynloader.h"
32 #include "internet_addressing.h"
36 struct usersupp vrfy_buffer;
47 #define SMTP ((struct citsmtp *)CtdlGetUserData(SYM_SMTP))
53 * Here's where our SMTP session begins its happy day.
55 void smtp_greeting(void) {
57 strcpy(CC->cs_clientname, "Citadel SMTP");
58 CtdlAllocUserData(SYM_SMTP, sizeof(struct citsmtp));
60 cprintf("220 Welcome to the Citadel/UX ESMTP server at %s\n",
66 * Implement HELO and EHLO commands.
68 void smtp_hello(char *argbuf, int is_esmtp) {
71 cprintf("250 Greetings and joyous salutations.\n");
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");
83 * Implement HELP command.
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");
101 void smtp_get_user(char *argbuf) {
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;
113 cprintf("500 No such user.\n");
114 SMTP->command_state = smtp_command;
122 void smtp_get_pass(char *argbuf) {
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");
132 cprintf("500 Authentication failed.\n");
134 SMTP->command_state = smtp_command;
141 void smtp_auth(char *argbuf) {
144 if (strncasecmp(argbuf, "login", 5) ) {
145 cprintf("550 We only support LOGIN authentication.\n");
149 if (strlen(argbuf) >= 7) {
150 smtp_get_user(&argbuf[6]);
154 encode_base64(buf, "Username:");
155 cprintf("334 %s\n", buf);
156 SMTP->command_state = smtp_user;
162 * Back end for smtp_vrfy() command
164 void smtp_vrfy_backend(struct usersupp *us) {
166 if (!fuzzy_match(us, SMTP->vrfy_match)) {
168 memcpy(&SMTP->vrfy_buffer, us, sizeof(struct usersupp));
174 * Implements the VRFY (verify user name) command.
175 * Performs fuzzy match on full user names.
177 void smtp_vrfy(char *argbuf) {
178 SMTP->vrfy_count = 0;
179 strcpy(SMTP->vrfy_match, argbuf);
180 ForEachUser(smtp_vrfy_backend);
182 if (SMTP->vrfy_count < 1) {
183 cprintf("550 String does not match anything.\n");
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,
191 else if (SMTP->vrfy_count > 1) {
192 cprintf("553 Request ambiguous: %d users matched.\n",
201 * Back end for smtp_expn() command
203 void smtp_expn_backend(struct usersupp *us) {
205 if (!fuzzy_match(us, SMTP->vrfy_match)) {
207 if (SMTP->vrfy_count >= 1) {
208 cprintf("250-%s <cit%ld@%s>\n",
209 SMTP->vrfy_buffer.fullname,
210 SMTP->vrfy_buffer.usernum,
215 memcpy(&SMTP->vrfy_buffer, us, sizeof(struct usersupp));
221 * Implements the EXPN (expand user name) command.
222 * Performs fuzzy match on full user names.
224 void smtp_expn(char *argbuf) {
225 SMTP->vrfy_count = 0;
226 strcpy(SMTP->vrfy_match, argbuf);
227 ForEachUser(smtp_expn_backend);
229 if (SMTP->vrfy_count < 1) {
230 cprintf("550 String does not match anything.\n");
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,
243 * Main command loop for SMTP sessions.
245 void smtp_command_loop(void) {
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");
255 lprintf(5, "citserver[%3d]: %s\n", CC->cs_pid, cmdbuf);
256 while (strlen(cmdbuf) < 5) strcat(cmdbuf, " ");
258 if (SMTP->command_state == smtp_user) {
259 smtp_get_user(cmdbuf);
262 else if (SMTP->command_state == smtp_password) {
263 smtp_get_pass(cmdbuf);
266 else if (!strncasecmp(cmdbuf, "AUTH", 4)) {
267 smtp_auth(&cmdbuf[5]);
270 else if (!strncasecmp(cmdbuf, "EHLO", 4)) {
271 smtp_hello(&cmdbuf[5], 1);
274 else if (!strncasecmp(cmdbuf, "EXPN", 4)) {
275 smtp_expn(&cmdbuf[5]);
278 else if (!strncasecmp(cmdbuf, "HELO", 4)) {
279 smtp_hello(&cmdbuf[5], 0);
282 else if (!strncasecmp(cmdbuf, "HELP", 4)) {
286 else if (!strncasecmp(cmdbuf, "NOOP", 4)) {
287 cprintf("250 This command successfully did nothing.\n");
290 else if (!strncasecmp(cmdbuf, "QUIT", 4)) {
291 cprintf("221 Goodbye...\n");
296 else if (!strncasecmp(cmdbuf, "VRFY", 4)) {
297 smtp_vrfy(&cmdbuf[5]);
301 cprintf("500 I'm afraid I can't do that, Dave.\n");
308 char *Dynamic_Module_Init(void)
310 SYM_SMTP = CtdlGetDynamicSymbol();
311 CtdlRegisterServiceHook(SMTP_PORT,