install correct aliases file
[unix-history] / usr / src / usr.sbin / lpr / lpd / lpd.c
CommitLineData
d0aeaf5a
DF
1/*
2 * Copyright (c) 1983 Regents of the University of California.
9d85c861
KB
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
a399f6c8
KB
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
d0aeaf5a
DF
16 */
17
18#ifndef lint
19char copyright[] =
20"@(#) Copyright (c) 1983 Regents of the University of California.\n\
21 All rights reserved.\n";
9d85c861 22#endif /* not lint */
d0aeaf5a 23
3a7f30af 24#ifndef lint
a399f6c8 25static char sccsid[] = "@(#)lpd.c 5.6 (Berkeley) %G%";
9d85c861 26#endif /* not lint */
3a7f30af 27
7245937a
RC
28/*
29 * lpd -- line printer daemon.
30 *
31 * Listen for a connection and perform the requested operation.
32 * Operations are:
33 * \1printer\n
34 * check the queue for jobs and print any found.
35 * \2printer\n
36 * receive a job from another machine and queue it.
37 * \3printer [users ...] [jobs ...]\n
38 * return the current state of the queue (short form).
39 * \4printer [users ...] [jobs ...]\n
40 * return the current state of the queue (long form).
41 * \5printer person [users ...] [jobs ...]\n
42 * remove jobs from the queue.
43 *
44 * Strategy to maintain protected spooling area:
45 * 1. Spooling area is writable only by daemon and spooling group
46 * 2. lpr runs setuid root and setgrp spooling group; it uses
47 * root to access any file it wants (verifying things before
48 * with an access call) and group id to know how it should
49 * set up ownership of files in the spooling area.
4d4caa50 50 * 3. Files in spooling area are owned by root, group spooling
7245937a
RC
51 * group, with mode 660.
52 * 4. lpd, lpq and lprm run setuid daemon and setgrp spooling group to
53 * access files and printer. Users can't get to anything
54 * w/o help of lpq and lprm programs.
55 */
56
57#include "lp.h"
58
82bca8f8 59int lflag; /* log requests flag */
54266d1f 60
7245937a 61int reapchild();
82bca8f8 62int mcleanup();
7245937a
RC
63
64main(argc, argv)
65 int argc;
66 char **argv;
67{
8c4b7b45
SL
68 int f, funix, finet, options, defreadfds, fromlen;
69 struct sockaddr_un sun, fromunix;
70 struct sockaddr_in sin, frominet;
c0297f12 71 int omask, lfd;
7245937a
RC
72
73 gethostname(host, sizeof(host));
74 name = argv[0];
75
7245937a
RC
76 while (--argc > 0) {
77 argv++;
78 if (argv[0][0] == '-')
79 switch (argv[0][1]) {
80 case 'd':
81 options |= SO_DEBUG;
82 break;
83 case 'l':
4d4caa50
RC
84 lflag++;
85 break;
7245937a 86 }
7245937a 87 }
c0297f12 88
7245937a
RC
89#ifndef DEBUG
90 /*
91 * Set up standard environment by detaching from the parent.
92 */
93 if (fork())
94 exit(0);
82bca8f8 95 for (f = 0; f < 5; f++)
7245937a 96 (void) close(f);
adec4d9e
SL
97 (void) open("/dev/null", O_RDONLY);
98 (void) open("/dev/null", O_WRONLY);
82bca8f8 99 (void) dup(1);
adec4d9e 100 f = open("/dev/tty", O_RDWR);
7245937a
RC
101 if (f > 0) {
102 ioctl(f, TIOCNOTTY, 0);
103 (void) close(f);
104 }
105#endif
c0297f12 106
126fc76f 107 openlog("lpd", LOG_PID, LOG_LPR);
7245937a 108 (void) umask(0);
c0297f12
RC
109 lfd = open(MASTERLOCK, O_WRONLY|O_CREAT, 0644);
110 if (lfd < 0) {
82bca8f8 111 syslog(LOG_ERR, "%s: %m", MASTERLOCK);
c0297f12
RC
112 exit(1);
113 }
114 if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
115 if (errno == EWOULDBLOCK) /* active deamon present */
116 exit(0);
82bca8f8 117 syslog(LOG_ERR, "%s: %m", MASTERLOCK);
c0297f12
RC
118 exit(1);
119 }
120 ftruncate(lfd, 0);
121 /*
122 * write process id for others to know
123 */
124 sprintf(line, "%u\n", getpid());
125 f = strlen(line);
126 if (write(lfd, line, f) != f) {
82bca8f8 127 syslog(LOG_ERR, "%s: %m", MASTERLOCK);
c0297f12
RC
128 exit(1);
129 }
130 signal(SIGCHLD, reapchild);
54266d1f
RC
131 /*
132 * Restart all the printers.
133 */
134 startup();
c0297f12 135 (void) unlink(SOCKETNAME);
8c4b7b45
SL
136 funix = socket(AF_UNIX, SOCK_STREAM, 0);
137 if (funix < 0) {
82bca8f8 138 syslog(LOG_ERR, "socket: %m");
7245937a
RC
139 exit(1);
140 }
845f1693
RC
141#define mask(s) (1 << ((s) - 1))
142 omask = sigblock(mask(SIGHUP)|mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM));
82bca8f8
RC
143 signal(SIGHUP, mcleanup);
144 signal(SIGINT, mcleanup);
145 signal(SIGQUIT, mcleanup);
146 signal(SIGTERM, mcleanup);
8c4b7b45
SL
147 sun.sun_family = AF_UNIX;
148 strcpy(sun.sun_path, SOCKETNAME);
149 if (bind(funix, &sun, strlen(sun.sun_path) + 2) < 0) {
82bca8f8 150 syslog(LOG_ERR, "ubind: %m");
7245937a
RC
151 exit(1);
152 }
8c4b7b45 153 sigsetmask(omask);
845f1693
RC
154 defreadfds = 1 << funix;
155 listen(funix, 5);
8c4b7b45
SL
156 finet = socket(AF_INET, SOCK_STREAM, 0);
157 if (finet >= 0) {
158 struct servent *sp;
159
160 if (options & SO_DEBUG)
161 if (setsockopt(finet, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) {
82bca8f8
RC
162 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
163 mcleanup();
8c4b7b45
SL
164 }
165 sp = getservbyname("printer", "tcp");
166 if (sp == NULL) {
82bca8f8
RC
167 syslog(LOG_ERR, "printer/tcp: unknown service");
168 mcleanup();
8c4b7b45
SL
169 }
170 sin.sin_family = AF_INET;
171 sin.sin_port = sp->s_port;
172 if (bind(finet, &sin, sizeof(sin), 0) < 0) {
82bca8f8
RC
173 syslog(LOG_ERR, "bind: %m");
174 mcleanup();
8c4b7b45 175 }
8c4b7b45
SL
176 defreadfds |= 1 << finet;
177 listen(finet, 5);
178 }
845f1693
RC
179 /*
180 * Main loop: accept, do a request, continue.
181 */
7245937a 182 for (;;) {
3a7f30af 183 int domain, nfds, s, readfds = defreadfds;
7245937a 184
3a7f30af
SL
185 nfds = select(20, &readfds, 0, 0, 0);
186 if (nfds <= 0) {
82bca8f8
RC
187 if (nfds < 0 && errno != EINTR)
188 syslog(LOG_WARNING, "select: %m");
3a7f30af
SL
189 continue;
190 }
8c4b7b45 191 if (readfds & (1 << funix)) {
3a7f30af 192 domain = AF_UNIX, fromlen = sizeof(fromunix);
8c4b7b45 193 s = accept(funix, &fromunix, &fromlen);
3a7f30af
SL
194 } else if (readfds & (1 << finet)) {
195 domain = AF_INET, fromlen = sizeof(frominet);
8c4b7b45
SL
196 s = accept(finet, &frominet, &fromlen);
197 }
7245937a 198 if (s < 0) {
82bca8f8
RC
199 if (errno != EINTR)
200 syslog(LOG_WARNING, "accept: %m");
201 continue;
7245937a
RC
202 }
203 if (fork() == 0) {
adec4d9e 204 signal(SIGCHLD, SIG_IGN);
f0b73bd5
RC
205 signal(SIGHUP, SIG_IGN);
206 signal(SIGINT, SIG_IGN);
207 signal(SIGQUIT, SIG_IGN);
208 signal(SIGTERM, SIG_IGN);
8c4b7b45
SL
209 (void) close(funix);
210 (void) close(finet);
211 dup2(s, 1);
212 (void) close(s);
213 if (domain == AF_INET)
214 chkhost(&frominet);
215 doit();
7245937a
RC
216 exit(0);
217 }
218 (void) close(s);
219 }
220}
221
222reapchild()
223{
224 union wait status;
225
226 while (wait3(&status, WNOHANG, 0) > 0)
227 ;
228}
229
82bca8f8 230mcleanup()
8c4b7b45 231{
845f1693 232 if (lflag)
82bca8f8 233 syslog(LOG_INFO, "exiting");
8c4b7b45
SL
234 unlink(SOCKETNAME);
235 exit(0);
236}
237
7245937a
RC
238/*
239 * Stuff for handling job specifications
240 */
241char *user[MAXUSERS]; /* users to process */
242int users; /* # of users in user array */
243int requ[MAXREQUESTS]; /* job number of spool entries */
244int requests; /* # of spool requests */
54266d1f 245char *person; /* name of person doing lprm */
7245937a 246
82bca8f8
RC
247char fromb[32]; /* buffer for client's machine name */
248char cbuf[BUFSIZ]; /* command line buffer */
249char *cmdnames[] = {
4d4caa50
RC
250 "null",
251 "printjob",
252 "recvjob",
253 "displayq short",
254 "displayq long",
255 "rmjob"
256};
7245937a 257
8c4b7b45 258doit()
7245937a
RC
259{
260 register char *cp;
7245937a 261 register int n;
7245937a 262
7245937a
RC
263 for (;;) {
264 cp = cbuf;
265 do {
8c4b7b45
SL
266 if (cp >= &cbuf[sizeof(cbuf) - 1])
267 fatal("Command line too long");
268 if ((n = read(1, cp, 1)) != 1) {
7245937a
RC
269 if (n < 0)
270 fatal("Lost connection");
271 return;
272 }
8c4b7b45 273 } while (*cp++ != '\n');
7245937a
RC
274 *--cp = '\0';
275 cp = cbuf;
82bca8f8
RC
276 if (lflag) {
277 if (*cp >= '\1' && *cp <= '\5')
278 syslog(LOG_INFO, "%s requests %s %s",
279 from, cmdnames[*cp], cp+1);
280 else
281 syslog(LOG_INFO, "bad request (%d) from %s",
282 *cp, from);
4d4caa50 283 }
7245937a
RC
284 switch (*cp++) {
285 case '\1': /* check the queue and print any jobs there */
286 printer = cp;
287 printjob();
288 break;
289 case '\2': /* receive files to be queued */
290 printer = cp;
291 recvjob();
292 break;
4d4caa50
RC
293 case '\3': /* display the queue (short form) */
294 case '\4': /* display the queue (long form) */
7245937a
RC
295 printer = cp;
296 while (*cp) {
297 if (*cp != ' ') {
298 cp++;
299 continue;
300 }
301 *cp++ = '\0';
302 while (isspace(*cp))
303 cp++;
304 if (*cp == '\0')
305 break;
306 if (isdigit(*cp)) {
307 if (requests >= MAXREQUESTS)
308 fatal("Too many requests");
309 requ[requests++] = atoi(cp);
310 } else {
311 if (users >= MAXUSERS)
312 fatal("Too many users");
313 user[users++] = cp;
314 }
315 }
316 displayq(cbuf[0] - '\3');
317 exit(0);
318 case '\5': /* remove a job from the queue */
319 printer = cp;
320 while (*cp && *cp != ' ')
321 cp++;
322 if (!*cp)
323 break;
324 *cp++ = '\0';
325 person = cp;
326 while (*cp) {
327 if (*cp != ' ') {
328 cp++;
329 continue;
330 }
331 *cp++ = '\0';
332 while (isspace(*cp))
333 cp++;
334 if (*cp == '\0')
335 break;
336 if (isdigit(*cp)) {
337 if (requests >= MAXREQUESTS)
338 fatal("Too many requests");
339 requ[requests++] = atoi(cp);
340 } else {
341 if (users >= MAXUSERS)
342 fatal("Too many users");
343 user[users++] = cp;
344 }
345 }
346 rmjob();
347 break;
348 }
349 fatal("Illegal service request");
7245937a
RC
350 }
351}
352
4d4caa50
RC
353/*
354 * Make a pass through the printcap database and start printing any
355 * files left from the last time the machine went down.
356 */
357startup()
358{
359 char buf[BUFSIZ];
360 register char *cp;
361 int pid;
362
363 printer = buf;
364
365 /*
366 * Restart the daemons.
367 */
368 while (getprent(buf) > 0) {
369 for (cp = buf; *cp; cp++)
370 if (*cp == '|' || *cp == ':') {
371 *cp = '\0';
372 break;
373 }
374 if ((pid = fork()) < 0) {
82bca8f8
RC
375 syslog(LOG_WARNING, "startup: cannot fork");
376 mcleanup();
4d4caa50
RC
377 }
378 if (!pid) {
379 endprent();
380 printjob();
381 }
382 }
383}
384
e961d21f
JB
385#define DUMMY ":nobody::"
386
4d4caa50
RC
387/*
388 * Check to see if the from host has access to the line printer.
389 */
8c4b7b45
SL
390chkhost(f)
391 struct sockaddr_in *f;
4d4caa50 392{
8c4b7b45 393 register struct hostent *hp;
4d4caa50 394 register FILE *hostf;
e961d21f 395 register char *cp, *sp;
4d4caa50 396 char ahost[50];
24c04811 397 int first = 1;
8c4b7b45 398 extern char *inet_ntoa();
e961d21f 399 int baselen = -1;
4d4caa50 400
8c4b7b45
SL
401 f->sin_port = ntohs(f->sin_port);
402 if (f->sin_family != AF_INET || f->sin_port >= IPPORT_RESERVED)
403 fatal("Malformed from address");
404 hp = gethostbyaddr(&f->sin_addr, sizeof(struct in_addr), f->sin_family);
405 if (hp == 0)
406 fatal("Host name for your address (%s) unknown",
407 inet_ntoa(f->sin_addr));
408
409 strcpy(fromb, hp->h_name);
410 from = fromb;
219e8551 411 if (!strcmp(from, host))
8c4b7b45 412 return;
219e8551 413
e961d21f
JB
414 sp = fromb;
415 cp = ahost;
416 while (*sp) {
417 if (*sp == '.') {
418 if (baselen == -1)
419 baselen = sp - fromb;
420 *cp++ = *sp++;
421 } else {
422 *cp++ = isupper(*sp) ? tolower(*sp++) : *sp++;
423 }
424 }
425 *cp = '\0';
4d4caa50 426 hostf = fopen("/etc/hosts.equiv", "r");
24c04811
RC
427again:
428 if (hostf) {
e961d21f
JB
429 if (!_validuser(hostf, ahost, DUMMY, DUMMY, baselen)) {
430 (void) fclose(hostf);
431 return;
4d4caa50 432 }
24c04811
RC
433 (void) fclose(hostf);
434 }
435 if (first == 1) {
436 first = 0;
437 hostf = fopen("/etc/hosts.lpd", "r");
438 goto again;
4d4caa50 439 }
8c4b7b45 440 fatal("Your host does not have line printer access");
4d4caa50 441}