1 # include <ctype.h> 2 # include <sysexits.h> 3 # include "sendmail.h" 4 5 # ifndef SMTP 6 SCCSID(@(#)usersmtp.c 3.40 01/18/83 (no SMTP)); 7 # else SMTP 8 9 SCCSID(@(#)usersmtp.c 3.40 01/18/83); 10 11 12 13 /* 14 ** USERSMTP -- run SMTP protocol from the user end. 15 ** 16 ** This protocol is described in RFC821. 17 */ 18 19 #define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */ 20 #define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */ 21 #define SMTPCLOSING 421 /* "Service Shutting Down" */ 22 23 char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */ 24 FILE *SmtpOut; /* output file */ 25 FILE *SmtpIn; /* input file */ 26 int SmtpPid; /* pid of mailer */ 27 bool SmtpClosing; /* set on a forced close */ 28 /* 29 ** SMTPINIT -- initialize SMTP. 30 ** 31 ** Opens the connection and sends the initial protocol. 32 ** 33 ** Parameters: 34 ** m -- mailer to create connection to. 35 ** pvp -- pointer to parameter vector to pass to 36 ** the mailer. 37 ** 38 ** Returns: 39 ** appropriate exit status -- EX_OK on success. 40 ** 41 ** Side Effects: 42 ** creates connection and sends initial protocol. 43 */ 44 45 smtpinit(m, pvp) 46 struct mailer *m; 47 char **pvp; 48 { 49 register int r; 50 char buf[MAXNAME]; 51 52 /* 53 ** Open the connection to the mailer. 54 */ 55 56 SmtpIn = SmtpOut = NULL; 57 SmtpClosing = FALSE; 58 SmtpPid = openmailer(m, pvp, (ADDRESS *) NULL, TRUE, &SmtpOut, &SmtpIn); 59 if (SmtpPid < 0) 60 { 61 # ifdef DEBUG 62 if (tTd(18, 1)) 63 printf("smtpinit: cannot open %s: stat %d errno %d\n", 64 pvp[0], ExitStat, errno); 65 # endif DEBUG 66 return (ExitStat); 67 } 68 69 /* 70 ** Get the greeting message. 71 ** This should appear spontaneously. 72 */ 73 74 r = reply(m); 75 if (r < 0 || REPLYTYPE(r) != 2) 76 return (EX_TEMPFAIL); 77 78 /* 79 ** Send the HELO command. 80 ** My mother taught me to always introduce myself. 81 */ 82 83 smtpmessage("HELO %s", m, HostName); 84 r = reply(m); 85 if (r < 0) 86 return (EX_TEMPFAIL); 87 else if (REPLYTYPE(r) == 5) 88 return (EX_UNAVAILABLE); 89 else if (REPLYTYPE(r) != 2) 90 return (EX_TEMPFAIL); 91 92 /* 93 ** If this is expected to be another sendmail, send some internal 94 ** commands. 95 */ 96 97 if (bitset(M_INTERNAL, m->m_flags)) 98 { 99 /* tell it to be verbose */ 100 smtpmessage("VERB", m); 101 r = reply(m); 102 if (r < 0) 103 return (EX_TEMPFAIL); 104 105 /* tell it we will be sending one transaction only */ 106 smtpmessage("ONEX", m); 107 r = reply(m); 108 if (r < 0) 109 return (EX_TEMPFAIL); 110 } 111 112 /* 113 ** Send the MAIL command. 114 ** Designates the sender. 115 */ 116 117 expand("$g", buf, &buf[sizeof buf - 1], CurEnv); 118 if (CurEnv->e_from.q_mailer == LocalMailer || 119 !bitset(M_FROMPATH, m->m_flags)) 120 { 121 smtpmessage("MAIL From:<%s>", m, buf); 122 } 123 else 124 { 125 smtpmessage("MAIL From:<@%s%c%s>", m, HostName, 126 buf[0] == '@' ? ',' : ':', buf); 127 } 128 r = reply(m); 129 if (r < 0 || REPLYTYPE(r) == 4) 130 return (EX_TEMPFAIL); 131 else if (r == 250) 132 return (EX_OK); 133 else if (r == 552) 134 return (EX_UNAVAILABLE); 135 return (EX_PROTOCOL); 136 } 137 /* 138 ** SMTPRCPT -- designate recipient. 139 ** 140 ** Parameters: 141 ** to -- address of recipient. 142 ** m -- the mailer we are sending to. 143 ** 144 ** Returns: 145 ** exit status corresponding to recipient status. 146 ** 147 ** Side Effects: 148 ** Sends the mail via SMTP. 149 */ 150 151 smtprcpt(to, m) 152 ADDRESS *to; 153 register MAILER *m; 154 { 155 register int r; 156 extern char *remotename(); 157 158 smtpmessage("RCPT To:<%s>", m, remotename(to->q_user, m, FALSE, TRUE)); 159 160 r = reply(m); 161 if (r < 0 || REPLYTYPE(r) == 4) 162 return (EX_TEMPFAIL); 163 else if (REPLYTYPE(r) == 2) 164 return (EX_OK); 165 else if (r == 550 || r == 551 || r == 553) 166 return (EX_NOUSER); 167 else if (r == 552 || r == 554) 168 return (EX_UNAVAILABLE); 169 return (EX_PROTOCOL); 170 } 171 /* 172 ** SMTPDATA -- send the data and clean up the transaction. 173 ** 174 ** Parameters: 175 ** m -- mailer being sent to. 176 ** e -- the envelope for this message. 177 ** 178 ** Returns: 179 ** exit status corresponding to DATA command. 180 ** 181 ** Side Effects: 182 ** none. 183 */ 184 185 smtpdata(m, e) 186 struct mailer *m; 187 register ENVELOPE *e; 188 { 189 register int r; 190 191 /* 192 ** Send the data. 193 ** First send the command and check that it is ok. 194 ** Then send the data. 195 ** Follow it up with a dot to terminate. 196 ** Finally get the results of the transaction. 197 */ 198 199 /* send the command and check ok to proceed */ 200 smtpmessage("DATA", m); 201 r = reply(m); 202 if (r < 0 || REPLYTYPE(r) == 4) 203 return (EX_TEMPFAIL); 204 else if (r == 554) 205 return (EX_UNAVAILABLE); 206 else if (r != 354) 207 return (EX_PROTOCOL); 208 209 /* now output the actual message */ 210 (*e->e_puthdr)(SmtpOut, m, CurEnv); 211 putline("\n", SmtpOut, m); 212 (*e->e_putbody)(SmtpOut, m, CurEnv); 213 214 /* terminate the message */ 215 fprintf(SmtpOut, ".%s", m->m_eol); 216 if (Verbose && !HoldErrs) 217 nmessage(Arpa_Info, ">>> ."); 218 219 /* check for the results of the transaction */ 220 r = reply(m); 221 if (r < 0 || REPLYTYPE(r) == 4) 222 return (EX_TEMPFAIL); 223 else if (r == 250) 224 return (EX_OK); 225 else if (r == 552 || r == 554) 226 return (EX_UNAVAILABLE); 227 return (EX_PROTOCOL); 228 } 229 /* 230 ** SMTPQUIT -- close the SMTP connection. 231 ** 232 ** Parameters: 233 ** name -- name of mailer we are quitting. 234 ** 235 ** Returns: 236 ** none. 237 ** 238 ** Side Effects: 239 ** sends the final protocol and closes the connection. 240 */ 241 242 smtpquit(name, m) 243 char *name; 244 register MAILER *m; 245 { 246 int i; 247 248 /* if the connection is already closed, don't bother */ 249 if (SmtpIn == NULL) 250 return; 251 252 /* send the quit message if not a forced quit */ 253 if (!SmtpClosing) 254 { 255 smtpmessage("QUIT", m); 256 (void) reply(m); 257 if (SmtpClosing) 258 return; 259 } 260 261 /* now actually close the connection */ 262 (void) fclose(SmtpIn); 263 (void) fclose(SmtpOut); 264 SmtpIn = SmtpOut = NULL; 265 266 /* and pick up the zombie */ 267 i = endmailer(SmtpPid, name); 268 if (i != EX_OK) 269 syserr("smtpquit %s: stat %d", name, i); 270 } 271 /* 272 ** REPLY -- read arpanet reply 273 ** 274 ** Parameters: 275 ** m -- the mailer we are reading the reply from. 276 ** 277 ** Returns: 278 ** reply code it reads. 279 ** 280 ** Side Effects: 281 ** flushes the mail file. 282 */ 283 284 reply(m) 285 { 286 (void) fflush(SmtpOut); 287 288 if (tTd(18, 1)) 289 printf("reply\n"); 290 291 /* 292 ** Read the input line, being careful not to hang. 293 */ 294 295 for (;;) 296 { 297 register int r; 298 register char *p; 299 300 /* actually do the read */ 301 if (CurEnv->e_xfp != NULL) 302 (void) fflush(CurEnv->e_xfp); /* for debugging */ 303 304 /* if we are in the process of closing just give the code */ 305 if (SmtpClosing) 306 return (SMTPCLOSING); 307 308 /* get the line from the other side */ 309 p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, SmtpIn); 310 if (p == NULL) 311 { 312 extern char MsgBuf[]; /* err.c */ 313 extern char Arpa_TSyserr[]; /* conf.c */ 314 315 message(Arpa_TSyserr, "reply: read error"); 316 # ifdef DEBUG 317 /* if debugging, pause so we can see state */ 318 if (tTd(18, 100)) 319 pause(); 320 # endif DEBUG 321 # ifdef LOG 322 syslog(LOG_ERR, "%s", &MsgBuf[4]); 323 # endif LOG 324 SmtpClosing = TRUE; 325 smtpquit("reply error", m); 326 return (-1); 327 } 328 fixcrlf(SmtpReplyBuffer, TRUE); 329 330 /* log the input in the transcript for future error returns */ 331 if (Verbose && !HoldErrs) 332 nmessage(Arpa_Info, "%s", SmtpReplyBuffer); 333 else if (CurEnv->e_xfp != NULL) 334 fprintf(CurEnv->e_xfp, "%s\n", SmtpReplyBuffer); 335 336 /* if continuation is required, we can go on */ 337 if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0])) 338 continue; 339 340 /* decode the reply code */ 341 r = atoi(SmtpReplyBuffer); 342 343 /* extra semantics: 0xx codes are "informational" */ 344 if (r < 100) 345 continue; 346 347 /* reply code 421 is "Service Shutting Down" */ 348 if (r == SMTPCLOSING) 349 { 350 /* send the quit protocol */ 351 smtpquit("SMTP Shutdown", m); 352 SmtpClosing = TRUE; 353 } 354 355 return (r); 356 } 357 } 358 /* 359 ** SMTPMESSAGE -- send message to server 360 ** 361 ** Parameters: 362 ** f -- format 363 ** m -- the mailer to control formatting. 364 ** a, b, c -- parameters 365 ** 366 ** Returns: 367 ** none. 368 ** 369 ** Side Effects: 370 ** writes message to SmtpOut. 371 */ 372 373 /*VARARGS1*/ 374 smtpmessage(f, m, a, b, c) 375 char *f; 376 MAILER *m; 377 { 378 char buf[100]; 379 380 (void) sprintf(buf, f, a, b, c); 381 if (tTd(18, 1) || (Verbose && !HoldErrs)) 382 nmessage(Arpa_Info, ">>> %s", buf); 383 else if (CurEnv->e_xfp != NULL) 384 fprintf(CurEnv->e_xfp, ">>> %s\n", buf); 385 if (!SmtpClosing) 386 fprintf(SmtpOut, "%s%s", buf, m->m_eol); 387 } 388 389 # endif SMTP 390