Beispiel #1
0
int
main(int argc, char **argv)
{
	FILE *acctf;
	const char *cp, *printer;

	printer = NULL;
	euid = geteuid();	/* these aren't used in pac(1) */
	uid = getuid();
	while (--argc) {
		cp = *++argv;
		if (*cp++ == '-') {
			switch(*cp++) {
			case 'P':
				/*
				 * Printer name.
				 */
				printer = cp;
				continue;

			case 'p':
				/*
				 * get the price.
				 */
				price = atof(cp);
				pflag = 1;
				continue;

			case 's':
				/*
				 * Summarize and compress accounting file.
				 */
				summarize++;
				continue;

			case 'c':
				/*
				 * Sort by cost.
				 */
				sort++;
				continue;

			case 'm':
				/*
				 * disregard machine names for each user
				 */
				mflag = 1;
				continue;

			case 'r':
				/*
				 * Reverse sorting order.
				 */
				reverse++;
				continue;

			default:
				usage();
			}
		}
		(void) enter(--cp);
		allflag = 0;
	}
	if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
		printer = DEFLP;
	if (!chkprinter(printer)) {
		printf("pac: unknown printer %s\n", printer);
		exit(2);
	}

	if ((acctf = fopen(acctfile, "r")) == NULL) {
		perror(acctfile);
		exit(1);
	}
	account(acctf);
	fclose(acctf);
	if ((acctf = fopen(sumfile, "r")) != NULL) {
		account(acctf);
		fclose(acctf);
	}
	if (summarize)
		rewrite();
	else
		dumpit();
	exit(errs);
}
Beispiel #2
0
int
main(int argc, char *argv[])
{
	struct passwd *pw;
	struct group *gptr;
	const char *arg, *cp, *printer;
	char *p;
	char buf[BUFSIZ];
	int c, i, f, errs;
	int	 ret, didlink;
	struct stat stb;
	struct stat statb1, statb2;
	struct printer myprinter, *pp = &myprinter;

	printer = NULL;
	euid = geteuid();
	uid = getuid();
	PRIV_END
	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
		signal(SIGHUP, cleanup);
	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
		signal(SIGINT, cleanup);
	if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
		signal(SIGQUIT, cleanup);
	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
		signal(SIGTERM, cleanup);

	progname = argv[0];
	gethostname(local_host, sizeof(local_host));
	openlog("lpd", 0, LOG_LPR);

	errs = 0;
	while ((c = getopt(argc, argv,
			   ":#:1:2:3:4:C:J:L:P:T:U:Z:cdfghi:lnmprstvw:"))
	       != -1)
		switch (c) {
		case '#':		/* n copies */
			i = strtol(optarg, &p, 10);
			if (*p)
				errx(1, "Bad argument to -#, number expected");
			if (i > 0)
				ncopies = i;
			break;

		case '1':		/* troff fonts */
		case '2':
		case '3':
		case '4':
			fonts[optopt - '1'] = optarg;
			break;

		case 'C':		/* classification spec */
			hdr++;
			class = optarg;
			break;

		case 'J':		/* job name */
			hdr++;
			jobname = optarg;
			break;

		case 'P':		/* specifiy printer name */
			printer = optarg;
			break;

		case 'L':               /* pr's locale */
			locale = optarg;
			break;

		case 'T':		/* pr's title line */
			title = optarg;
			break;

		case 'U':		/* user name */
			hdr++;
			Uflag = optarg;
			break;

		case 'Z':
			Zflag = optarg;
			break;

		case 'c':		/* print cifplot output */
		case 'd':		/* print tex output (dvi files) */
		case 'g':		/* print graph(1G) output */
		case 'l':		/* literal output */
		case 'n':		/* print ditroff output */
		case 't':		/* print troff output (cat files) */
		case 'p':		/* print using ``pr'' */
		case 'v':		/* print vplot output */
			format = optopt;
			break;

		case 'f':		/* print fortran output */
			format = 'r';
			break;

		case 'h':		/* nulifiy header page */
			hdr = 0;
			break;

		case 'i':		/* indent output */
			iflag++;
			indent = strtol(optarg, &p, 10);
			if (*p)
				errx(1, "Bad argument to -i, number expected");
			break;

		case 'm':		/* send mail when done */
			mailflg++;
			break;

		case 'q':		/* just queue job */
			qflag++;
			break;

		case 'r':		/* remove file when done */
			rflag++;
			break;

		case 's':		/* try to link files */
			sflag++;
			break;

		case 'w':		/* versatec page width */
			width = optarg;
			break;

		case ':':		/* catch "missing argument" error */
			if (optopt == 'i') {
				iflag++; /* -i without args is valid */
				indent = 8;
			} else
				errs++;
			break;

		default:
			errs++;
		}
	argc -= optind;
	argv += optind;
	if (errs)
		usage();
	if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
		printer = DEFLP;
	chkprinter(printer, pp);
	if (pp->no_copies && ncopies > 1)
		errx(1, "multiple copies are not allowed");
	if (pp->max_copies > 0 && ncopies > pp->max_copies)
		errx(1, "only %ld copies are allowed", pp->max_copies);
	/*
	 * Get the identity of the person doing the lpr using the same
	 * algorithm as lprm.  Actually, not quite -- lprm will override
	 * the login name with "root" if the user is running as root;
	 * the daemon actually checks for the string "root" in its
	 * permission checking.  Sigh.
	 */
	userid = getuid();
	if (Uflag) {
		if (userid != 0 && userid != pp->daemon_user)
			errx(1, "only privileged users may use the `-U' flag");
		lpr_username = Uflag;		/* -U person doing 'lpr' */
	} else {
		lpr_username = getlogin();	/* person doing 'lpr' */
		if (userid != pp->daemon_user || lpr_username == 0) {
			if ((pw = getpwuid(userid)) == NULL)
				errx(1, "Who are you?");
			lpr_username = pw->pw_name;
		}
	}

	/*
	 * Check for restricted group access.
	 */
	if (pp->restrict_grp != NULL && userid != pp->daemon_user) {
		if ((gptr = getgrnam(pp->restrict_grp)) == NULL)
			errx(1, "Restricted group specified incorrectly");
		if (gptr->gr_gid != getgid()) {
			while (*gptr->gr_mem != NULL) {
				if ((strcmp(lpr_username, *gptr->gr_mem)) == 0)
					break;
				gptr->gr_mem++;
			}
			if (*gptr->gr_mem == NULL)
				errx(1, "Not a member of the restricted group");
		}
	}
	/*
	 * Check to make sure queuing is enabled if userid is not root.
	 */
	lock_file_name(pp, buf, sizeof buf);
	if (userid && stat(buf, &stb) == 0 && (stb.st_mode & LFM_QUEUE_DIS))
		errx(1, "Printer queue is disabled");
	/*
	 * Initialize the control file.
	 */
	mktemps(pp);
	tfd = nfile(tfname);
	PRIV_START
	(void) fchown(tfd, pp->daemon_user, -1);
	/* owned by daemon for protection */
	PRIV_END
	card('H', local_host);
	card('P', lpr_username);
	card('C', class);
	if (hdr && !pp->no_header) {
		if (jobname == NULL) {
			if (argc == 0)
				jobname = "stdin";
			else
				jobname = ((arg = strrchr(argv[0], '/'))
					   ? arg + 1 : argv[0]);
		}
		card('J', jobname);
		card('L', lpr_username);
	}
	if (format != 'p' && Zflag != 0)
		card('Z', Zflag);
	if (iflag)
		card('I', itoa(indent));
	if (mailflg)
		card('M', lpr_username);
	if (format == 't' || format == 'n' || format == 'd')
		for (i = 0; i < 4; i++)
			if (fonts[i] != NULL)
				card('1'+i, fonts[i]);
	if (width != NULL)
		card('W', width);
	/*
	 * XXX
	 * Our use of `Z' here is incompatible with LPRng's
	 * use.  We assume that the only use of our existing
	 * `Z' card is as shown for `p' format (pr) files.
	 */
	if (format == 'p') {
		char *s;

		if (locale)
			card('Z', locale);
		else if ((s = setlocale(LC_TIME, "")) != NULL)
			card('Z', s);
	}

	/*
	 * Read the files and spool them.
	 */
	if (argc == 0)
		copy(pp, 0, " ");
	else while (argc--) {
		if (argv[0][0] == '-' && argv[0][1] == '\0') {
			/* use stdin */
			copy(pp, 0, " ");
			argv++;
			continue;
		}
		if ((f = test(arg = *argv++)) < 0)
			continue;	/* file unreasonable */

		if (sflag && (cp = linked(arg)) != NULL) {
			(void)snprintf(buf, sizeof(buf), "%ju %ju",
			    (uintmax_t)statb.st_dev, (uintmax_t)statb.st_ino);
			card('S', buf);
			if (format == 'p')
				card('T', title ? title : arg);
			for (i = 0; i < ncopies; i++)
				card(format, &dfname[inchar-2]);
			card('U', &dfname[inchar-2]);
			if (f)
				card('U', cp);
			card('N', arg);
			dfname[inchar]++;
			nact++;
			continue;
		}
		if (sflag)
			printf("%s: %s: not linked, copying instead\n",
			    progname, arg);

		if (f) {
			/*
			 * The user wants the file removed after it is copied
			 * to the spool area, so see if the file can be moved
			 * instead of copy/unlink'ed.  This is much faster and
			 * uses less spool space than copying the file.  This
			 * can be very significant when running services like
			 * samba, pcnfs, CAP, et al.
			 */
			PRIV_START
			didlink = 0;
			/*
			 * There are several things to check to avoid any
			 * security issues.  Some of these are redundant
			 * under BSD's, but are necessary when lpr is built
			 * under some other OS's (which I do do...)
			 */
			if (lstat(arg, &statb1) < 0)
				goto nohardlink;
			if (S_ISLNK(statb1.st_mode))
				goto nohardlink;
			if (link(arg, dfname) != 0)
				goto nohardlink;
			didlink = 1;
			/*
			 * Make sure the user hasn't tried to trick us via
			 * any race conditions
			 */
			if (lstat(dfname, &statb2) < 0)
				goto nohardlink;
			if (statb1.st_dev != statb2.st_dev)
				goto nohardlink;
			if (statb1.st_ino != statb2.st_ino)
				goto nohardlink;
			/*
			 * Skip if the file already had multiple hard links,
			 * because changing the owner and access-bits would
			 * change ALL versions of the file
			 */
			if (statb2.st_nlink > 2)
				goto nohardlink;
			/*
			 * If we can access and remove the original file
			 * without special setuid-ness then this method is
			 * safe.  Otherwise, abandon the move and fall back
			 * to the (usual) copy method.
			 */
			PRIV_END
			ret = access(dfname, R_OK);
			if (ret == 0)
				ret = unlink(arg);
			PRIV_START
			if (ret != 0)
				goto nohardlink;
			/*
			 * Unlink of user file was successful.  Change the
			 * owner and permissions, add entries to the control
			 * file, and skip the file copying step.
			 */
			chown(dfname, pp->daemon_user, getegid());
			chmod(dfname, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
			PRIV_END
			if (format == 'p')
				card('T', title ? title : arg);
			for (i = 0; i < ncopies; i++)
				card(format, &dfname[inchar-2]);
			card('U', &dfname[inchar-2]);
			card('N', arg);
			nact++;
			continue;
		nohardlink:
			if (didlink)
				unlink(dfname);
			PRIV_END           /* restore old uid */
		} /* end: if (f) */

		if ((i = open(arg, O_RDONLY)) < 0) {
			printf("%s: cannot open %s\n", progname, arg);
		} else {
			copy(pp, i, arg);
			(void) close(i);
			if (f && unlink(arg) < 0)
				printf("%s: %s: not removed\n", progname, arg);
		}
	}

	if (nact) {
		(void) close(tfd);
		tfname[inchar]--;
		/*
		 * Touch the control file to fix position in the queue.
		 */
		PRIV_START
		if ((tfd = open(tfname, O_RDWR)) >= 0) {
			char touch_c;

			if (read(tfd, &touch_c, 1) == 1 &&
			    lseek(tfd, (off_t)0, 0) == 0 &&
			    write(tfd, &touch_c, 1) != 1) {
				printf("%s: cannot touch %s\n", progname,
				    tfname);
				tfname[inchar]++;
				cleanup(0);
			}
			(void) close(tfd);
		}
		if (link(tfname, cfname) < 0) {
			printf("%s: cannot rename %s\n", progname, cfname);
			tfname[inchar]++;
			cleanup(0);
		}
		unlink(tfname);
		PRIV_END
		if (qflag)		/* just q things up */
			exit(0);
		if (!startdaemon(pp))
			printf("jobs queued, but cannot start daemon.\n");
		exit(0);
	}
	cleanup(0);
	return (1);
	/* NOTREACHED */
}
Beispiel #3
0
int
main(int argc, char *argv[])
{
	struct passwd *pw;
	struct group *gptr;
	char *arg;
	const char *cp;
	char buf[MAXPATHLEN];
	int i, f, errs, c;
	struct stat stb;
	int oerrno;

	euid = geteuid();
	uid = getuid();
	seteuid(uid);

	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
		signal(SIGHUP, cleanup);
	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
		signal(SIGINT, cleanup);
	if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
		signal(SIGQUIT, cleanup);
	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
		signal(SIGTERM, cleanup);

	setprogname(*argv);
	gethostname(host, sizeof (host));
	host[sizeof(host) - 1] = '\0';
	openlog("lpd", 0, LOG_LPR);

	errs = 0;
	while ((c = getopt(argc, argv,
	    ":#:1:2:3:4:C:J:P:RT:U:cdfghi:lmnopqrstvw:")) != -1) {
		switch (c) {

		case '#':		/* n copies */
			if (isdigit((unsigned char)*optarg)) {
				i = atoi(optarg);
				if (i > 0)
					ncopies = i;
			}
			break;

		case '4':		/* troff fonts */
		case '3':
		case '2':
		case '1':
			fonts[optopt - '1'] = optarg;
			break;

		case 'C':		/* classification spec */
			hdr++;
			class = optarg;
			break;

		case 'J':		/* job name */
			hdr++;
			jobname = optarg;
			break;

		case 'P':		/* specifiy printer name */
			printer = optarg;
			break;

		case 'R':		/* print request id */
			Rflag++;
			break;
			
		case 'T':		/* pr's title line */
			title = optarg;
			break;

		case 'U':		/* user name */
			hdr++;
			person = optarg;
			break;

		case 'c':		/* print cifplot output */
		case 'd':		/* print tex output (dvi files) */
		case 'g':		/* print graph(1G) output */
		case 'l':		/* literal output */
		case 'o':		/* print postscript output */
		case 'n':		/* print ditroff output */
		case 'p':		/* print using ``pr'' */
		case 't':		/* print troff output (cat files) */
		case 'v':		/* print vplot output */
			format = optopt;
			break;

		case 'f':		/* print fortran output */
			format = 'r';
			break;

		case 'h':		/* toggle want of header page */
			hdr = !hdr;
			break;

		case 'i':		/* indent output */
			iflag++;
			indent = atoi(optarg);
			if (indent < 0)
				indent = 8;
			break;

		case 'm':		/* send mail when done */
			mailflg++;
			break;

		case 'q':		/* just q job */
			qflag++;
			break;

		case 'r':		/* remove file when done */
			rflag++;
			break;

		case 's':		/* try to link files */
			sflag++;
			break;

		case 'w':		/* versatec page width */
			width = optarg;
			break;

		case ':':               /* catch "missing argument" error */
			if (optopt == 'i') {
				iflag++; /* -i without args is valid */
				indent = 8;
			} else
				errs++;
			break;

		default:
			errs++;
		}
	}
	argc -= optind;
	argv += optind;
	if (errs)
		usage();
	if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
		printer = DEFLP;
	chkprinter(printer);
	if (SC && ncopies > 1)
		errx(EXIT_FAILURE, "multiple copies are not allowed");
	if (MC > 0 && ncopies > MC)
		errx(EXIT_FAILURE, "only %ld copies are allowed", MC);
	/*
	 * Get the identity of the person doing the lpr using the same
	 * algorithm as lprm. 
	 */
	userid = getuid();
	if (userid != DU || person == 0) {
		if ((pw = getpwuid(userid)) == NULL)
			errx(EXIT_FAILURE, "Who are you?");
		person = pw->pw_name;
	}
	/*
	 * Check for restricted group access.
	 */
	if (RG != NULL && userid != DU) {
		if ((gptr = getgrnam(RG)) == NULL)
			errx(EXIT_FAILURE,
			     "Restricted group specified incorrectly");
		if (gptr->gr_gid != getgid()) {
			while (*gptr->gr_mem != NULL) {
				if ((strcmp(person, *gptr->gr_mem)) == 0)
					break;
				gptr->gr_mem++;
			}
			if (*gptr->gr_mem == NULL)
				errx(EXIT_FAILURE,
				     "Not a member of the restricted group");
		}
	}
	/*
	 * Check to make sure queuing is enabled if userid is not root.
	 */
	(void)snprintf(buf, sizeof buf, "%s/%s", SD, LO);
	if (userid && stat(buf, &stb) == 0 && (stb.st_mode & S_IXGRP))
		errx(EXIT_FAILURE, "Printer queue is disabled");
	/*
	 * Initialize the control file.
	 */
	mktemps();
	tfd = nfile(tfname);
	seteuid(euid);
	(void)fchown(tfd, DU, -1);	/* owned by daemon for protection */
	seteuid(uid);
	card('H', host);
	card('P', person);
	if (hdr && !SH) {
		if (jobname == NULL) {
			if (argc == 0)
				jobname = "stdin";
			else
				jobname = (arg = strrchr(argv[0], '/')) ?
				    arg+1 : argv[0];
		}
		card('J', jobname);
		card('C', class);
		card('L', person);
	}
	if (iflag)
		card('I', itoa(indent));
	if (mailflg)
		card('M', person);
	if (format == 't' || format == 'n' || format == 'd')
		for (i = 0; i < 4; i++)
			if (fonts[i] != NULL)
				card('1'+i, fonts[i]);
	if (width != NULL)
		card('W', width);

	/*
	 * Read the files and spool them.
	 */
	if (argc == 0)
		copy(0, " ");
	else while (argc--) {
		if (argv[0][0] == '-' && argv[0][1] == '\0') {
			/* use stdin */
			copy(0, " ");
			argv++;
			continue;
		}
		if ((f = test(arg = *argv++)) < 0)
			continue;	/* file unreasonable */

		if (sflag && (cp = linked(arg)) != NULL) {
			(void)snprintf(buf, sizeof buf,
			    "%llu %llu",
			    (unsigned long long)statb.st_dev,
			    (unsigned long long)statb.st_ino);
			card('S', buf);
			if (format == 'p')
				card('T', title ? title : arg);
			for (i = 0; i < ncopies; i++)
				card(format, &dfname[inchar-2]);
			card('U', &dfname[inchar-2]);
			if (f)
				card('U', cp);
			card('N', arg);
			dfname[inchar]++;
			nact++;
			continue;
		}
		if (sflag)
			warnx("%s: not linked, copying instead", arg);
		seteuid(uid);
		if ((i = open(arg, O_RDONLY)) < 0) {
			oerrno = errno;
			seteuid(uid);
			errno = oerrno;
			warn("cannot open %s", arg);
			continue;
		} else {
			copy(i, arg);
			(void)close(i);
			if (f && unlink(arg) < 0)
				warn("%s: not removed", arg);
		}
		seteuid(uid);
	}

	if (nact) {
		(void)close(tfd);
		tfname[inchar]--;
		/*
		 * Touch the control file to fix position in the queue.
		 */
		seteuid(euid);
		if ((tfd = open(tfname, O_RDWR)) >= 0) {
			char ch;

			if (read(tfd, &ch, 1) == 1 &&
			    lseek(tfd, (off_t)0, 0) == 0 &&
			    write(tfd, &ch, 1) != 1) {
				warn("cannot touch %s", tfname);
				tfname[inchar]++;
				cleanup(0);
			}
			(void)close(tfd);
		}
		if (link(tfname, cfname) < 0) {
			warn("cannot rename %s", cfname);
			tfname[inchar]++;
			cleanup(0);
		}
		unlink(tfname);
		seteuid(uid);
		if (Rflag)
			printf("request id is %d\n", reqid);
		if (qflag)		/* just queue things up */
			exit(0);
		if (!startdaemon(printer))
			printf("jobs queued, but cannot start daemon.\n");
		exit(0);
	}
	cleanup(0);
#ifdef __GNUC__
	return (0);
#endif
	/* NOTREACHED */
}
Beispiel #4
0
int
main(int argc, char **argv)
{
	struct passwd *pw;
	struct group *gptr;
	char *arg, *cp;
	char buf[MAXPATHLEN];
	int i, f, ch;
	struct stat stb;

	/*
	 * Simulate setuid daemon w/ PRIV_END called.
	 * We don't want lpr to actually be setuid daemon since that
	 * requires that the lpr binary be owned by user daemon, which
	 * is potentially unsafe.
	 */
	if ((pw = getpwuid(DEFUID)) == NULL)
		errx(1, "daemon uid (%u) not in password file", DEFUID);
	effective_uid = pw->pw_uid;
	real_uid = getuid();
	effective_gid = pw->pw_gid;
	real_gid = getgid();
	setresgid(real_gid, real_gid, effective_gid);
	setresuid(real_uid, real_uid, effective_uid);

	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
		signal(SIGHUP, cleanup);
	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
		signal(SIGINT, cleanup);
	if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
		signal(SIGQUIT, cleanup);
	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
		signal(SIGTERM, cleanup);

	gethostname(host, sizeof (host));
	openlog("lpr", 0, LOG_LPR);

	while ((ch = getopt(argc, argv,
	    ":#:1:2:3:4:C:J:P:T:U:cdfghi:lmnpqrstvw:")) != -1) {
		switch (ch) {

		case '#':		/* n copies */
			if (isdigit((unsigned char)*optarg)) {
				i = atoi(optarg);
				if (i > 0)
					ncopies = i;
			}
			break;

		case '4':		/* troff fonts */
		case '3':
		case '2':
		case '1':
			fonts[ch - '1'] = optarg;
			break;

		case 'C':		/* classification spec */
			hdr++;
			class = optarg;
			break;

		case 'J':		/* job name */
			hdr++;
			jobname = optarg;
			break;

		case 'P':		/* specifiy printer name */
			printer = optarg;
			break;

		case 'T':		/* pr's title line */
			title = optarg;
			break;

		case 'U':		/* user name */
			hdr++;
			person = optarg;
			break;

		case 'c':		/* print cifplot output */
		case 'd':		/* print tex output (dvi files) */
		case 'g':		/* print graph(1G) output */
		case 'l':		/* literal output */
		case 'n':		/* print ditroff output */
		case 'p':		/* print using ``pr'' */
		case 't':		/* print troff output (cat files) */
		case 'v':		/* print vplot output */
			format = ch;
			break;

		case 'f':		/* print fortran output */
			format = 'r';
			break;

		case 'h':		/* toggle want of header page */
			hdr = !hdr;
			break;

		case 'i':		/* indent output */
			iflag++;
			indent = atoi(optarg);
			if (indent < 0)
				indent = 8;
			break;

		case 'm':		/* send mail when done */
			mailflg++;
			break;

		case 'q':		/* just q job */
			qflag++;
			break;

		case 'r':		/* remove file when done */
			rflag++;
			break;

		case 's':		/* try to link files */
			sflag++;
			break;

		case 'w':		/* versatec page width */
			width = optarg;
			break;

		case ':':               /* catch "missing argument" error */
			if (optopt == 'i') {
				iflag++; /* -i without args is valid */
				indent = 8;
			} else
				usage();
			break;

		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;
	if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
		printer = DEFLP;
	chkprinter(printer);
	if (SC && ncopies > 1)
		errx(1, "multiple copies are not allowed");
	if (MC > 0 && ncopies > MC)
		errx(1, "only %ld copies are allowed", MC);
	/*
	 * Get the identity of the person doing the lpr using the same
	 * algorithm as lprm. 
	 */
	if (real_uid != DU || person == NULL) {
		if ((pw = getpwuid(real_uid)) == NULL)
			errx(1, "Who are you?");
		if ((person = strdup(pw->pw_name)) == NULL)
			err(1, NULL);
	}
	/*
	 * Check for restricted group access.
	 */
	if (RG != NULL && real_uid != DU) {
		if ((gptr = getgrnam(RG)) == NULL)
			errx(1, "Restricted group specified incorrectly");
		if (gptr->gr_gid != getgid()) {
			while (*gptr->gr_mem != NULL) {
				if ((strcmp(person, *gptr->gr_mem)) == 0)
					break;
				gptr->gr_mem++;
			}
			if (*gptr->gr_mem == NULL)
				errx(1, "Not a member of the restricted group");
		}
	}
	/*
	 * Check to make sure queuing is enabled if real_uid is not root.
	 */
	(void)snprintf(buf, sizeof(buf), "%s/%s", SD, LO);
	if (real_uid && stat(buf, &stb) == 0 && (stb.st_mode & 010))
		errx(1, "Printer queue is disabled");
	/*
	 * Initialize the control file.
	 */
	mktemps();
	tfd = nfile(tfname);
	card('H', host);
	card('P', person);
	if (hdr) {
		if (jobname == NULL) {
			if (argc == 0)
				jobname = "stdin";
			else
				jobname = (arg = strrchr(argv[0], '/')) ?
				    arg + 1 : argv[0];
		}
		card('J', jobname);
		card('C', class);
		if (!SH)
			card('L', person);
	}
	if (iflag)
		card('I', itoa(indent));
	if (mailflg)
		card('M', person);
	if (format == 't' || format == 'n' || format == 'd')
		for (i = 0; i < 4; i++)
			if (fonts[i] != NULL)
				card('1'+i, fonts[i]);
	if (width != NULL)
		card('W', width);

	/*
	 * Read the files and spool them.
	 */
	if (argc == 0)
		copy(0, " ");
	else while (argc--) {
		if (argv[0][0] == '-' && argv[0][1] == '\0') {
			/* use stdin */
			copy(0, " ");
			argv++;
			continue;
		}
		if ((f = test(arg = *argv++)) < 0)
			continue;	/* file unreasonable */

		if (sflag && (cp = linked(arg)) != NULL) {
			(void)snprintf(buf, sizeof(buf), "%d %llu",
			    statb.st_dev, (unsigned long long)statb.st_ino);
			card('S', buf);
			if (format == 'p')
				card('T', title ? title : arg);
			for (i = 0; i < ncopies; i++)
				card(format, &dfname[inchar-2]);
			card('U', &dfname[inchar-2]);
			if (f)
				card('U', cp);
			card('N', arg);
			dfname[inchar]++;
			nact++;
			continue;
		}
		if (sflag)
			warnx("%s: not linked, copying instead", arg);
		if ((i = safe_open(arg, O_RDONLY, 0)) < 0)
			warn("%s", arg);
		else {
			copy(i, arg);
			(void)close(i);
			if (f && unlink(arg) < 0)
				warnx("%s: not removed", arg);
		}
	}

	if (nact) {
		(void)close(tfd);
		tfname[inchar]--;
		/*
		 * Touch the control file to fix position in the queue.
		 */
		PRIV_START;
		if ((tfd = safe_open(tfname, O_RDWR|O_NOFOLLOW, 0)) >= 0) {
			char c;

			if (read(tfd, &c, 1) == 1 &&
			    lseek(tfd, (off_t)0, SEEK_SET) == 0 &&
			    write(tfd, &c, 1) != 1) {
				warn("%s", tfname);
				tfname[inchar]++;
				cleanup(0);
			}
			(void)close(tfd);
		}
		if (link(tfname, cfname) < 0) {
			warn("cannot rename %s", cfname);
			tfname[inchar]++;
			cleanup(0);
		}
		unlink(tfname);
		PRIV_END;
		if (qflag)		/* just q things up */
			exit(0);
		if (!startdaemon(printer))
			printf("jobs queued, but cannot start daemon.\n");
		exit(0);
	}
	cleanup(0);
	return (1);
	/* NOTREACHED */
}
Beispiel #5
0
int
main(int argc, char **argv)
{
	FILE *acct;
	int ch;

	/* these aren't actually used in pac(1) */
	effective_uid = geteuid();
	real_uid = getuid();
	effective_gid = getegid();
	real_gid = getgid();

	while ((ch = getopt(argc, argv, "P:p:scmr")) != -1) {
		switch (ch) {
		case 'P':
			/*
			 * Printer name.
			 */
			printer = optarg;
			continue;

		case 'p':
			/*
			 * get the price.
			 */
			price = atof(optarg);
			pflag = 1;
			continue;

		case 's':
			/*
			 * Summarize and compress accounting file.
			 */
			summarize++;
			continue;

		case 'c':
			/*
			 * Sort by cost.
			 */
			sort++;
			continue;

		case 'm':
			/*
			 * disregard machine names for each user
			 */
			mflag = 1;
			continue;

		case 'r':
			/*
			 * Reverse sorting order.
			 */
			reverse++;
			continue;

		default:
			usage();
			/* NOTREACHED */
		}
	}
	argc -= optind;
	argv += optind;

	/*
	 * If there are any arguments left, they're names of users
	 * we want to print info for. In that case, put them in the hash
	 * table and unset allflag.
	 */
	for( ; argc > 0; argc--, argv++) {
		(void)enter(*argv);
		allflag = 0;
	}

	if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
		printer = DEFLP;
	if (!chkprinter(printer))
		errx(2, "unknown printer: %s", printer);

	if ((acct = fopen(acctfile, "r")) == NULL)
		err(1, "%s", acctfile);
	account(acct);
	fclose(acct);
	if ((acct = fopen(sumfile, "r")) != NULL) {
		account(acct);
		fclose(acct);
	}
	if (summarize)
		rewrite();
	else
		dumpit();
	exit(errs);
}
Beispiel #6
0
int
pickfilter(RSTATUS *prs, CANDIDATE *pc, FSTATUS *pfs)
{
	register char **	pp;
	register char **	pl;

	register PSTATUS *	pps		= pc->pps;

	char *			pipes[2]	= { 0 , 0 };
	char *			cp;
	char *			output_type;

	char **			modes		= 0;
	char **			parms		= 0;
	char **			valid_printer_types;
	char **			p_cpi		= 0;
	char **			p_lpi		= 0;
	char **			p_pwid		= 0;
	char **			p_plen		= 0;

	FILTERTYPE		ret		= fl_none;

	int			got_cpi		= 0;
	int			got_lpi		= 0;
	int			got_plen	= 0;
	int			got_pwid	= 0;
	int			must_have_filter= 0;

	unsigned long		chk;


	/* fix for bugid 1097387	*/
	output_type = (char *) NULL;

	/*
	 * The bulk of the code below is building a parameter list "parms"
	 * to send to "insfilter()".
	 */

	if (prs->request->modes) {
		cp = Strdup(prs->request->modes);
		transform_WS_to_SEP(cp);
		modes = getlist(cp, "", LP_SEP);
		Free (cp);
	}

	pp = parms = (char **)Malloc(
		2 * (NPARM_SPEC + lenlist(modes) + 1) * sizeof(char *)
	);

	/*
	 * Add to the parameter list the appropriate cpi/lpi/etc.
	 * characteristics (aka ``stuff'') that will be used for
	 * this job. The printer defaults are questionable.
	 * Take this opportunity to also save the ``stuff'' in
	 * the request structure.
	 */

	unload_str (&(prs->cpi));
	unload_str (&(prs->lpi));
	unload_str (&(prs->plen));
	unload_str (&(prs->pwid));

	/*
	 * If a form is involved, pick up its page size and print
	 * spacing requirements.
	 */
	if (pfs) {
		if (pfs->cpi) {
			*pp++ = PARM_CPI;
			*pp++ = prs->cpi = pfs->cpi;
			got_cpi = 1;
		}
		if (pfs->lpi) {
			*pp++ = PARM_LPI;
			*pp++ = prs->lpi = pfs->lpi;
			got_lpi = 1;
		}
		if (pfs->plen) {
			*pp++ = PARM_LENGTH;
			*pp++ = prs->plen = pfs->plen;
			got_plen = 1;
		}
		if (pfs->pwid) {
			*pp++ = PARM_WIDTH;
			*pp++ = prs->pwid = pfs->pwid;
			got_pwid = 1;
		}

	/*
	 * If no form is involved, pick up whatever page size and print
	 * spacing requirements were given by the user.
	 */
	} else {
		if (o_cpi) {
			*pp++ = PARM_CPI;
			*pp++ = prs->cpi = o_cpi;
			got_cpi = 1;
		}
		if (o_lpi) {
			*pp++ = PARM_LPI;
			*pp++ = prs->lpi = o_lpi;
			got_lpi = 1;
		}
		if (o_length) {
			*pp++ = PARM_LENGTH;
			*pp++ = prs->plen = o_length;
			got_plen = 1;
		}
		if (o_width) {
			*pp++ = PARM_WIDTH;
			*pp++ = prs->pwid = o_width;
			got_pwid = 1;
		}
	}

	/*
	 * Pick up whatever page size and print spacing requirements
	 * haven't been specified yet from the printer defaults.
	 *
	 * Note: The following cpi/lpi/etc are guaranteed to work
	 * for at least one type of the printer at hand, but not
	 * necessarily all types. Once we pick a type that works
	 * we'll verify that the cpi/lpi/etc stuff works, too.
	 * The code that does that assumes that we do the following last,
	 * after picking up the form and/or user stuff. If this changes,
	 * then the later code will have to be changed, too.
	 */
	if (!got_cpi && pps->cpi) {
		*pp++ = PARM_CPI;
		*(p_cpi = pp++) = prs->cpi = pps->cpi;
	}
	if (!got_lpi && pps->lpi) {
		*pp++ = PARM_LPI;
		*(p_lpi = pp++) = prs->lpi = pps->lpi;
	}
	if (!got_plen && pps->plen) {
		*pp++ = PARM_LENGTH;
		*(p_plen = pp++) = prs->plen = pps->plen;
	}
	if (!got_pwid && pps->pwid) {
		*pp++ = PARM_WIDTH;
		*(p_pwid = pp++) = prs->pwid = pps->pwid;
	}

	/*
	 * Pick up the number of pages, character set (the form's
	 * or the user's), the form name, the number of copies,
	 * and the modes.
	 */

	if (prs->request->pages) {
		*pp++ = PARM_PAGES;
		*pp++ = prs->request->pages;
		must_have_filter = 1;
	}

	if (prs->request->charset) {
		*pp++ = PARM_CHARSET;
		*pp++ = prs->request->charset;

	} else if (pfs && pfs->form->chset) {
		*pp++ = PARM_CHARSET;
		*pp++ = pfs->form->chset;
	}

	if (prs->request->form) {
		*pp++ = PARM_FORM;
		*pp++ = prs->request->form;
	}

	if (prs->request->copies > 1) {
		*pp++ = PARM_COPIES;
		sprintf ((*pp++ = BIGGEST_NUMBER_S), "%d", prs->request->copies);
	}

	if (modes) {
		for (pl = modes; *pl; pl++) {
			*pp++ = PARM_MODES;
			*pp++ = *pl;
		}
		must_have_filter = 1;
	}

	*pp = 0;	/* null terminated list! */


	/*
	 * If the printer type(s) are not ``unknown'', then include
	 * them as possible ``output'' type(s) to match
	 * with the user's input type (directly, or through a filter).
	 */
	if (!STREQU(*(pps->printer->printer_types), NAME_UNKNOWN))
		valid_printer_types = pc->printer_types;
	else {
		valid_printer_types = 0;
		must_have_filter = 0;
	}

	pc->fast = 0;
	pc->slow = 0;
	pc->output_type = 0;
	pc->flags = 0;
	ret = fl_none;

	/*
	 * If we don't really need a filter and the types match,
	 * then that's good enough. Some ``broadly defined''
	 * filters might match our needs, but if the printer
	 * can do what we need, then why pull in a filter?



	 * Besides, Section 3.40 in the requirements imply
	 * that we don't use a filter if the printer can handle
	 * the file.
	 */
	if (!must_have_filter ) {

		if (
			valid_printer_types
		     && searchlist_with_terminfo(
				prs->request->input_type,
				valid_printer_types
			)
		) {
			ret = fl_both;	/* not really, but ok */
			pc->printer_type = Strdup(prs->request->input_type);

		} else if (
			pps->printer->input_types
		     && searchlist_with_terminfo(
				prs->request->input_type,
				pps->printer->input_types
			)
		) {
			ret = fl_both;	/* not really, but ok */

			/*
			 * (1) There is one printer type, might even
			 *     be ``unknown'';
			 * (2) There are several printer types, but that
			 *     means only one input type, ``simple'',
			 *     which any of the printer types can handle.
			 */
			pc->printer_type = Strdup(*(pc->printer_types));

		}
	}

	/*
	 * Don't try using a filter if the user doesn't want
	 * a filter to be used! He or she would rather see an
	 * error message than (heaven forbid!) a filter being
	 * used.
	 */
	if (ret == fl_none && !(prs->request->actions & ACT_RAW)) {

		/*
		 * For each printer type, and each input type the printer
		 * accepts, see if we have a filter that matches the
		 * request to the printer. Each time we try, save the
		 * output type we use in case of success; we just might
		 * need that value later....
		 */

		for (
			pl = valid_printer_types;
			pl && *pl && ret == fl_none;
			pl++
		)
			ret = insfilter(
				pipes,
				prs->request->input_type,
				(output_type = *pl),
				*pl,
				pps->printer->name,
				parms,
				&(pc->flags)
			);
		if (ret != fl_none)
			pc->printer_type = Strdup(*pl);

		for (
			pl = pps->printer->input_types;
			pl && *pl && ret == fl_none;
			pl++
		)
			/*
			 * Don't waste time with check we've already made.
			 */
			if ((must_have_filter == 1) ||
				!valid_printer_types
			     || !searchlist(*pl, valid_printer_types)
			)
				/*
				 * Either we have one (or less) printer
				 * types and many input types, or we have
				 * one input type, ``simple''; regardless,
				 * using the first printer type is OK.
				 */
				ret = insfilter(
					pipes,
					prs->request->input_type,
					(output_type = *pl),
					*(pc->printer_types),
					pps->printer->name,
					parms,
					&(pc->flags)
				);
		if (ret != fl_none)
			pc->printer_type = Strdup(*(pc->printer_types));

	}

	/*
	 * If we were successful, check that the printer type
	 * we picked can handle the PRINTER'S cpi/lpi/etc. defaults.
	 * (We know that ALL the printer's types can handle the stuff
	 * the user gave or the stuff in the form.)
	 * Each printer's default that doesn't pass muster gets dropped.
	 * This may mean re-instantiating the filter(s) (if any).
	 */
	if (ret != fl_none && (p_cpi || p_lpi || p_pwid || p_plen)) {

#define	NZ(X)	((X)? *(X) : (char *)0)
		chk = chkprinter(
			pc->printer_type,
			NZ(p_cpi),
			NZ(p_lpi),
			NZ(p_plen),
			NZ(p_pwid),
			(char *)0
		);

		if (chk) {
			register char **	_pp;

			char *			hole	= "";


			/*
			 * Remove the offending printer defaults from the
			 * request list of cpi/lpi/etc. stuff, and punch
			 * (non-null!) holes in the parameter list.
			 */
#define DROP(P,R)	if (P) {P[-1] = P[0] = hole; R = 0;} else/*EMPTY*/
			if (chk & PCK_CPI)	DROP (p_cpi, prs->cpi);
			if (chk & PCK_LPI)	DROP (p_lpi, prs->lpi);
			if (chk & PCK_WIDTH)	DROP (p_pwid, prs->pwid);
			if (chk & PCK_LENGTH)	DROP (p_plen, prs->plen);

			/*
			 * If there are filters, we have to re-instantiate
			 * them. (Can't check "ret" here, because it may
			 * be misleading.)
			 */
			if (pipes[0] || pipes[1]) {

				/*
				 * First, close up the gaps we punched in
				 * the parameter list.
				 */
				for (pp = _pp = parms; *pp; pp++)
					if (*pp != hole)
						*_pp++ = *pp;
				*_pp = 0;

				/*
				 * Re-instantiate the filter(s). This
				 * CAN'T fail, because it is not mandatory
				 * that filters handle cpi/lpi/etc. stuff.
				 */
				ret = insfilter(
					pipes,
					prs->request->input_type,
					output_type,
					pc->printer_type,
					pps->printer->name,
					parms,
					&(pc->flags)
				);
			}
		}
	}

	/*
	 * Save the filters, if any. Note: although "ret" can be
	 * misleading, i.e. set to "fl_both" when there really aren't
	 * any filters, the declaration of "pipes" ensured they'd be
	 * zero if not set.
	 */
	if (ret == fl_both || ret == fl_slow)
		pc->slow = pipes[0];
	if (ret == fl_both || ret == fl_fast)
		pc->fast = pipes[1];

	if (ret != fl_none)
		pc->output_type = Strdup (output_type);

	/*
	 * Wait until now to allocate storage for the cpi/etc.
	 * stuff, to make life easier above.
	 */
	if (prs->cpi)	prs->cpi = Strdup(prs->cpi);
	if (prs->lpi)	prs->lpi = Strdup(prs->lpi);
	if (prs->plen)	prs->plen = Strdup(prs->plen);
	if (prs->pwid)	prs->pwid = Strdup(prs->pwid);


	if (parms)
		Free ((char *)parms);
	if (modes)
		freelist (modes);

	return ((ret != fl_none));
}