1 # include <ctype.h> 2 # include <sysexits.h> 3 # include "sendmail.h" 4 5 # ifndef SMTP 6 SCCSID(@(#)usersmtp.c 3.36 01/06/83 (no SMTP)); 7 # else SMTP 8 9 SCCSID(@(#)usersmtp.c 3.36 01/06/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 extern char *canonname(); 52 53 /* 54 ** Open the connection to the mailer. 55 */ 56 57 SmtpIn = SmtpOut = NULL; 58 SmtpClosing = FALSE; 59 SmtpPid = openmailer(m, pvp, (ADDRESS *) NULL, TRUE, &SmtpOut, &SmtpIn); 60 if (SmtpPid < 0) 61 { 62 # ifdef DEBUG 63 if (tTd(18, 1)) 64 printf("smtpinit: cannot open %s: stat %d errno %d\n", 65 pvp[0], ExitStat, errno); 66 # endif DEBUG 67 return (ExitStat); 68 } 69 70 /* 71 ** Get the greeting message. 72 ** This should appear spontaneously. 73 */ 74 75 r = reply(m); 76 if (r < 0 || REPLYTYPE(r) != 2) 77 return (EX_TEMPFAIL); 78 79 /* 80 ** Send the HELO command. 81 ** My mother taught me to always introduce myself. 82 */ 83 84 smtpmessage("HELO %s", m, HostName); 85 r = reply(m); 86 if (r < 0) 87 return (EX_TEMPFAIL); 88 else if (REPLYTYPE(r) == 5) 89 return (EX_UNAVAILABLE); 90 else if (REPLYTYPE(r) != 2) 91 return (EX_TEMPFAIL); 92 93 /* 94 ** If this is expected to be another sendmail, send some internal 95 ** commands. 96 */ 97 98 if (bitset(M_INTERNAL, m->m_flags)) 99 { 100 /* tell it to be verbose */ 101 smtpmessage("VERB", m); 102 r = reply(m); 103 if (r < 0) 104 return (EX_TEMPFAIL); 105 106 /* tell it we will be sending one transaction only */ 107 smtpmessage("ONEX", m); 108 r = reply(m); 109 if (r < 0) 110 return (EX_TEMPFAIL); 111 } 112 113 /* 114 ** Send the MAIL command. 115 ** Designates the sender. 116 */ 117 118 expand("$g", buf, &buf[sizeof buf - 1], CurEnv); 119 if (CurEnv->e_from.q_mailer == LocalMailer || 120 !bitset(M_FROMPATH, m->m_flags)) 121 { 122 smtpmessage("MAIL From:<%s>", m, canonname(buf, 1)); 123 } 124 else 125 { 126 smtpmessage("MAIL From:<@%s%c%s>", m, HostName, 127 buf[0] == '@' ? ',' : ':', canonname(buf, 1)); 128 } 129 r = reply(m); 130 if (r < 0 || REPLYTYPE(r) == 4) 131 return (EX_TEMPFAIL); 132 else if (r == 250) 133 return (EX_OK); 134 else if (r == 552) 135 return (EX_UNAVAILABLE); 136 return (EX_PROTOCOL); 137 } 138 /* 139 ** SMTPRCPT -- designate recipient. 140 ** 141 ** Parameters: 142 ** to -- address of recipient. 143 ** m -- the mailer we are sending to. 144 ** 145 ** Returns: 146 ** exit status corresponding to recipient status. 147 ** 148 ** Side Effects: 149 ** Sends the mail via SMTP. 150 */ 151 152 smtprcpt(to, m) 153 ADDRESS *to; 154 register MAILER *m; 155 { 156 register int r; 157 extern char *canonname(); 158 159 smtpmessage("RCPT To:<%s>", m, canonname(to->q_user, 2)); 160 161 r = reply(m); 162 if (r < 0 || REPLYTYPE(r) == 4) 163 return (EX_TEMPFAIL); 164 else if (REPLYTYPE(r) == 2) 165 return (EX_OK); 166 else if (r == 550 || r == 551 || r == 553) 167 return (EX_NOUSER); 168 else if (r == 552 || r == 554) 169 return (EX_UNAVAILABLE); 170 return (EX_PROTOCOL); 171 } 172 /* 173 ** SMTPDATA -- send the data and clean up the transaction. 174 ** 175 ** Parameters: 176 ** m -- mailer being sent to. 177 ** e -- the envelope for this message. 178 ** 179 ** Returns: 180 ** exit status corresponding to DATA command. 181 ** 182 ** Side Effects: 183 ** none. 184 */ 185 186 smtpdata(m, e) 187 struct mailer *m; 188 register ENVELOPE *e; 189 { 190 register int r; 191 192 /* 193 ** Send the data. 194 ** First send the command and check that it is ok. 195 ** Then send the data. 196 ** Follow it up with a dot to terminate. 197 ** Finally get the results of the transaction. 198 */ 199 200 /* send the command and check ok to proceed */ 201 smtpmessage("DATA", m); 202 r = reply(m); 203 if (r < 0 || REPLYTYPE(r) == 4) 204 return (EX_TEMPFAIL); 205 else if (r == 554) 206 return (EX_UNAVAILABLE); 207 else if (r != 354) 208 return (EX_PROTOCOL); 209 210 /* now output the actual message */ 211 (*e->e_puthdr)(SmtpOut, m, CurEnv); 212 putline("\n", SmtpOut, m); 213 (*e->e_putbody)(SmtpOut, m, CurEnv); 214 215 /* terminate the message */ 216 fprintf(SmtpOut, ".%s\n", bitset(M_CRLF, m->m_flags) ? "\r" : ""); 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 LOG 317 syslog(LOG_ERR, "%s", &MsgBuf[4]); 318 # endif LOG 319 SmtpClosing = TRUE; 320 smtpquit("reply error", m); 321 return (-1); 322 } 323 fixcrlf(SmtpReplyBuffer, TRUE); 324 325 /* log the input in the transcript for future error returns */ 326 if (Verbose && !HoldErrs) 327 nmessage(Arpa_Info, "%s", SmtpReplyBuffer); 328 else if (CurEnv->e_xfp != NULL) 329 fprintf(CurEnv->e_xfp, "%s\n", SmtpReplyBuffer); 330 331 /* if continuation is required, we can go on */ 332 if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0])) 333 continue; 334 335 /* decode the reply code */ 336 r = atoi(SmtpReplyBuffer); 337 338 /* extra semantics: 0xx codes are "informational" */ 339 if (r < 100) 340 continue; 341 342 /* reply code 421 is "Service Shutting Down" */ 343 if (r == SMTPCLOSING) 344 { 345 /* send the quit protocol */ 346 smtpquit("SMTP Shutdown", m); 347 SmtpClosing = TRUE; 348 } 349 350 return (r); 351 } 352 } 353 /* 354 ** SMTPMESSAGE -- send message to server 355 ** 356 ** Parameters: 357 ** f -- format 358 ** m -- the mailer to control formatting. 359 ** a, b, c -- parameters 360 ** 361 ** Returns: 362 ** none. 363 ** 364 ** Side Effects: 365 ** writes message to SmtpOut. 366 */ 367 368 /*VARARGS1*/ 369 smtpmessage(f, m, a, b, c) 370 char *f; 371 MAILER *m; 372 { 373 char buf[100]; 374 375 (void) sprintf(buf, f, a, b, c); 376 if (tTd(18, 1) || (Verbose && !HoldErrs)) 377 nmessage(Arpa_Info, ">>> %s", buf); 378 else if (CurEnv->e_xfp != NULL) 379 fprintf(CurEnv->e_xfp, ">>> %s\n", buf); 380 if (!SmtpClosing) 381 fprintf(SmtpOut, "%s%s\n", bitset(M_CRLF, m->m_flags) ? "\r" : "", buf); 382 } 383 384 # endif SMTP 385