1 # include <errno.h> 2 # include "sendmail.h" 3 4 #ifndef DAEMON 5 SCCSID(@(#)daemon.c 4.6 03/11/84 (w/o daemon mode)); 6 #else 7 8 #include <sys/socket.h> 9 #include <netinet/in.h> 10 #include <netdb.h> 11 #include <sys/wait.h> 12 13 SCCSID(@(#)daemon.c 4.6 03/11/84 (with daemon mode)); 14 15 /* 16 ** DAEMON.C -- routines to use when running as a daemon. 17 ** 18 ** This entire file is highly dependent on the 4.2 BSD 19 ** interprocess communication primitives. No attempt has 20 ** been made to make this file portable to Version 7, 21 ** Version 6, MPX files, etc. If you should try such a 22 ** thing yourself, I recommend chucking the entire file 23 ** and starting from scratch. Basic semantics are: 24 ** 25 ** getrequests() 26 ** Opens a port and initiates a connection. 27 ** Returns in a child. Must set InChannel and 28 ** OutChannel appropriately. 29 ** clrdaemon() 30 ** Close any open files associated with getting 31 ** the connection; this is used when running the queue, 32 ** etc., to avoid having extra file descriptors during 33 ** the queue run and to avoid confusing the network 34 ** code (if it cares). 35 ** makeconnection(host, port, outfile, infile) 36 ** Make a connection to the named host on the given 37 ** port. Set *outfile and *infile to the files 38 ** appropriate for communication. Returns zero on 39 ** success, else an exit status describing the 40 ** error. 41 ** 42 ** The semantics of both of these should be clean. 43 */ 44 /* 45 ** GETREQUESTS -- open mail IPC port and get requests. 46 ** 47 ** Parameters: 48 ** none. 49 ** 50 ** Returns: 51 ** none. 52 ** 53 ** Side Effects: 54 ** Waits until some interesting activity occurs. When 55 ** it does, a child is created to process it, and the 56 ** parent waits for completion. Return from this 57 ** routine is always in the child. The file pointers 58 ** "InChannel" and "OutChannel" should be set to point 59 ** to the communication channel. 60 */ 61 62 struct sockaddr_in SendmailAddress;/* internet address of sendmail */ 63 64 int DaemonSocket = -1; /* fd describing socket */ 65 char *NetName = "ARPA"; /* name of home (local?) network */ 66 67 getrequests() 68 { 69 int t; 70 union wait status; 71 register struct servent *sp; 72 73 /* 74 ** Set up the address for the mailer. 75 */ 76 77 sp = getservbyname("smtp", "tcp"); 78 if (sp == NULL) 79 { 80 syserr("server \"smtp\" unknown"); 81 goto severe; 82 } 83 SendmailAddress.sin_family = AF_INET; 84 SendmailAddress.sin_addr.s_addr = INADDR_ANY; 85 SendmailAddress.sin_port = sp->s_port; 86 87 /* 88 ** Try to actually open the connection. 89 */ 90 91 # ifdef DEBUG 92 if (tTd(15, 1)) 93 printf("getrequests: port 0x%x\n", SendmailAddress.sin_port); 94 # endif DEBUG 95 96 /* get a socket for the SMTP connection */ 97 DaemonSocket = socket(AF_INET, SOCK_STREAM, 0, 0); 98 if (DaemonSocket < 0) 99 { 100 /* probably another daemon already */ 101 syserr("getrequests: can't create socket"); 102 severe: 103 # ifdef LOG 104 if (LogLevel > 0) 105 syslog(LOG_SALERT, "cannot get connection"); 106 # endif LOG 107 finis(); 108 } 109 110 #ifdef DEBUG 111 /* turn on network debugging? */ 112 if (tTd(15, 15)) 113 (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, 0, 0); 114 #endif DEBUG 115 116 if (bind(DaemonSocket, &SendmailAddress, sizeof SendmailAddress, 0) < 0) 117 { 118 syserr("getrequests: cannot bind"); 119 (void) close(DaemonSocket); 120 goto severe; 121 } 122 listen(DaemonSocket, 10); 123 124 # ifdef DEBUG 125 if (tTd(15, 1)) 126 printf("getrequests: %d\n", DaemonSocket); 127 # endif DEBUG 128 129 for (;;) 130 { 131 register int pid; 132 auto int lotherend; 133 struct sockaddr_in otherend; 134 extern int RefuseLA; 135 136 /* see if we are rejecting connections */ 137 while (getla() > RefuseLA) 138 sleep(5); 139 140 /* wait for a connection */ 141 do 142 { 143 errno = 0; 144 lotherend = sizeof otherend; 145 t = accept(DaemonSocket, &otherend, &lotherend, 0); 146 } while (t < 0 && errno == EINTR); 147 if (t < 0) 148 { 149 syserr("getrequests: accept"); 150 sleep(5); 151 continue; 152 } 153 154 /* 155 ** Create a subprocess to process the mail. 156 */ 157 158 # ifdef DEBUG 159 if (tTd(15, 2)) 160 printf("getrequests: forking (fd = %d)\n", t); 161 # endif DEBUG 162 163 pid = fork(); 164 if (pid < 0) 165 { 166 syserr("daemon: cannot fork"); 167 sleep(10); 168 (void) close(t); 169 continue; 170 } 171 172 if (pid == 0) 173 { 174 extern struct hostent *gethostbyaddr(); 175 register struct hostent *hp; 176 extern char *RealHostName; /* srvrsmtp.c */ 177 char buf[MAXNAME]; 178 179 /* 180 ** CHILD -- return to caller. 181 ** Collect verified idea of sending host. 182 ** Verify calling user id if possible here. 183 */ 184 185 /* determine host name */ 186 hp = gethostbyaddr(&otherend.sin_addr, sizeof otherend.sin_addr, AF_INET); 187 if (hp != NULL) 188 (void) sprintf(buf, "%s.%s", hp->h_name, NetName); 189 else 190 /* this should produce a dotted quad */ 191 (void) sprintf(buf, "%lx", otherend.sin_addr.s_addr); 192 RealHostName = newstr(buf); 193 194 (void) close(DaemonSocket); 195 InChannel = fdopen(t, "r"); 196 OutChannel = fdopen(t, "w"); 197 # ifdef DEBUG 198 if (tTd(15, 2)) 199 printf("getreq: returning\n"); 200 # endif DEBUG 201 # ifdef LOG 202 if (LogLevel > 11) 203 syslog(LOG_DEBUG, "connected, pid=%d", getpid()); 204 # endif LOG 205 return; 206 } 207 208 /* 209 ** PARENT -- wait for child to terminate. 210 ** Perhaps we should allow concurrent processing? 211 */ 212 213 # ifdef DEBUG 214 if (tTd(15, 2)) 215 { 216 sleep(2); 217 printf("getreq: parent waiting\n"); 218 } 219 # endif DEBUG 220 221 /* close the port so that others will hang (for a while) */ 222 (void) close(t); 223 224 /* pick up old zombies */ 225 while (wait3(&status, WNOHANG, 0) > 0) 226 continue; 227 } 228 /*NOTREACHED*/ 229 } 230 /* 231 ** CLRDAEMON -- reset the daemon connection 232 ** 233 ** Parameters: 234 ** none. 235 ** 236 ** Returns: 237 ** none. 238 ** 239 ** Side Effects: 240 ** releases any resources used by the passive daemon. 241 */ 242 243 clrdaemon() 244 { 245 if (DaemonSocket >= 0) 246 (void) close(DaemonSocket); 247 DaemonSocket = -1; 248 } 249 /* 250 ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 251 ** 252 ** Parameters: 253 ** host -- the name of the host. 254 ** port -- the port number to connect to. 255 ** outfile -- a pointer to a place to put the outfile 256 ** descriptor. 257 ** infile -- ditto for infile. 258 ** 259 ** Returns: 260 ** An exit code telling whether the connection could be 261 ** made and if not why not. 262 ** 263 ** Side Effects: 264 ** none. 265 */ 266 267 makeconnection(host, port, outfile, infile) 268 char *host; 269 u_short port; 270 FILE **outfile; 271 FILE **infile; 272 { 273 register int s; 274 275 /* 276 ** Set up the address for the mailer. 277 ** Accept "[a.b.c.d]" syntax for host name. 278 */ 279 280 if (host[0] == '[') 281 { 282 long hid; 283 register char *p = index(host, ']'); 284 285 if (p != NULL) 286 { 287 *p = '\0'; 288 hid = inet_addr(&host[1]); 289 *p = ']'; 290 } 291 if (p == NULL || hid == -1) 292 { 293 usrerr("Invalid numeric domain spec \"%s\"", host); 294 return (EX_NOHOST); 295 } 296 SendmailAddress.sin_addr.s_addr = hid; 297 } 298 else 299 { 300 register struct hostent *hp = gethostbyname(host); 301 302 if (hp == NULL) 303 return (EX_NOHOST); 304 bmove(hp->h_addr, (char *) &SendmailAddress.sin_addr, hp->h_length); 305 } 306 307 /* 308 ** Determine the port number. 309 */ 310 311 if (port != 0) 312 SendmailAddress.sin_port = htons(port); 313 else 314 { 315 register struct servent *sp = getservbyname("smtp", "tcp"); 316 317 if (sp == NULL) 318 { 319 syserr("makeconnection: server \"smtp\" unknown"); 320 return (EX_OSFILE); 321 } 322 SendmailAddress.sin_port = sp->s_port; 323 } 324 325 /* 326 ** Try to actually open the connection. 327 */ 328 329 # ifdef DEBUG 330 if (tTd(16, 1)) 331 printf("makeconnection (%s)\n", host); 332 # endif DEBUG 333 334 s = socket(AF_INET, SOCK_STREAM, 0, 0); 335 if (s < 0) 336 { 337 syserr("makeconnection: no socket"); 338 goto failure; 339 } 340 341 # ifdef DEBUG 342 if (tTd(16, 1)) 343 printf("makeconnection: %d\n", s); 344 345 /* turn on network debugging? */ 346 if (tTd(16, 14)) 347 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 0, 0); 348 # endif DEBUG 349 (void) fflush(CurEnv->e_xfp); /* for debugging */ 350 errno = 0; /* for debugging */ 351 SendmailAddress.sin_family = AF_INET; 352 if (connect(s, &SendmailAddress, sizeof SendmailAddress, 0) < 0) 353 { 354 /* failure, decide if temporary or not */ 355 failure: 356 switch (errno) 357 { 358 case EISCONN: 359 case ETIMEDOUT: 360 case EINPROGRESS: 361 case EALREADY: 362 case EADDRINUSE: 363 case EHOSTDOWN: 364 case ENETDOWN: 365 case ENETRESET: 366 case ENOBUFS: 367 case ECONNREFUSED: 368 case ECONNRESET: 369 case EHOSTUNREACH: 370 case ENETUNREACH: 371 /* there are others, I'm sure..... */ 372 return (EX_TEMPFAIL); 373 374 case EPERM: 375 /* why is this happening? */ 376 syserr("makeconnection: funny failure, addr=%lx, port=%x", 377 SendmailAddress.sin_addr.s_addr, SendmailAddress.sin_port); 378 return (EX_TEMPFAIL); 379 380 default: 381 return (EX_UNAVAILABLE); 382 } 383 } 384 385 /* connection ok, put it into canonical form */ 386 *outfile = fdopen(s, "w"); 387 *infile = fdopen(s, "r"); 388 389 return (EX_OK); 390 } 391 /* 392 ** MYHOSTNAME -- return the name of this host. 393 ** 394 ** Parameters: 395 ** hostbuf -- a place to return the name of this host. 396 ** size -- the size of hostbuf. 397 ** 398 ** Returns: 399 ** A list of aliases for this host. 400 ** 401 ** Side Effects: 402 ** none. 403 */ 404 405 char ** 406 myhostname(hostbuf, size) 407 char hostbuf[]; 408 int size; 409 { 410 extern struct hostent *gethostbyname(); 411 struct hostent *hp; 412 413 gethostname(hostbuf, size); 414 hp = gethostbyname(hostbuf); 415 if (hp != NULL) 416 return (hp->h_aliases); 417 else 418 return (NULL); 419 } 420 421 # else DAEMON 422 423 /* 424 ** MYHOSTNAME -- stub version for case of no daemon code. 425 ** 426 ** Can't convert to upper case here because might be a UUCP name. 427 ** 428 ** Mark, you can change this to be anything you want...... 429 */ 430 431 char ** 432 myhostname(hostbuf, size) 433 char hostbuf[]; 434 int size; 435 { 436 register FILE *f; 437 438 hostbuf[0] = '\0'; 439 f = fopen("/usr/include/whoami", "r"); 440 if (f != NULL) 441 { 442 (void) fgets(hostbuf, size, f); 443 fixcrlf(hostbuf, TRUE); 444 (void) fclose(f); 445 } 446 return (NULL); 447 } 448 449 #endif DAEMON 450