lpdaemon.c 9.8 KB

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