lpc.c revision 62294
11553Srgrimes/*
21553Srgrimes * Copyright (c) 1983, 1993
31553Srgrimes *	The Regents of the University of California.  All rights reserved.
41553Srgrimes *
51553Srgrimes *
61553Srgrimes * Redistribution and use in source and binary forms, with or without
71553Srgrimes * modification, are permitted provided that the following conditions
81553Srgrimes * are met:
91553Srgrimes * 1. Redistributions of source code must retain the above copyright
101553Srgrimes *    notice, this list of conditions and the following disclaimer.
111553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
121553Srgrimes *    notice, this list of conditions and the following disclaimer in the
131553Srgrimes *    documentation and/or other materials provided with the distribution.
141553Srgrimes * 3. All advertising materials mentioning features or use of this software
151553Srgrimes *    must display the following acknowledgement:
161553Srgrimes *	This product includes software developed by the University of
171553Srgrimes *	California, Berkeley and its contributors.
181553Srgrimes * 4. Neither the name of the University nor the names of its contributors
191553Srgrimes *    may be used to endorse or promote products derived from this software
201553Srgrimes *    without specific prior written permission.
211553Srgrimes *
221553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
231553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
241553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
251553Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
261553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
271553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
281553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
291553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
301553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
311553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
321553Srgrimes * SUCH DAMAGE.
331553Srgrimes */
341553Srgrimes
351553Srgrimes#ifndef lint
3629780Scharnierstatic const char copyright[] =
371553Srgrimes"@(#) Copyright (c) 1983, 1993\n\
381553Srgrimes	The Regents of the University of California.  All rights reserved.\n";
391553Srgrimes#endif /* not lint */
401553Srgrimes
411553Srgrimes#ifndef lint
4229780Scharnier#if 0
4315637Sjoergstatic char sccsid[] = "@(#)lpc.c	8.3 (Berkeley) 4/28/95";
4429780Scharnier#endif
4529780Scharnierstatic const char rcsid[] =
4650479Speter  "$FreeBSD: head/usr.sbin/lpr/lpc/lpc.c 62294 2000-06-30 20:05:21Z mph $";
471553Srgrimes#endif /* not lint */
481553Srgrimes
491553Srgrimes#include <sys/param.h>
501553Srgrimes
5129780Scharnier#include <ctype.h>
521553Srgrimes#include <dirent.h>
5331492Swollman#include <err.h>
5429780Scharnier#include <grp.h>
5529780Scharnier#include <setjmp.h>
561553Srgrimes#include <signal.h>
5729780Scharnier#include <stdio.h>
5829780Scharnier#include <stdlib.h>
591553Srgrimes#include <syslog.h>
6029780Scharnier#include <string.h>
611553Srgrimes#include <unistd.h>
6250039Smdodd#include <histedit.h>
6331492Swollman
641553Srgrimes#include "lp.h"
651553Srgrimes#include "lpc.h"
661553Srgrimes#include "extern.h"
671553Srgrimes
6815637Sjoerg#ifndef LPR_OPER
6915637Sjoerg#define LPR_OPER	"operator"	/* group name of lpr operators */
7015637Sjoerg#endif
7115637Sjoerg
721553Srgrimes/*
731553Srgrimes * lpc -- line printer control program
741553Srgrimes */
751553Srgrimes
7627618Simp#define MAX_CMDLINE	200
7727618Simp#define MAX_MARGV	20
7839084Swollmanstatic int	fromatty;
791553Srgrimes
8039084Swollmanstatic char	cmdline[MAX_CMDLINE];
8139084Swollmanstatic int	margc;
8239084Swollmanstatic char	*margv[MAX_MARGV];
8339084Swollmanuid_t		uid, euid;
841553Srgrimes
8539084Swollmanint			 main __P((int, char *[]));
8650039Smdoddstatic void		 cmdscanner __P((void));
871553Srgrimesstatic struct cmd	*getcmd __P((char *));
881553Srgrimesstatic void		 intr __P((int));
891553Srgrimesstatic void		 makeargv __P((void));
9015637Sjoergstatic int		 ingroup __P((char *));
911553Srgrimes
921553Srgrimesint
931553Srgrimesmain(argc, argv)
941553Srgrimes	int argc;
951553Srgrimes	char *argv[];
961553Srgrimes{
971553Srgrimes	register struct cmd *c;
981553Srgrimes
9927618Simp	euid = geteuid();
10027618Simp	uid = getuid();
10127618Simp	seteuid(uid);
1021553Srgrimes	name = argv[0];
1031553Srgrimes	openlog("lpd", 0, LOG_LPR);
1041553Srgrimes
1051553Srgrimes	if (--argc > 0) {
1061553Srgrimes		c = getcmd(*++argv);
1071553Srgrimes		if (c == (struct cmd *)-1) {
1081553Srgrimes			printf("?Ambiguous command\n");
1091553Srgrimes			exit(1);
1101553Srgrimes		}
1111553Srgrimes		if (c == 0) {
1121553Srgrimes			printf("?Invalid command\n");
1131553Srgrimes			exit(1);
1141553Srgrimes		}
11515637Sjoerg		if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) {
1161553Srgrimes			printf("?Privileged command\n");
1171553Srgrimes			exit(1);
1181553Srgrimes		}
11931492Swollman		if (c->c_generic != 0)
12031492Swollman			generic(c->c_generic, argc, argv);
12131492Swollman		else
12231492Swollman			(*c->c_handler)(argc, argv);
1231553Srgrimes		exit(0);
1241553Srgrimes	}
1251553Srgrimes	fromatty = isatty(fileno(stdin));
12650039Smdodd	if (!fromatty)
1271553Srgrimes		signal(SIGINT, intr);
1281553Srgrimes	for (;;) {
12950039Smdodd		cmdscanner();
1301553Srgrimes	}
1311553Srgrimes}
1321553Srgrimes
1331553Srgrimesstatic void
1341553Srgrimesintr(signo)
1351553Srgrimes	int signo;
1361553Srgrimes{
13750039Smdodd	exit(0);
1381553Srgrimes}
1391553Srgrimes
14050039Smdoddstatic char *
14150039Smdoddlpc_prompt()
14250039Smdodd{
14350039Smdodd	return("lpc> ");
14450039Smdodd}
14550039Smdodd
1461553Srgrimes/*
1471553Srgrimes * Command parser.
1481553Srgrimes */
1491553Srgrimesstatic void
15050039Smdoddcmdscanner()
1511553Srgrimes{
1521553Srgrimes	register struct cmd *c;
15350039Smdodd	static EditLine *el = NULL;
15450039Smdodd	static History *hist = NULL;
15550039Smdodd	int num = 0;
15650071Smdodd	int len;
15750039Smdodd	const char *bp = NULL;
1581553Srgrimes
1591553Srgrimes	for (;;) {
1601553Srgrimes		if (fromatty) {
16150039Smdodd			if (!el) {
16250039Smdodd				el = el_init("lpc", stdin, stdout);
16350039Smdodd				hist = history_init();
16450039Smdodd				history(hist, H_EVENT, 100);
16550039Smdodd				el_set(el, EL_HIST, history, hist);
16650039Smdodd				el_set(el, EL_EDITOR, "emacs");
16750039Smdodd				el_set(el, EL_PROMPT, lpc_prompt);
16850039Smdodd				el_set(el, EL_SIGNAL, 1);
16950042Smdodd				el_source(el, NULL);
17050039Smdodd			}
17150039Smdodd			if ((bp = el_gets(el, &num)) == NULL || num == 0)
17262294Smph				quit(0, NULL);
17350039Smdodd
17450077Smdodd			len = (num > MAX_CMDLINE) ? MAX_CMDLINE : num;
17550071Smdodd			memcpy(cmdline, bp, len);
17650071Smdodd			cmdline[len] = 0;
17750039Smdodd			history(hist, H_ENTER, bp);
17850039Smdodd
17950039Smdodd		} else {
18050039Smdodd			if (fgets(cmdline, MAX_CMDLINE, stdin) == 0)
18150039Smdodd				quit(0, NULL);
18250039Smdodd			if (cmdline[0] == 0 || cmdline[0] == '\n')
18350039Smdodd				break;
1841553Srgrimes		}
18550039Smdodd
1861553Srgrimes		makeargv();
18750039Smdodd		if (margc == 0)
18850039Smdodd			continue;
18950039Smdodd		if (el_parse(el, margc, margv) != -1)
19050039Smdodd			continue;
19150039Smdodd
1921553Srgrimes		c = getcmd(margv[0]);
1931553Srgrimes		if (c == (struct cmd *)-1) {
1941553Srgrimes			printf("?Ambiguous command\n");
1951553Srgrimes			continue;
1961553Srgrimes		}
1971553Srgrimes		if (c == 0) {
1981553Srgrimes			printf("?Invalid command\n");
1991553Srgrimes			continue;
2001553Srgrimes		}
20115637Sjoerg		if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) {
2021553Srgrimes			printf("?Privileged command\n");
2031553Srgrimes			continue;
2041553Srgrimes		}
20531492Swollman		if (c->c_generic != 0)
20631492Swollman			generic(c->c_generic, margc, margv);
20731492Swollman		else
20831492Swollman			(*c->c_handler)(margc, margv);
2091553Srgrimes	}
2101553Srgrimes}
2111553Srgrimes
21215637Sjoergstatic struct cmd *
2131553Srgrimesgetcmd(name)
2141553Srgrimes	register char *name;
2151553Srgrimes{
2161553Srgrimes	register char *p, *q;
2171553Srgrimes	register struct cmd *c, *found;
2181553Srgrimes	register int nmatches, longest;
2191553Srgrimes
2201553Srgrimes	longest = 0;
2211553Srgrimes	nmatches = 0;
2221553Srgrimes	found = 0;
22319202Simp	for (c = cmdtab; (p = c->c_name); c++) {
2241553Srgrimes		for (q = name; *q == *p++; q++)
2251553Srgrimes			if (*q == 0)		/* exact match? */
2261553Srgrimes				return(c);
2271553Srgrimes		if (!*q) {			/* the name was a prefix */
2281553Srgrimes			if (q - name > longest) {
2291553Srgrimes				longest = q - name;
2301553Srgrimes				nmatches = 1;
2311553Srgrimes				found = c;
2321553Srgrimes			} else if (q - name == longest)
2331553Srgrimes				nmatches++;
2341553Srgrimes		}
2351553Srgrimes	}
2361553Srgrimes	if (nmatches > 1)
2371553Srgrimes		return((struct cmd *)-1);
2381553Srgrimes	return(found);
2391553Srgrimes}
2401553Srgrimes
2411553Srgrimes/*
2421553Srgrimes * Slice a string up into argc/argv.
2431553Srgrimes */
2441553Srgrimesstatic void
2451553Srgrimesmakeargv()
2461553Srgrimes{
2471553Srgrimes	register char *cp;
2481553Srgrimes	register char **argp = margv;
24927618Simp	register int n = 0;
2501553Srgrimes
2511553Srgrimes	margc = 0;
25227618Simp	for (cp = cmdline; *cp && (cp - cmdline) < sizeof(cmdline) &&
25327618Simp	    n < MAX_MARGV; n++) {
2541553Srgrimes		while (isspace(*cp))
2551553Srgrimes			cp++;
2561553Srgrimes		if (*cp == '\0')
2571553Srgrimes			break;
2581553Srgrimes		*argp++ = cp;
2591553Srgrimes		margc += 1;
2601553Srgrimes		while (*cp != '\0' && !isspace(*cp))
2611553Srgrimes			cp++;
2621553Srgrimes		if (*cp == '\0')
2631553Srgrimes			break;
2641553Srgrimes		*cp++ = '\0';
2651553Srgrimes	}
2661553Srgrimes	*argp++ = 0;
2671553Srgrimes}
2681553Srgrimes
2691553Srgrimes#define HELPINDENT (sizeof ("directory"))
2701553Srgrimes
2711553Srgrimes/*
2721553Srgrimes * Help command.
2731553Srgrimes */
2741553Srgrimesvoid
2751553Srgrimeshelp(argc, argv)
2761553Srgrimes	int argc;
2771553Srgrimes	char *argv[];
2781553Srgrimes{
2791553Srgrimes	register struct cmd *c;
2801553Srgrimes
2811553Srgrimes	if (argc == 1) {
2821553Srgrimes		register int i, j, w;
2831553Srgrimes		int columns, width = 0, lines;
2841553Srgrimes
2851553Srgrimes		printf("Commands may be abbreviated.  Commands are:\n\n");
2861553Srgrimes		for (c = cmdtab; c->c_name; c++) {
2871553Srgrimes			int len = strlen(c->c_name);
2881553Srgrimes
2891553Srgrimes			if (len > width)
2901553Srgrimes				width = len;
2911553Srgrimes		}
2921553Srgrimes		width = (width + 8) &~ 7;
2931553Srgrimes		columns = 80 / width;
2941553Srgrimes		if (columns == 0)
2951553Srgrimes			columns = 1;
2961553Srgrimes		lines = (NCMDS + columns - 1) / columns;
2971553Srgrimes		for (i = 0; i < lines; i++) {
2981553Srgrimes			for (j = 0; j < columns; j++) {
2991553Srgrimes				c = cmdtab + j * lines + i;
3001553Srgrimes				if (c->c_name)
3011553Srgrimes					printf("%s", c->c_name);
3021553Srgrimes				if (c + lines >= &cmdtab[NCMDS]) {
3031553Srgrimes					printf("\n");
3041553Srgrimes					break;
3051553Srgrimes				}
3061553Srgrimes				w = strlen(c->c_name);
3071553Srgrimes				while (w < width) {
3081553Srgrimes					w = (w + 8) &~ 7;
3091553Srgrimes					putchar('\t');
3101553Srgrimes				}
3111553Srgrimes			}
3121553Srgrimes		}
3131553Srgrimes		return;
3141553Srgrimes	}
3151553Srgrimes	while (--argc > 0) {
3161553Srgrimes		register char *arg;
3171553Srgrimes		arg = *++argv;
3181553Srgrimes		c = getcmd(arg);
3191553Srgrimes		if (c == (struct cmd *)-1)
3201553Srgrimes			printf("?Ambiguous help command %s\n", arg);
3211553Srgrimes		else if (c == (struct cmd *)0)
3221553Srgrimes			printf("?Invalid help command %s\n", arg);
3231553Srgrimes		else
32434784Sjb			printf("%-*s\t%s\n", (int) HELPINDENT,
3251553Srgrimes				c->c_name, c->c_help);
3261553Srgrimes	}
3271553Srgrimes}
32815637Sjoerg
32915637Sjoerg/*
33015637Sjoerg * return non-zero if the user is a member of the given group
33115637Sjoerg */
33215637Sjoergstatic int
33315637Sjoergingroup(grname)
33415637Sjoerg	char *grname;
33515637Sjoerg{
33615637Sjoerg	static struct group *gptr=NULL;
33715637Sjoerg	static gid_t groups[NGROUPS];
33815637Sjoerg	register gid_t gid;
33915637Sjoerg	register int i;
34015637Sjoerg
34115637Sjoerg	if (gptr == NULL) {
34215637Sjoerg		if ((gptr = getgrnam(grname)) == NULL) {
34329780Scharnier			warnx("warning: unknown group '%s'", grname);
34415637Sjoerg			return(0);
34515637Sjoerg		}
34629780Scharnier		if (getgroups(NGROUPS, groups) < 0)
34729780Scharnier			err(1, "getgroups");
34815637Sjoerg	}
34915637Sjoerg	gid = gptr->gr_gid;
35015637Sjoerg	for (i = 0; i < NGROUPS; i++)
35115637Sjoerg		if (gid == groups[i])
35215637Sjoerg			return(1);
35315637Sjoerg	return(0);
35415637Sjoerg}
355