lpdaemon.c 9.7 KB

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