can't access a symbolic link, get target
[unix-history] / usr / src / usr.sbin / sendmail / src / srvrsmtp.c
CommitLineData
6b861048
EA
1# include "sendmail.h"
2
884a20cb 3# ifndef SMTP
b85ad418 4SCCSID(@(#)srvrsmtp.c 3.17 %G% (no SMTP));
884a20cb
EA
5# else SMTP
6
b85ad418 7SCCSID(@(#)srvrsmtp.c 3.17 %G%);
d727056e 8
6b861048
EA
9/*
10** SMTP -- run the SMTP protocol.
11**
12** Parameters:
13** none.
14**
15** Returns:
16** never.
17**
18** Side Effects:
19** Reads commands from the input channel and processes
20** them.
21*/
22
23struct cmd
24{
25 char *cmdname; /* command name */
26 int cmdcode; /* internal code, see below */
27};
28
29/* values for cmdcode */
30# define CMDERROR 0 /* bad command */
31# define CMDMAIL 1 /* mail -- designate sender */
4a4ebe09 32# define CMDRCPT 2 /* rcpt -- designate recipient */
6b861048 33# define CMDDATA 3 /* data -- send message text */
6b861048
EA
34# define CMDRSET 5 /* rset -- reset state */
35# define CMDVRFY 6 /* vrfy -- verify address */
36# define CMDHELP 7 /* help -- give usage info */
37# define CMDNOOP 8 /* noop -- do nothing */
38# define CMDQUIT 9 /* quit -- close connection and die */
34d37b7d 39# define CMDMRSQ 10 /* mrsq -- for old mtp compat only */
4a4ebe09 40# define CMDHELO 11 /* helo -- be polite */
d4f42161 41# define CMDDBGSHOWQ 12 /* showq -- show send queue (DEBUG) */
6b861048
EA
42
43static struct cmd CmdTab[] =
44{
45 "mail", CMDMAIL,
4a4ebe09
EA
46 "rcpt", CMDRCPT,
47 "mrcp", CMDRCPT, /* for old MTP compatability */
6b861048 48 "data", CMDDATA,
6b861048
EA
49 "rset", CMDRSET,
50 "vrfy", CMDVRFY,
abae7b2d 51 "expn", CMDVRFY,
6b861048
EA
52 "help", CMDHELP,
53 "noop", CMDNOOP,
54 "quit", CMDQUIT,
34d37b7d 55 "mrsq", CMDMRSQ,
4a4ebe09 56 "helo", CMDHELO,
d4f42161
EA
57# ifdef DEBUG
58 "showq", CMDDBGSHOWQ,
59# endif DEBUG
6b861048
EA
60 NULL, CMDERROR,
61};
62
63smtp()
64{
65 char inp[MAXLINE];
66 register char *p;
67 struct cmd *c;
68 char *cmd;
69 extern char *skipword();
70 extern bool sameword();
71 bool hasmail; /* mail command received */
49086753 72 int rcps; /* number of recipients */
abae7b2d
EA
73 extern ADDRESS *sendto();
74 ADDRESS *a;
6b861048 75
abae7b2d 76 hasmail = FALSE;
49086753 77 rcps = 0;
b85ad418 78 message("220", "%s Sendmail version %s at your service", HostName, Version);
6b861048
EA
79 for (;;)
80 {
2654b031 81 CurEnv->e_to = NULL;
34d37b7d 82 Errors = 0;
6b861048
EA
83 if (fgets(inp, sizeof inp, InChannel) == NULL)
84 {
85 /* end of file, just die */
2768afe3 86 message("421", "%s Lost input channel", HostName);
6b861048
EA
87 finis();
88 }
89
90 /* clean up end of line */
2768afe3 91 fixcrlf(inp, TRUE);
6b861048 92
49086753
EA
93 /* echo command to transcript */
94 fprintf(Xscript, "*** %s\n", inp);
95
6b861048
EA
96 /* break off command */
97 for (p = inp; isspace(*p); p++)
98 continue;
99 cmd = p;
100 while (*++p != '\0' && !isspace(*p))
101 continue;
102 if (*p != '\0')
103 *p++ = '\0';
104
105 /* decode command */
106 for (c = CmdTab; c->cmdname != NULL; c++)
107 {
108 if (sameword(c->cmdname, cmd))
109 break;
110 }
111
112 /* process command */
113 switch (c->cmdcode)
114 {
4a4ebe09 115 case CMDHELO: /* hello -- introduce yourself */
d87a0dbb 116 define('s', newstr(p));
abae7b2d 117 message("250", "%s Hello %s, pleased to meet you", HostName, p);
4a4ebe09
EA
118 break;
119
6b861048 120 case CMDMAIL: /* mail -- designate sender */
2768afe3
EA
121 if (hasmail)
122 {
123 message("503", "Sender already specified");
124 break;
125 }
6b861048
EA
126 p = skipword(p, "from");
127 if (p == NULL)
128 break;
129 if (index(p, ',') != NULL)
130 {
131 message("501", "Source routing not implemented");
132 Errors++;
133 break;
134 }
135 setsender(p);
34d37b7d 136 if (Errors == 0)
6b861048
EA
137 {
138 message("250", "Sender ok");
139 hasmail = TRUE;
140 }
141 break;
142
4a4ebe09 143 case CMDRCPT: /* rcpt -- designate recipient */
6b861048
EA
144 p = skipword(p, "to");
145 if (p == NULL)
146 break;
147 if (index(p, ',') != NULL)
148 {
149 message("501", "Source routing not implemented");
150 Errors++;
151 break;
152 }
abae7b2d
EA
153 a = sendto(p, 1, (ADDRESS *) NULL, 0);
154# ifdef DEBUG
155 if (Debug > 1)
156 printaddr(a, TRUE);
157# endif DEBUG
34d37b7d 158 if (Errors == 0)
6b861048 159 {
7a7eada3 160 message("250", "%s... Recipient ok", p);
49086753 161 rcps++;
6b861048
EA
162 }
163 break;
164
165 case CMDDATA: /* data -- text of mail */
6b861048 166 if (!hasmail)
4a4ebe09 167 {
6b861048 168 message("503", "Need MAIL command");
4a4ebe09
EA
169 break;
170 }
49086753 171 else if (rcps <= 0)
6b861048 172 {
4a4ebe09
EA
173 message("503", "Need RCPT (recipient)");
174 break;
6b861048 175 }
4a4ebe09
EA
176
177 /* collect the text of the message */
178 collect(TRUE);
179 if (Errors != 0)
180 break;
181
182 /* if sending to multiple people, mail back errors */
183 if (rcps != 1)
184 HoldErrs = MailBack = TRUE;
185
186 /* send to all recipients */
3c7fe765 187 sendall(CurEnv, FALSE);
4a4ebe09
EA
188
189 /* reset strange modes */
190 HoldErrs = FALSE;
2654b031 191 CurEnv->e_to = NULL;
4a4ebe09
EA
192
193 /* issue success if appropriate */
194 if (Errors == 0 || rcps != 1)
195 message("250", "Sent");
6b861048
EA
196 break;
197
198 case CMDRSET: /* rset -- reset state */
199 message("250", "Reset state");
200 finis();
201
202 case CMDVRFY: /* vrfy -- verify address */
abae7b2d 203 paddrtree(a);
6b861048
EA
204 break;
205
206 case CMDHELP: /* help -- give user info */
34d37b7d
EA
207 if (*p == '\0')
208 p = "SMTP";
209 help(p);
6b861048
EA
210 break;
211
212 case CMDNOOP: /* noop -- do nothing */
213 message("200", "OK");
214 break;
215
216 case CMDQUIT: /* quit -- leave mail */
217 message("221", "%s closing connection", HostName);
218 finis();
219
34d37b7d
EA
220 case CMDMRSQ: /* mrsq -- negotiate protocol */
221 if (*p == 'R' || *p == 'T')
222 {
223 /* recipients first or text first */
224 message("200", "%c ok, please continue", *p);
225 }
226 else if (*p == '?')
227 {
228 /* what do I prefer? anything, anytime */
229 message("215", "R Recipients first is my choice");
230 }
231 else if (*p == '\0')
232 {
233 /* no meaningful scheme */
234 message("200", "okey dokie boobie");
235 }
236 else
237 {
238 /* bad argument */
239 message("504", "Scheme unknown");
240 }
241 break;
242
d4f42161
EA
243# ifdef DEBUG
244 case CMDDBGSHOWQ: /* show queues */
2654b031
EA
245 printf("Send Queue=");
246 printaddr(CurEnv->e_sendqueue, TRUE);
d4f42161
EA
247 break;
248# endif DEBUG
249
6b861048
EA
250 case CMDERROR: /* unknown command */
251 message("500", "Command unrecognized");
252 break;
253
254 default:
255 syserr("smtp: unknown code %d", c->cmdcode);
256 break;
257 }
258 }
259}
260\f/*
261** SKIPWORD -- skip a fixed word.
262**
263** Parameters:
264** p -- place to start looking.
265** w -- word to skip.
266**
267** Returns:
268** p following w.
269** NULL on error.
270**
271** Side Effects:
272** clobbers the p data area.
273*/
274
275static char *
276skipword(p, w)
277 register char *p;
278 char *w;
279{
280 register char *q;
281 extern bool sameword();
282
283 /* find beginning of word */
284 while (isspace(*p))
285 p++;
286 q = p;
287
288 /* find end of word */
289 while (*p != '\0' && *p != ':' && !isspace(*p))
290 p++;
291 while (isspace(*p))
292 *p++ = '\0';
293 if (*p != ':')
294 {
295 syntax:
296 message("501", "Syntax error");
297 Errors++;
298 return (NULL);
299 }
300 *p++ = '\0';
301 while (isspace(*p))
302 p++;
303
304 /* see if the input word matches desired word */
305 if (!sameword(q, w))
306 goto syntax;
307
308 return (p);
309}
34d37b7d
EA
310\f/*
311** HELP -- implement the HELP command.
312**
313** Parameters:
314** topic -- the topic we want help for.
315**
316** Returns:
317** none.
318**
319** Side Effects:
320** outputs the help file to message output.
321*/
322
323help(topic)
324 char *topic;
325{
326 register FILE *hf;
327 int len;
328 char buf[MAXLINE];
329 bool noinfo;
a1a88160 330 extern char *HelpFile;
34d37b7d 331
a1a88160 332 hf = fopen(HelpFile, "r");
34d37b7d
EA
333 if (hf == NULL)
334 {
335 /* no help */
336 message("502", "HELP not implemented");
337 return;
338 }
339
340 len = strlen(topic);
341 makelower(topic);
342 noinfo = TRUE;
343
344 while (fgets(buf, sizeof buf, hf) != NULL)
345 {
346 if (strncmp(buf, topic, len) == 0)
347 {
348 register char *p;
349
350 p = index(buf, '\t');
351 if (p == NULL)
352 p = buf;
353 else
354 p++;
355 fixcrlf(p, TRUE);
356 message("214-", p);
357 noinfo = FALSE;
358 }
359 }
360
361 if (noinfo)
362 message("504", "HELP topic unknown");
363 else
364 message("214", "End of HELP info");
ed45aae1 365 (void) fclose(hf);
34d37b7d 366}
abae7b2d
EA
367\f/*
368** PADDRTREE -- print address tree
369**
370** Used by VRFY and EXPD to dump the tree of addresses produced.
371**
372** Parameters:
373** a -- address of root.
374**
375** Returns:
376** none.
377**
378** Side Effects:
379** prints the tree in a nice order.
380*/
381
382paddrtree(a)
383 register ADDRESS *a;
384{
385 static ADDRESS *prev;
386 static int lev;
387
388 if (a == NULL)
389 return;
390 lev++;
391 if (!bitset(QDONTSEND, a->q_flags))
392 {
393 if (prev != NULL)
394 {
395 if (prev->q_fullname != NULL)
396 message("250-", "%s <%s>", prev->q_fullname, prev->q_paddr);
397 else
398 message("250-", "<%s>", prev->q_paddr);
399 }
400 prev = a;
401 }
402 paddrtree(a->q_child);
403 paddrtree(a->q_sibling);
404 if (--lev <= 0)
405 {
406 if (prev != NULL)
407 {
408 /* last one */
409 if (prev->q_fullname != NULL)
410 message("250", "%s <%s>", prev->q_fullname, prev->q_paddr);
411 else
412 message("250", "<%s>", prev->q_paddr);
413 prev = NULL;
414 }
415 else
416 message("550", "User unknown");
417 }
418}
884a20cb
EA
419
420# endif SMTP