|
|
1.1 root 1: #include <stddef.h>
2: #include <stdio.h>
3: #include <signal.h>
4: #include <errno.h>
5: #include <time.h>
6: #include <stdarg.h>
7:
8: /* for Tenth Edition systems */
9: #define LP "/usr/bin/lp"
10: /* for System V or BSD systems */
11: /* #define LP "/v/bin/lp" */
12:
13: #define LPDAEMONLOG "/tmp/lpdaemonl"
14:
15: #define ARGSIZ 4096
16: #define NAMELEN 11
17:
18: char argvstr[ARGSIZ]; /* arguments after parsing */
19: char *argvals[ARGSIZ/2+1]; /* pointers to arguments after parsing */
20: int ascnt = 0, argcnt = 0; /* number of arguments parsed */
21: /* for 'stuff' gleened from lpr cntrl file */
22: struct jobinfo {
23: char user[NAMELEN+1];
24: char host[NAMELEN+1];
25: } *getjobinfo();
26:
27: #define MIN(a,b) ((a<b)?a:b)
28:
29: #define CPYFIELD(src, dst) { while (*(src)!=' ' && *(src)!='\t' && *(src)!='\r' && *(src)!='\n' && *(src)!='\0') *(dst)++ = *(src)++; }
30:
31: #define ACK() write(1, "", 1)
32: #define NAK() write(1, "\001", 1)
33:
34: #define LNBFSZ 4096
35: char lnbuf[LNBFSZ];
36: int readline();
37:
38: #define RDSIZE 512
39: char jobbuf[RDSIZE];
40:
41: int datafd[400], cntrlfd;
42:
43: int dbgstate = 0;
44: char *dbgstrings[] = {
45: "",
46: "sendack1",
47: "send",
48: "rcvack",
49: "sendack2",
50: "done"
51: };
52:
53: void
54: error(char *s1, ...)
55: {
56: FILE *fp;
57: long thetime;
58: char *chartime;
59: va_list ap;
60: char *args[8];
61: int argno = 0;
62:
63: if((fp=fopen(LPDAEMONLOG, "a"))==NULL)
64: return;
65:
66: time(&thetime);
67: chartime = ctime(&thetime);
68: fprintf(fp, "%.15s ", &(chartime[4]));
69: va_start(ap, s1);
70: while((args[argno++] = va_arg(ap, char*)) && argno<8);
71: va_end(ap);
72: fprintf(fp, s1, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
73: fclose(fp);
74: return;
75: }
76:
77: void
78: forklp(int inputfd)
79: {
80: int i, cpid;
81: char *bp, *cp;
82: char logent[LNBFSZ];
83:
84: /* log this call to lp */
85: cp = logent;
86: for (i=1; i<argcnt; i++) {
87: bp = argvals[i];
88: if (cp+strlen(bp)+1 < logent+LNBFSZ-1) {
89: CPYFIELD(bp, cp);
90: *cp++ = ' ';
91: }
92: }
93: *--cp = '\n';
94: *++cp = '\0';
95: error(logent);
96: switch((cpid=fork())){
97: case -1:
98: error("fork error\n");
99: exit(2);
100: case 0:
101: if (inputfd != 0)
102: dup2(inputfd, 0);
103: dup2(1, 2);
104: lseek(0, 0L, 0);
105: execvp(LP, argvals);
106: error("exec failed\n");
107: exit(3);
108: default:
109: while(wait((int *)0) != cpid);
110: }
111: }
112:
113: int
114: tempfile(void)
115: {
116: static tindx = 0;
117: char tmpf[20];
118: int crtfd, tmpfd;
119:
120: sprintf(tmpf, "/tmp/lp%d.%d", getpid(), tindx++);
121: if((crtfd=creat(tmpf, 0666)) < 0) {
122: error("cannot create temp file %s\n", tmpf);
123: NAK();
124: exit(3);
125: }
126: if((tmpfd=open(tmpf, 2)) < 0) {
127: error("cannot open temp file %s\n", tmpf);
128: NAK();
129: exit(3);
130: }
131: close(crtfd);
132: unlink(tmpf); /* comment out for debugging */
133: return(tmpfd);
134: }
135:
136: int
137: getfiles(void)
138: {
139: char *ap;
140: int filecnt, bsize, rv;
141:
142: filecnt = 0;
143: /* get a line, hopefully containing a ctrl char, size, and name */
144: for(;;) {
145: ap = lnbuf;
146: do {
147: if ((rv = read(1, ap, 1)) != 1) {
148: if (rv < 0) {
149: error("Lost connection\n");
150: NAK();
151: }
152: return(filecnt);
153: }
154: } while (*ap != '\n' && (ap++ - lnbuf < LNBFSZ - 1));
155: *ap = '\0';
156: ap = lnbuf;
157: switch(*ap++) {
158: case '\1': /* cleanup - data sent was bad (whatever that means) */
159: break;
160: case '\2': /* read control file */
161: bsize = atoi(ap);
162: cntrlfd = tempfile();
163: if (readfile(cntrlfd, bsize) < 0) {
164: close(cntrlfd);
165: NAK();
166: return(0);
167: }
168: return(filecnt);
169: case '\3': /* read data file */
170: bsize = atoi(ap);
171: datafd[filecnt] = tempfile();
172: readfile(datafd[filecnt++], bsize);
173: break;
174: default:
175: error("protocol error <%d>\n", *(ap-1));
176: NAK();
177: }
178: }
179: }
180:
181: int
182: readfile(int outfd, int bsize)
183: {
184: int rv;
185:
186: dbgstate = 1;
187: alarm(60);
188: ACK();
189: dbgstate = 2;
190: for(; bsize > 0; bsize -= rv) {
191: alarm(60);
192: if((rv=read(0, jobbuf, MIN(bsize,RDSIZE))) < 0) {
193: error("error reading input, %d unread\n", bsize);
194: exit(4);
195: } else if((write(outfd, jobbuf, rv)) != rv) {
196: error("error writing temp file, %d unread\n", bsize);
197: exit(5);
198: }
199: }
200: dbgstate = 3;
201: alarm(60);
202: if (((rv=read(0, jobbuf, 1))==1) && (*jobbuf=='\0')) {
203: alarm(60);
204: ACK();
205: dbgstate = 4;
206: alarm(0);
207: return(outfd);
208: }
209: alarm(0);
210: error("received bad status <%d> from sender\n", *jobbuf);
211: error("rv=%d\n", rv);
212: NAK();
213: return(-1);
214: }
215:
216: struct jobinfo *
217: getjobinfo(int fd)
218: {
219: register char *ap;
220: int rv;
221: static struct jobinfo info;
222:
223: if (lseek(fd, 0L, 0) < 0) {
224: error("error seeking in temp file\n");
225: exit(7);
226: }
227: /* the following strings should be < NAMELEN or else they will not
228: * be null terminated.
229: */
230: strncpy(info.user, "daemon", NAMELEN);
231: strncpy(info.host, "nowhere", NAMELEN);
232: /* there may be a space after the name and host. It will be filtered out
233: * by CPYFIELD.
234: */
235: while ((rv=readline(fd)) != 0) {
236: ap = lnbuf;
237: ap[rv-1] = '\0'; /* remove newline from string */
238: switch (*ap) {
239: case 'H':
240: strncpy(info.host, &ap[1], NAMELEN);
241: break;
242: case 'P':
243: strncpy(info.user, &ap[1], NAMELEN);
244: break;
245: }
246: }
247: return(&info);
248: }
249:
250: int
251: readline(int inpfd)
252: {
253: register char *ap;
254: register int i;
255:
256: ap = lnbuf;
257: i = 0;
258: do {
259: if (read(inpfd, ap, 1) != 1) {
260: error("read error\n");
261: break;
262: }
263: i++;
264: } while (*ap++ != '\n' && (i < LNBFSZ - 2));
265: if (*(ap-1) != '\n') {
266: *(ap-1) = '\n';
267: i++;
268: }
269: *ap = '\0';
270: return(i);
271: }
272:
273: void
274: alarmhandler(int sig) {
275: signal(sig, alarmhandler);
276: error("alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]);
277: }
278:
279: main()
280: {
281: char *ap, *bp, *cp, *savbufpnt;
282: int i, rv, saveflg, savargcnt;
283: struct jobinfo *jinfop;
284:
285: signal(1, SIG_IGN); /* SIGHUP not in lcc */
286: signal(14, alarmhandler); /* SIGALRM not in lcc */
287: cp = argvstr;
288: /* setup argv[0] for exec */
289: argvals[argcnt++] = cp;
290: for (bp = LP, i = 0; (*bp != '\0') && (i < ARGSIZ-1); *cp++ = *bp++, i++);
291: *cp++ = '\0';
292: /* get the first line sent and parse it as arguments for lp */
293: ap = lnbuf;
294: i = 0;
295: do {
296: if ((rv = read(0, ap, 1)) != 1) {
297: if (rv < 0) {
298: error("Lost connection\n");
299: }
300: exit(1);
301: }
302: i++;
303: } while (*ap++ != '\n' && (i < LNBFSZ - 2));
304: if (*(ap-1) != '\n') {
305: *(ap-1) = '\n';
306: i++;
307: }
308: *ap = '\0';
309: ap = lnbuf;
310: if (ap == (char *)0) {
311: error("cannot read arg line\n");
312: NAK();
313: exit(1);
314: }
315: bp = ap;
316: /* setup the remaining arguments */
317: /* check for BSD style request */
318: /* ^A, ^B, ^C, ^D, ^E (for BSD lpr) */
319: switch (*bp) {
320: case '\001':
321: case '\003':
322: case '\004':
323: bp++; /* drop the ctrl character from the input */
324: argvals[argcnt++] = cp;
325: *cp++ = '-'; *cp++ = 'q'; *cp++ = '\0'; /* -q */
326: argvals[argcnt++] = cp;
327: *cp++ = '-'; *cp++ = 'd'; /* -d */
328: CPYFIELD(bp, cp); /* printer */
329: *cp++ = '\0';
330: break;
331: case '\002':
332: bp++; /* drop the ctrl character from the input */
333: argvals[argcnt++] = cp;
334: *cp++ = '-'; *cp++ = 'd'; /* -d */
335: CPYFIELD(bp, cp); /* printer */
336: *cp++ = '\0';
337: ACK();
338: savargcnt = argcnt;
339: savbufpnt = cp;
340: while ((rv=getfiles())) {
341: jinfop = getjobinfo(cntrlfd);
342: close(cntrlfd);
343: argcnt = savargcnt;
344: cp = savbufpnt;
345: argvals[argcnt++] = cp;
346: *cp++ = '-'; *cp++ = 'M'; /* -M */
347: bp = jinfop->host;
348: CPYFIELD(bp, cp); /* host name */
349: *cp++ = '\0';
350: argvals[argcnt++] = cp;
351: *cp++ = '-'; *cp++ = 'u'; /* -u */
352: bp = jinfop->user;
353: CPYFIELD(bp, cp); /* user name */
354: *cp++ = '\0';
355: for(i=0;i<rv;i++)
356: forklp(datafd[i]);
357: }
358: exit(0);
359: case '\005':
360: bp++; /* drop the ctrl character from the input */
361: argvals[argcnt++] = cp;
362: *cp++ = '-'; *cp++ = 'k'; *cp++ = '\0'; /* -k */
363: argvals[argcnt++] = cp;
364: *cp++ = '-'; *cp++ = 'd'; /* -d */
365: CPYFIELD(bp, cp); /* printer */
366: *cp++ = '\0';
367: argvals[argcnt++] = cp;
368: *cp++ = '-'; *cp++ = 'u'; /* -u */
369: CPYFIELD(bp, cp); /* username */
370: *cp++ = '\0';
371: datafd[0] = tempfile();
372: fprint(datafd[0], "%s\n", bp);
373: break;
374: default:
375: /* otherwise get my lp arguments */
376: do {
377: /* move to next non-white space */
378: while (*bp==' '||*bp=='\t')
379: ++bp;
380: if (*bp=='\n') continue;
381: /* only accept arguments beginning with -
382: * this is done to prevent the printing of
383: * local files from the destination host
384: */
385: if (*bp=='-') {
386: argvals[argcnt++] = cp;
387: saveflg = 1;
388: } else
389: saveflg = 0;
390: /* move to next white space copying text to argument buffer */
391: while (*bp!=' ' && *bp!='\t' && *bp!='\n'
392: && *bp!='\0') {
393: *cp = *bp++;
394: cp += saveflg;
395: }
396: *cp = '\0';
397: cp += saveflg;
398: } while (*bp!='\n');
399: readline(0);
400: datafd[0] = tempfile();
401: if(readfile(datafd[0], atoi(lnbuf)) < 0) {
402: error("readfile failed\n");
403: exit(7);
404: }
405: }
406: forklp(datafd[0]);
407: exit(0);
408: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.