1*12106Sralph /* lpd.c 4.1 83/04/29 */ 2*12106Sralph /* 3*12106Sralph * lpd -- line printer daemon. 4*12106Sralph * 5*12106Sralph * Listen for a connection and perform the requested operation. 6*12106Sralph * Operations are: 7*12106Sralph * \1printer\n 8*12106Sralph * check the queue for jobs and print any found. 9*12106Sralph * \2printer\n 10*12106Sralph * receive a job from another machine and queue it. 11*12106Sralph * \3printer [users ...] [jobs ...]\n 12*12106Sralph * return the current state of the queue (short form). 13*12106Sralph * \4printer [users ...] [jobs ...]\n 14*12106Sralph * return the current state of the queue (long form). 15*12106Sralph * \5printer person [users ...] [jobs ...]\n 16*12106Sralph * remove jobs from the queue. 17*12106Sralph * 18*12106Sralph * Strategy to maintain protected spooling area: 19*12106Sralph * 1. Spooling area is writable only by daemon and spooling group 20*12106Sralph * 2. lpr runs setuid root and setgrp spooling group; it uses 21*12106Sralph * root to access any file it wants (verifying things before 22*12106Sralph * with an access call) and group id to know how it should 23*12106Sralph * set up ownership of files in the spooling area. 24*12106Sralph * 3. Files in spooling area are owned by the owner, group spooling 25*12106Sralph * group, with mode 660. 26*12106Sralph * 4. lpd, lpq and lprm run setuid daemon and setgrp spooling group to 27*12106Sralph * access files and printer. Users can't get to anything 28*12106Sralph * w/o help of lpq and lprm programs. 29*12106Sralph */ 30*12106Sralph 31*12106Sralph #include "lp.h" 32*12106Sralph 33*12106Sralph char *logfile = DEFLOGF; 34*12106Sralph struct sockaddr_in sin = { AF_INET }; 35*12106Sralph int reapchild(); 36*12106Sralph char *ntoa(); 37*12106Sralph 38*12106Sralph main(argc, argv) 39*12106Sralph int argc; 40*12106Sralph char **argv; 41*12106Sralph { 42*12106Sralph int f, options; 43*12106Sralph struct sockaddr_in from; 44*12106Sralph struct servent *sp; 45*12106Sralph 46*12106Sralph gethostname(host, sizeof(host)); 47*12106Sralph name = argv[0]; 48*12106Sralph 49*12106Sralph sp = getservbyname("printer", "tcp"); 50*12106Sralph if (sp == NULL) { 51*12106Sralph log("printer/tcp: unknown service"); 52*12106Sralph exit(1); 53*12106Sralph } 54*12106Sralph sin.sin_port = sp->s_port; 55*12106Sralph 56*12106Sralph while (--argc > 0) { 57*12106Sralph argv++; 58*12106Sralph if (argv[0][0] == '-') 59*12106Sralph switch (argv[0][1]) { 60*12106Sralph case 'd': 61*12106Sralph options |= SO_DEBUG; 62*12106Sralph break; 63*12106Sralph case 'l': 64*12106Sralph argc--; 65*12106Sralph logfile = *++argv; 66*12106Sralph break; 67*12106Sralph } 68*12106Sralph else { 69*12106Sralph int port = atoi(argv[0]); 70*12106Sralph 71*12106Sralph if (port < 0) { 72*12106Sralph fprintf(stderr, "%s: bad port #\n", argv[0]); 73*12106Sralph exit(1); 74*12106Sralph } 75*12106Sralph sin.sin_port = htons((u_short) port); 76*12106Sralph } 77*12106Sralph } 78*12106Sralph #ifndef DEBUG 79*12106Sralph /* 80*12106Sralph * Set up standard environment by detaching from the parent. 81*12106Sralph */ 82*12106Sralph if (fork()) 83*12106Sralph exit(0); 84*12106Sralph for (f = 0; f < 3; f++) 85*12106Sralph (void) close(f); 86*12106Sralph (void) open("/dev/null", FRDONLY, 0); 87*12106Sralph (void) open("/dev/null", FWRONLY, 0); 88*12106Sralph (void) open(logfile, FWRONLY|FAPPEND, 0); 89*12106Sralph f = open("/dev/tty", FRDWR, 0); 90*12106Sralph if (f > 0) { 91*12106Sralph ioctl(f, TIOCNOTTY, 0); 92*12106Sralph (void) close(f); 93*12106Sralph } 94*12106Sralph #endif 95*12106Sralph (void) umask(0); 96*12106Sralph f = socket(AF_INET, SOCK_STREAM, 0); 97*12106Sralph if (f < 0) { 98*12106Sralph logerror("socket"); 99*12106Sralph exit(1); 100*12106Sralph } 101*12106Sralph if (options & SO_DEBUG) 102*12106Sralph if (setsockopt(f, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 103*12106Sralph logerror("setsockopt (SO_DEBUG)"); 104*12106Sralph if (bind(f, &sin, sizeof(sin), 0) < 0) { 105*12106Sralph logerror("bind"); 106*12106Sralph exit(1); 107*12106Sralph } 108*12106Sralph /* 109*12106Sralph * Restart all the printers and tell everyone that we are 110*12106Sralph * up and running. 111*12106Sralph */ 112*12106Sralph startup(); 113*12106Sralph /* 114*12106Sralph * Main loop: listen, accept, do a request, continue. 115*12106Sralph */ 116*12106Sralph sigset(SIGCHLD, reapchild); 117*12106Sralph listen(f, 10); 118*12106Sralph for (;;) { 119*12106Sralph int s, len = sizeof(from); 120*12106Sralph 121*12106Sralph s = accept(f, &from, &len, 0); 122*12106Sralph if (s < 0) { 123*12106Sralph if (errno == EINTR) 124*12106Sralph continue; 125*12106Sralph logerror("accept"); 126*12106Sralph continue; 127*12106Sralph } 128*12106Sralph if (fork() == 0) { 129*12106Sralph sigset(SIGCHLD, SIG_IGN); 130*12106Sralph (void) close(f); 131*12106Sralph doit(s, &from); 132*12106Sralph exit(0); 133*12106Sralph } 134*12106Sralph (void) close(s); 135*12106Sralph } 136*12106Sralph } 137*12106Sralph 138*12106Sralph reapchild() 139*12106Sralph { 140*12106Sralph union wait status; 141*12106Sralph 142*12106Sralph while (wait3(&status, WNOHANG, 0) > 0) 143*12106Sralph ; 144*12106Sralph } 145*12106Sralph 146*12106Sralph /* 147*12106Sralph * Stuff for handling job specifications 148*12106Sralph */ 149*12106Sralph char *user[MAXUSERS]; /* users to process */ 150*12106Sralph int users; /* # of users in user array */ 151*12106Sralph int requ[MAXREQUESTS]; /* job number of spool entries */ 152*12106Sralph int requests; /* # of spool requests */ 153*12106Sralph 154*12106Sralph char cbuf[BUFSIZ]; /* command line buffer */ 155*12106Sralph char fromb[32]; /* buffer for client's machine name */ 156*12106Sralph 157*12106Sralph doit(f, fromp) 158*12106Sralph int f; 159*12106Sralph struct sockaddr_in *fromp; 160*12106Sralph { 161*12106Sralph register char *cp; 162*12106Sralph register struct hostent *hp; 163*12106Sralph register int n; 164*12106Sralph extern char *person; 165*12106Sralph char c; 166*12106Sralph 167*12106Sralph dup2(f, 1); 168*12106Sralph (void) close(f); 169*12106Sralph f = 1; 170*12106Sralph fromp->sin_port = ntohs(fromp->sin_port); 171*12106Sralph if (fromp->sin_family != AF_INET || fromp->sin_port >= IPPORT_RESERVED) 172*12106Sralph fatal("Malformed from address"); 173*12106Sralph hp = gethostbyaddr(&fromp->sin_addr, sizeof(struct in_addr), 174*12106Sralph fromp->sin_family); 175*12106Sralph if (hp == 0) 176*12106Sralph fatal("Host name for your address (%s) unknown", 177*12106Sralph ntoa(fromp->sin_addr)); 178*12106Sralph strcpy(fromb, hp->h_name); 179*12106Sralph from = fromb; 180*12106Sralph for (;;) { 181*12106Sralph cp = cbuf; 182*12106Sralph do { 183*12106Sralph if ((n = read(f, &c, 1)) != 1) { 184*12106Sralph if (n < 0) 185*12106Sralph fatal("Lost connection"); 186*12106Sralph return; 187*12106Sralph } 188*12106Sralph if (cp >= &cbuf[sizeof(cbuf)]) 189*12106Sralph fatal("Command line too long"); 190*12106Sralph *cp++ = c; 191*12106Sralph } while (c != '\n'); 192*12106Sralph *--cp = '\0'; 193*12106Sralph cp = cbuf; 194*12106Sralph switch (*cp++) { 195*12106Sralph case '\1': /* check the queue and print any jobs there */ 196*12106Sralph printer = cp; 197*12106Sralph printjob(); 198*12106Sralph break; 199*12106Sralph case '\2': /* receive files to be queued */ 200*12106Sralph printer = cp; 201*12106Sralph recvjob(); 202*12106Sralph break; 203*12106Sralph case '\3': /* send back the short form queue status */ 204*12106Sralph case '\4': /* send back the long form queue status */ 205*12106Sralph printer = cp; 206*12106Sralph while (*cp) { 207*12106Sralph if (*cp != ' ') { 208*12106Sralph cp++; 209*12106Sralph continue; 210*12106Sralph } 211*12106Sralph *cp++ = '\0'; 212*12106Sralph while (isspace(*cp)) 213*12106Sralph cp++; 214*12106Sralph if (*cp == '\0') 215*12106Sralph break; 216*12106Sralph if (isdigit(*cp)) { 217*12106Sralph if (requests >= MAXREQUESTS) 218*12106Sralph fatal("Too many requests"); 219*12106Sralph requ[requests++] = atoi(cp); 220*12106Sralph } else { 221*12106Sralph if (users >= MAXUSERS) 222*12106Sralph fatal("Too many users"); 223*12106Sralph user[users++] = cp; 224*12106Sralph } 225*12106Sralph } 226*12106Sralph displayq(cbuf[0] - '\3'); 227*12106Sralph exit(0); 228*12106Sralph case '\5': /* remove a job from the queue */ 229*12106Sralph printer = cp; 230*12106Sralph while (*cp && *cp != ' ') 231*12106Sralph cp++; 232*12106Sralph if (!*cp) 233*12106Sralph break; 234*12106Sralph *cp++ = '\0'; 235*12106Sralph person = cp; 236*12106Sralph while (*cp) { 237*12106Sralph if (*cp != ' ') { 238*12106Sralph cp++; 239*12106Sralph continue; 240*12106Sralph } 241*12106Sralph *cp++ = '\0'; 242*12106Sralph while (isspace(*cp)) 243*12106Sralph cp++; 244*12106Sralph if (*cp == '\0') 245*12106Sralph break; 246*12106Sralph if (isdigit(*cp)) { 247*12106Sralph if (requests >= MAXREQUESTS) 248*12106Sralph fatal("Too many requests"); 249*12106Sralph requ[requests++] = atoi(cp); 250*12106Sralph } else { 251*12106Sralph if (users >= MAXUSERS) 252*12106Sralph fatal("Too many users"); 253*12106Sralph user[users++] = cp; 254*12106Sralph } 255*12106Sralph } 256*12106Sralph rmjob(); 257*12106Sralph break; 258*12106Sralph } 259*12106Sralph fatal("Illegal service request"); 260*12106Sralph exit(1); 261*12106Sralph } 262*12106Sralph } 263*12106Sralph 264*12106Sralph /* 265*12106Sralph * Convert network-format internet address 266*12106Sralph * to base 256 d.d.d.d representation. 267*12106Sralph */ 268*12106Sralph char * 269*12106Sralph ntoa(in) 270*12106Sralph struct in_addr in; 271*12106Sralph { 272*12106Sralph static char b[18]; 273*12106Sralph register char *p; 274*12106Sralph 275*12106Sralph p = (char *)∈ 276*12106Sralph #define UC(b) (((int)b)&0xff) 277*12106Sralph sprintf(b, "%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3])); 278*12106Sralph return (b); 279*12106Sralph } 280*12106Sralph 281*12106Sralph /*VARARGS1*/ 282*12106Sralph log(msg, a1, a2, a3) 283*12106Sralph char *msg; 284*12106Sralph { 285*12106Sralph short console = isatty(fileno(stderr)); 286*12106Sralph 287*12106Sralph fprintf(stderr, console ? "\r\n%s: " : "%s: ", name); 288*12106Sralph if (printer) 289*12106Sralph fprintf(stderr, "%s: ", printer); 290*12106Sralph fprintf(stderr, msg, a1, a2, a3); 291*12106Sralph if (console) 292*12106Sralph putc('\r', stderr); 293*12106Sralph putc('\n', stderr); 294*12106Sralph fflush(stderr); 295*12106Sralph } 296*12106Sralph 297*12106Sralph logerror(msg) 298*12106Sralph char *msg; 299*12106Sralph { 300*12106Sralph register int err = errno; 301*12106Sralph short console = isatty(fileno(stderr)); 302*12106Sralph extern int sys_nerr; 303*12106Sralph extern char *sys_errlist[]; 304*12106Sralph 305*12106Sralph fprintf(stderr, console ? "\r\n%s: " : "%s: ", name); 306*12106Sralph if (*msg) 307*12106Sralph fprintf(stderr, "%s: ", msg); 308*12106Sralph fputs(err < sys_nerr ? sys_errlist[err] : "Unknown error" , stderr); 309*12106Sralph if (console) 310*12106Sralph putc('\r', stderr); 311*12106Sralph putc('\n', stderr); 312*12106Sralph fflush(stderr); 313*12106Sralph } 314