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- RSET\n");
94 cprintf("214- VRFY\n");
95 cprintf("214 I could tell you more, but then I'd have to kill you.\n");
102 void smtp_get_user(char *argbuf) {
106 decode_base64(username, argbuf);
107 lprintf(9, "Trying <%s>\n", username);
108 if (CtdlLoginExistingUser(username) == login_ok) {
109 encode_base64(buf, "Password:");
110 cprintf("334 %s\n", buf);
111 SMTP->command_state = smtp_password;
114 cprintf("500 No such user.\n");
115 SMTP->command_state = smtp_command;
123 void smtp_get_pass(char *argbuf) {
126 decode_base64(password, argbuf);
127 lprintf(9, "Trying <%s>\n", password);
128 if (CtdlTryPassword(password) == pass_ok) {
129 cprintf("235 Authentication successful.\n");
130 lprintf(9, "SMTP auth login successful\n");
133 cprintf("500 Authentication failed.\n");
135 SMTP->command_state = smtp_command;
142 void smtp_auth(char *argbuf) {
145 if (strncasecmp(argbuf, "login", 5) ) {
146 cprintf("550 We only support LOGIN authentication.\n");
150 if (strlen(argbuf) >= 7) {
151 smtp_get_user(&argbuf[6]);
155 encode_base64(buf, "Username:");
156 cprintf("334 %s\n", buf);
157 SMTP->command_state = smtp_user;
163 * Back end for smtp_vrfy() command
165 void smtp_vrfy_backend(struct usersupp *us) {
167 if (!fuzzy_match(us, SMTP->vrfy_match)) {
169 memcpy(&SMTP->vrfy_buffer, us, sizeof(struct usersupp));
175 * Implements the VRFY (verify user name) command.
176 * Performs fuzzy match on full user names.
178 void smtp_vrfy(char *argbuf) {
179 SMTP->vrfy_count = 0;
180 strcpy(SMTP->vrfy_match, argbuf);
181 ForEachUser(smtp_vrfy_backend);
183 if (SMTP->vrfy_count < 1) {
184 cprintf("550 String does not match anything.\n");
186 else if (SMTP->vrfy_count == 1) {
187 cprintf("250 %s <cit%ld@%s>\n",
188 SMTP->vrfy_buffer.fullname,
189 SMTP->vrfy_buffer.usernum,
192 else if (SMTP->vrfy_count > 1) {
193 cprintf("553 Request ambiguous: %d users matched.\n",
202 * Back end for smtp_expn() command
204 void smtp_expn_backend(struct usersupp *us) {
206 if (!fuzzy_match(us, SMTP->vrfy_match)) {
208 if (SMTP->vrfy_count >= 1) {
209 cprintf("250-%s <cit%ld@%s>\n",
210 SMTP->vrfy_buffer.fullname,
211 SMTP->vrfy_buffer.usernum,
216 memcpy(&SMTP->vrfy_buffer, us, sizeof(struct usersupp));
222 * Implements the EXPN (expand user name) command.
223 * Performs fuzzy match on full user names.
225 void smtp_expn(char *argbuf) {
226 SMTP->vrfy_count = 0;
227 strcpy(SMTP->vrfy_match, argbuf);
228 ForEachUser(smtp_expn_backend);
230 if (SMTP->vrfy_count < 1) {
231 cprintf("550 String does not match anything.\n");
233 else if (SMTP->vrfy_count >= 1) {
234 cprintf("250 %s <cit%ld@%s>\n",
235 SMTP->vrfy_buffer.fullname,
236 SMTP->vrfy_buffer.usernum,
243 * Implements the RSET (reset state) command.
244 * Currently this just zeroes out the state buffer. If pointers to data
245 * allocated with mallok() are ever placed in the state buffer, we have to
246 * be sure to phree() them first!
248 void smtp_rset(void) {
249 memset(SMTP, 0, sizeof(struct citsmtp));
250 cprintf("250 Zap!\n");
256 * Main command loop for SMTP sessions.
258 void smtp_command_loop(void) {
262 memset(cmdbuf, 0, sizeof cmdbuf); /* Clear it, just in case */
263 if (client_gets(cmdbuf) < 1) {
264 lprintf(3, "SMTP socket is broken. Ending session.\n");
268 lprintf(5, "citserver[%3d]: %s\n", CC->cs_pid, cmdbuf);
269 while (strlen(cmdbuf) < 5) strcat(cmdbuf, " ");
271 if (SMTP->command_state == smtp_user) {
272 smtp_get_user(cmdbuf);
275 else if (SMTP->command_state == smtp_password) {
276 smtp_get_pass(cmdbuf);
279 else if (!strncasecmp(cmdbuf, "AUTH", 4)) {
280 smtp_auth(&cmdbuf[5]);
283 else if (!strncasecmp(cmdbuf, "EHLO", 4)) {
284 smtp_hello(&cmdbuf[5], 1);
287 else if (!strncasecmp(cmdbuf, "EXPN", 4)) {
288 smtp_expn(&cmdbuf[5]);
291 else if (!strncasecmp(cmdbuf, "HELO", 4)) {
292 smtp_hello(&cmdbuf[5], 0);
295 else if (!strncasecmp(cmdbuf, "HELP", 4)) {
299 else if (!strncasecmp(cmdbuf, "NOOP", 4)) {
300 cprintf("250 This command successfully did nothing.\n");
303 else if (!strncasecmp(cmdbuf, "QUIT", 4)) {
304 cprintf("221 Goodbye...\n");
309 else if (!strncasecmp(cmdbuf, "RSET", 4)) {
313 else if (!strncasecmp(cmdbuf, "VRFY", 4)) {
314 smtp_vrfy(&cmdbuf[5]);
318 cprintf("500 I'm afraid I can't do that, Dave.\n");
325 char *Dynamic_Module_Init(void)
327 SYM_SMTP = CtdlGetDynamicSymbol();
328 CtdlRegisterServiceHook(SMTP_PORT,