⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lpd.c

📁 早期freebsd实现
💻 C
字号:
/* * Copyright (c) 1983, 1993, 1994 *	The Regents of the University of California.  All rights reserved. * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char copyright[] ="@(#) Copyright (c) 1983, 1993, 1994\n\	The Regents of the University of California.  All rights reserved.\n";#endif /* not lint */#ifndef lintstatic char sccsid[] = "@(#)lpd.c	8.4 (Berkeley) 4/17/94";#endif /* not lint *//* * lpd -- line printer daemon. * * Listen for a connection and perform the requested operation. * Operations are: *	\1printer\n *		check the queue for jobs and print any found. *	\2printer\n *		receive a job from another machine and queue it. *	\3printer [users ...] [jobs ...]\n *		return the current state of the queue (short form). *	\4printer [users ...] [jobs ...]\n *		return the current state of the queue (long form). *	\5printer person [users ...] [jobs ...]\n *		remove jobs from the queue. * * Strategy to maintain protected spooling area: *	1. Spooling area is writable only by daemon and spooling group *	2. lpr runs setuid root and setgrp spooling group; it uses *	   root to access any file it wants (verifying things before *	   with an access call) and group id to know how it should *	   set up ownership of files in the spooling area. *	3. Files in spooling area are owned by root, group spooling *	   group, with mode 660. *	4. lpd, lpq and lprm run setuid daemon and setgrp spooling group to *	   access files and printer.  Users can't get to anything *	   w/o help of lpq and lprm programs. */#include <sys/param.h>#include <sys/wait.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/un.h>#include <sys/stat.h>#include <netinet/in.h>#include <netdb.h>#include <unistd.h>#include <syslog.h>#include <signal.h>#include <errno.h>#include <fcntl.h>#include <dirent.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include "lp.h"#include "lp.local.h"#include "pathnames.h"#include "extern.h"int	lflag;				/* log requests flag */int	from_remote;			/* from remote socket */static void       reapchild __P((int));static void       mcleanup __P((int));static void       doit __P((void));static void       startup __P((void));static void       chkhost __P((struct sockaddr_in *));intmain(argc, argv)	int argc;	char **argv;{	int f, funix, finet, options, fromlen;	fd_set defreadfds;	struct sockaddr_un un, fromunix;	struct sockaddr_in sin, frominet;	int omask, lfd;	options = 0;	gethostname(host, sizeof(host));	name = argv[0];	while (--argc > 0) {		argv++;		if (argv[0][0] == '-')			switch (argv[0][1]) {			case 'd':				options |= SO_DEBUG;				break;			case 'l':				lflag++;				break;			}	}#ifndef DEBUG	/*	 * Set up standard environment by detaching from the parent.	 */	daemon(0, 0);#endif	openlog("lpd", LOG_PID, LOG_LPR);	syslog(LOG_INFO, "restarted");	(void) umask(0);	lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT, 0644);	if (lfd < 0) {		syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);		exit(1);	}	if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {		if (errno == EWOULDBLOCK)	/* active deamon present */			exit(0);		syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);		exit(1);	}	ftruncate(lfd, 0);	/*	 * write process id for others to know	 */	sprintf(line, "%u\n", getpid());	f = strlen(line);	if (write(lfd, line, f) != f) {		syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);		exit(1);	}	signal(SIGCHLD, reapchild);	/*	 * Restart all the printers.	 */	startup();	(void) unlink(_PATH_SOCKETNAME);	funix = socket(AF_UNIX, SOCK_STREAM, 0);	if (funix < 0) {		syslog(LOG_ERR, "socket: %m");		exit(1);	}#define	mask(s)	(1 << ((s) - 1))	omask = sigblock(mask(SIGHUP)|mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM));	signal(SIGHUP, mcleanup);	signal(SIGINT, mcleanup);	signal(SIGQUIT, mcleanup);	signal(SIGTERM, mcleanup);	memset(&un, 0, sizeof(un));	un.sun_family = AF_UNIX;	strcpy(un.sun_path, _PATH_SOCKETNAME);#ifndef SUN_LEN#define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)#endif	if (bind(funix, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) {		syslog(LOG_ERR, "ubind: %m");		exit(1);	}	sigsetmask(omask);	FD_ZERO(&defreadfds);	FD_SET(funix, &defreadfds);	listen(funix, 5);	finet = socket(AF_INET, SOCK_STREAM, 0);	if (finet >= 0) {		struct servent *sp;		if (options & SO_DEBUG)			if (setsockopt(finet, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) {				syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");				mcleanup(0);			}		sp = getservbyname("printer", "tcp");		if (sp == NULL) {			syslog(LOG_ERR, "printer/tcp: unknown service");			mcleanup(0);		}		memset(&sin, 0, sizeof(sin));		sin.sin_family = AF_INET;		sin.sin_port = sp->s_port;		if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) {			syslog(LOG_ERR, "bind: %m");			mcleanup(0);		}		FD_SET(finet, &defreadfds);		listen(finet, 5);	}	/*	 * Main loop: accept, do a request, continue.	 */	memset(&frominet, 0, sizeof(frominet));	memset(&fromunix, 0, sizeof(fromunix));	for (;;) {		int domain, nfds, s;		fd_set readfds;		FD_COPY(&defreadfds, &readfds);		nfds = select(20, &readfds, 0, 0, 0);		if (nfds <= 0) {			if (nfds < 0 && errno != EINTR)				syslog(LOG_WARNING, "select: %m");			continue;		}		if (FD_ISSET(funix, &readfds)) {			domain = AF_UNIX, fromlen = sizeof(fromunix);			s = accept(funix,			    (struct sockaddr *)&fromunix, &fromlen);		} else /* if (FD_ISSET(finet, &readfds)) */  {			domain = AF_INET, fromlen = sizeof(frominet);			s = accept(finet,			    (struct sockaddr *)&frominet, &fromlen);		}		if (s < 0) {			if (errno != EINTR)				syslog(LOG_WARNING, "accept: %m");			continue;		}		if (fork() == 0) {			signal(SIGCHLD, SIG_IGN);			signal(SIGHUP, SIG_IGN);			signal(SIGINT, SIG_IGN);			signal(SIGQUIT, SIG_IGN);			signal(SIGTERM, SIG_IGN);			(void) close(funix);			(void) close(finet);			dup2(s, 1);			(void) close(s);			if (domain == AF_INET) {				from_remote = 1;				chkhost(&frominet);			} else				from_remote = 0;			doit();			exit(0);		}		(void) close(s);	}}static voidreapchild(signo)	int signo;{	union wait status;	while (wait3((int *)&status, WNOHANG, 0) > 0)		;}static voidmcleanup(signo)	int signo;{	if (lflag)		syslog(LOG_INFO, "exiting");	unlink(_PATH_SOCKETNAME);	exit(0);}/* * Stuff for handling job specifications */char	*user[MAXUSERS];	/* users to process */int	users;			/* # of users in user array */int	requ[MAXREQUESTS];	/* job number of spool entries */int	requests;		/* # of spool requests */char	*person;		/* name of person doing lprm */char	fromb[MAXHOSTNAMELEN];	/* buffer for client's machine name */char	cbuf[BUFSIZ];		/* command line buffer */char	*cmdnames[] = {	"null",	"printjob",	"recvjob",	"displayq short",	"displayq long",	"rmjob"};static voiddoit(){	register char *cp;	register int n;	for (;;) {		cp = cbuf;		do {			if (cp >= &cbuf[sizeof(cbuf) - 1])				fatal("Command line too long");			if ((n = read(1, cp, 1)) != 1) {				if (n < 0)					fatal("Lost connection");				return;			}		} while (*cp++ != '\n');		*--cp = '\0';		cp = cbuf;		if (lflag) {			if (*cp >= '\1' && *cp <= '\5')				syslog(LOG_INFO, "%s requests %s %s",					from, cmdnames[*cp], cp+1);			else				syslog(LOG_INFO, "bad request (%d) from %s",					*cp, from);		}		switch (*cp++) {		case '\1':	/* check the queue and print any jobs there */			printer = cp;			printjob();			break;		case '\2':	/* receive files to be queued */			if (!from_remote) {				syslog(LOG_INFO, "illegal request (%d)", *cp);				exit(1);			}			printer = cp;			recvjob();			break;		case '\3':	/* display the queue (short form) */		case '\4':	/* display the queue (long form) */			printer = cp;			while (*cp) {				if (*cp != ' ') {					cp++;					continue;				}				*cp++ = '\0';				while (isspace(*cp))					cp++;				if (*cp == '\0')					break;				if (isdigit(*cp)) {					if (requests >= MAXREQUESTS)						fatal("Too many requests");					requ[requests++] = atoi(cp);				} else {					if (users >= MAXUSERS)						fatal("Too many users");					user[users++] = cp;				}			}			displayq(cbuf[0] - '\3');			exit(0);		case '\5':	/* remove a job from the queue */			if (!from_remote) {				syslog(LOG_INFO, "illegal request (%d)", *cp);				exit(1);			}			printer = cp;			while (*cp && *cp != ' ')				cp++;			if (!*cp)				break;			*cp++ = '\0';			person = cp;			while (*cp) {				if (*cp != ' ') {					cp++;					continue;				}				*cp++ = '\0';				while (isspace(*cp))					cp++;				if (*cp == '\0')					break;				if (isdigit(*cp)) {					if (requests >= MAXREQUESTS)						fatal("Too many requests");					requ[requests++] = atoi(cp);				} else {					if (users >= MAXUSERS)						fatal("Too many users");					user[users++] = cp;				}			}			rmjob();			break;		}		fatal("Illegal service request");	}}/* * Make a pass through the printcap database and start printing any * files left from the last time the machine went down. */static voidstartup(){	char *buf;	register char *cp;	int pid;	/*	 * Restart the daemons.	 */	while (cgetnext(&buf, printcapdb) > 0) {		for (cp = buf; *cp; cp++)			if (*cp == '|' || *cp == ':') {				*cp = '\0';				break;			}		if ((pid = fork()) < 0) {			syslog(LOG_WARNING, "startup: cannot fork");			mcleanup(0);		}		if (!pid) {			printer = buf;			cgetclose();			printjob();		}	}}#define DUMMY ":nobody::"/* * Check to see if the from host has access to the line printer. */static voidchkhost(f)	struct sockaddr_in *f;{	register struct hostent *hp;	register FILE *hostf;	int first = 1;	extern char *inet_ntoa();	f->sin_port = ntohs(f->sin_port);	if (f->sin_family != AF_INET || f->sin_port >= IPPORT_RESERVED)		fatal("Malformed from address");	/* Need real hostname for temporary filenames */	hp = gethostbyaddr((char *)&f->sin_addr,	    sizeof(struct in_addr), f->sin_family);	if (hp == NULL)		fatal("Host name for your address (%s) unknown",			inet_ntoa(f->sin_addr));	(void) strncpy(fromb, hp->h_name, sizeof(fromb));	from[sizeof(fromb) - 1] = '\0';	from = fromb;	hostf = fopen(_PATH_HOSTSEQUIV, "r");again:	if (hostf) {		if (__ivaliduser(hostf, f->sin_addr.s_addr,		    DUMMY, DUMMY) == 0) {			(void) fclose(hostf);			return;		}		(void) fclose(hostf);	}	if (first == 1) {		first = 0;		hostf = fopen(_PATH_HOSTSLPD, "r");		goto again;	}	fatal("Your host does not have line printer access");	/*NOTREACHED*/}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -