1: #ifndef lint 2: static char *sccsid = "@(#)spawn.c 1.6 (Berkeley) 2/6/88"; 3: #endif 4: 5: #include "../common/conf.h" 6: 7: #include "common.h" 8: 9: #include <signal.h> 10: 11: #ifdef XFER_TIMEOUT 12: static int xfer_lines; 13: static int old_xfer_lines; 14: #endif 15: 16: static char tempfile[256]; 17: 18: /* 19: * spawn -- create a child process with the input from the client 20: * as stdin. 21: * 22: * Parameters: "path" is the path of the program to invoke. 23: * "name" is the name to call the program. 24: * "flag" is a single flag to be passed to the program. 25: * "cont_code" is the response code to transmit 26: * on successful startup. 27: * "err_code" is the response code to transmit when 28: * something goes wrong. 29: * 30: * Returns: -1 on non-zero return from child, 31: * 0 on error before fork/exec, 32: * 1 otherwise. 33: * 34: * Side effects: Creates and removes temporary file; 35: * accepts input from client; forks and execs. 36: * Can time out if XFER_TIMEOUT is defined. 37: */ 38: 39: spawn(path, name, flag, cont_code, err_code, errbuf) 40: char *path; 41: char *name; 42: char *flag; 43: int cont_code; 44: int err_code; 45: char *errbuf; 46: { 47: char line[NNTP_STRLEN]; 48: register char *cp; 49: int i, fd; 50: int fds[2]; 51: int pid, npid; 52: int exit_status; 53: #ifdef XFER_TIMEOUT 54: int xfer_timeout(); 55: int (*otimeout)(); 56: #endif 57: #ifdef USG 58: int status; 59: #else not USG 60: union wait status; 61: #endif not USG 62: register FILE *fp; 63: 64: (void) strcpy(tempfile, "/tmp/rpostXXXXXX"); 65: (void) mktemp(tempfile); 66: 67: fp = fopen(tempfile, "w"); 68: if (fp == NULL) { 69: printf("%d Cannot create temporary file.\r\n", err_code); 70: (void) fflush(stdout); 71: return (0); 72: } else { 73: printf("%d Ok\r\n", cont_code); 74: (void) fflush(stdout); 75: } 76: 77: #ifdef XFER_TIMEOUT 78: xfer_lines = old_xfer_lines = 0; 79: otimeout = signal(SIGALRM, xfer_timeout); 80: (void) alarm(XFER_TIMEOUT); 81: #endif 82: 83: while (fgets(line, sizeof(line), stdin) != NULL) { 84: #ifdef XFER_TIMEOUT 85: xfer_lines++; 86: #endif 87: if ((cp = index(line, '\r')) != NULL) 88: *cp = '\0'; 89: else if ((cp = index(line, '\n')) != NULL) 90: *cp = '\0'; 91: 92: if (line[0] == '.' && line[1] == '\0') 93: break; 94: 95: if (line[0] == '.') 96: fputs(line+1, fp); 97: else 98: fputs(line, fp); 99: putc('\n', fp); 100: } 101: (void) fclose(fp); 102: 103: #ifdef XFER_TIMEOUT 104: (void) alarm(0); 105: (void) signal(SIGALRM, otimeout); 106: #endif 107: 108: /* See if the connection got closed somehow... */ 109: 110: if (line[0] != '.' && line[1] != '\0') { 111: (void) unlink(tempfile); 112: #ifdef SYSLOG 113: # ifdef LOG 114: syslog(LOG_ERR, "%s spawn: EOF before period on line by itself", 115: hostname); 116: # else 117: syslog(LOG_ERR, "spawn: EOF before period on line by itself"); 118: # endif 119: #endif 120: return (0); 121: } 122: 123: #ifdef POSTER 124: (void) chown(tempfile, uid_poster, gid_poster); 125: #endif 126: 127: /* Set up a pipe so we can see errors from rnews */ 128: 129: if (pipe(fds) < 0) { 130: #ifdef SYSLOG 131: syslog(LOG_ERR, "spawn: pipe: %m"); 132: #endif 133: (void) unlink(tempfile); 134: return (-1); 135: } 136: 137: /* 138: * Ok, now we have the article in "tempfile". We 139: * should be able to fork off, close fd's 0 to 31 (or 140: * whatever), open "tempfile" for input, thus making 141: * it stdin, and then execl the inews. We think. 142: */ 143: 144: pid = vfork(); 145: if (pid == 0) { /* We're in child */ 146: #ifdef POSTER 147: (void) setuid(uid_poster); 148: (void) setgid(gid_poster); 149: #endif 150: 151: /* Set up stdout and stderr for child */ 152: 153: if (fds[1] != 1) { 154: (void) dup2(fds[1], 1); 155: (void) close(fds[1]); 156: } 157: (void) dup2(1, 2); 158: 159: for (i = 3; i < 10; ++i) /* XXX but getdtablesize is too big */ 160: (void) close(i); 161: 162: fd = open(tempfile, O_RDONLY); 163: if (fd != 0) { 164: (void) dup2(fd, 0); 165: (void) close(fd); 166: } 167: 168: execl(path, name, flag, (char *) NULL); 169: fprintf(stderr, "spawn: execl "); 170: perror(path); 171: _exit(-1); /* Error */ 172: } else { 173: (void) close(fds[1]); 174: fp = fdopen(fds[0], "r"); 175: if (fp == NULL) { 176: printf("%d Cannot fdopen %s pipe\r\n", err_code, path); 177: (void) fflush(stdout); 178: #ifdef SYSLOG 179: syslog(LOG_ERR, "spawn: pipe: %m"); 180: #endif 181: (void) unlink(tempfile); 182: return (0); 183: } 184: 185: if (errbuf) 186: *errbuf = '\0'; 187: 188: while (fgets(line, sizeof (line), fp) != NULL) { 189: if (line[0] != '\n') { 190: if (errbuf) { 191: if (cp = index(line, '\n')) 192: *cp = '\0'; 193: (void) strcat(errbuf, line); 194: (void) strcat(errbuf, "\\"); 195: } 196: #ifdef SYSLOG 197: syslog(LOG_ERR, "%s: %s", path, line); 198: #endif 199: } 200: } 201: 202: while ((npid = wait(&status)) > 0) 203: if (npid == pid) { 204: #ifdef USG 205: exit_status = (status >> 8) & 0xff; 206: #else not USG 207: exit_status = status.w_T.w_Retcode; 208: #endif not USG 209: break; 210: } 211: 212: (void) fclose(fp); 213: (void) unlink(tempfile); 214: (void) fflush(stdout); 215: if (npid < 0) { 216: #ifdef SYSLOG 217: syslog(LOG_ERR, "spawn: wait pid %d: %m", pid); 218: #endif 219: return (-1); 220: } 221: 222: #ifdef SYSLOG 223: if (exit_status != 0) 224: syslog(LOG_ERR, "spawn: %s exit status %d", 225: path, exit_status); 226: #endif 227: 228: return (exit_status ? -1 : 1); 229: } 230: } 231: 232: #ifdef XFER_TIMEOUT 233: 234: xfer_timeout() 235: { 236: if (old_xfer_lines < xfer_lines) { 237: old_xfer_lines = xfer_lines; 238: (void) alarm(XFER_TIMEOUT); 239: return; 240: } 241: 242: /* Timed out. */ 243: 244: printf("%d timeout after %d seconds, closing connection.\r\n", 245: ERR_FAULT, XFER_TIMEOUT); 246: fflush(stdout); 247: 248: #ifdef LOG 249: syslog(LOG_ERR, "%s transfer_timeout", hostname); 250: #endif LOG 251: 252: (void) unlink(tempfile); 253: 254: exit(1); 255: } 256: 257: #endif XFER_TIMEOUT