lpc.c revision 50039
1160383Snetchild/*
2160383Snetchild * Copyright (c) 1983, 1993
3172150Sariff *	The Regents of the University of California.  All rights reserved.
4160383Snetchild *
5160383Snetchild *
6160383Snetchild * Redistribution and use in source and binary forms, with or without
7160383Snetchild * modification, are permitted provided that the following conditions
8160383Snetchild * are met:
9160383Snetchild * 1. Redistributions of source code must retain the above copyright
10160383Snetchild *    notice, this list of conditions and the following disclaimer.
11160383Snetchild * 2. Redistributions in binary form must reproduce the above copyright
12160383Snetchild *    notice, this list of conditions and the following disclaimer in the
13160383Snetchild *    documentation and/or other materials provided with the distribution.
14160383Snetchild * 3. All advertising materials mentioning features or use of this software
15160383Snetchild *    must display the following acknowledgement:
16160383Snetchild *	This product includes software developed by the University of
17160383Snetchild *	California, Berkeley and its contributors.
18160383Snetchild * 4. Neither the name of the University nor the names of its contributors
19160383Snetchild *    may be used to endorse or promote products derived from this software
20160383Snetchild *    without specific prior written permission.
21160383Snetchild *
22160383Snetchild * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23160383Snetchild * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24160383Snetchild * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25160383Snetchild * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26160383Snetchild * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27160383Snetchild * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28160383Snetchild * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29160383Snetchild * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30160383Snetchild * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31160383Snetchild * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32160383Snetchild * SUCH DAMAGE.
33160383Snetchild */
34160383Snetchild
35160383Snetchild#ifndef lint
36160383Snetchildstatic const char copyright[] =
37160383Snetchild"@(#) Copyright (c) 1983, 1993\n\
38160383Snetchild	The Regents of the University of California.  All rights reserved.\n";
39160383Snetchild#endif /* not lint */
40160383Snetchild
41172150Sariff#ifndef lint
42160383Snetchild#if 0
43160383Snetchildstatic char sccsid[] = "@(#)lpc.c	8.3 (Berkeley) 4/28/95";
44160383Snetchild#endif
45160383Snetchildstatic const char rcsid[] =
46160383Snetchild	"$Id: lpc.c,v 1.8 1998/09/11 18:49:31 wollman Exp $";
47160383Snetchild#endif /* not lint */
48193640Sariff
49193640Sariff#include <sys/param.h>
50193640Sariff
51193640Sariff#include <ctype.h>
52160383Snetchild#include <dirent.h>
53160383Snetchild#include <err.h>
54160383Snetchild#include <grp.h>
55160383Snetchild#include <setjmp.h>
56229981Spfg#include <signal.h>
57160383Snetchild#include <stdio.h>
58160383Snetchild#include <stdlib.h>
59160383Snetchild#include <syslog.h>
60160383Snetchild#include <string.h>
61160383Snetchild#include <unistd.h>
62160383Snetchild#include <histedit.h>
63160383Snetchild
64160383Snetchild#include "lp.h"
65160383Snetchild#include "lpc.h"
66160383Snetchild#include "extern.h"
67160383Snetchild
68160383Snetchild#ifndef LPR_OPER
69160383Snetchild#define LPR_OPER	"operator"	/* group name of lpr operators */
70160383Snetchild#endif
71160383Snetchild
72160383Snetchild/*
73160383Snetchild * lpc -- line printer control program
74160383Snetchild */
75160383Snetchild
76160383Snetchild#define MAX_CMDLINE	200
77160383Snetchild#define MAX_MARGV	20
78160383Snetchildstatic int	fromatty;
79160383Snetchild
80160383Snetchildstatic char	cmdline[MAX_CMDLINE];
81160383Snetchildstatic int	margc;
82160383Snetchildstatic char	*margv[MAX_MARGV];
83160383Snetchilduid_t		uid, euid;
84160383Snetchild
85160383Snetchildint			 main __P((int, char *[]));
86160383Snetchildstatic void		 cmdscanner __P((void));
87160383Snetchildstatic struct cmd	*getcmd __P((char *));
88160383Snetchildstatic void		 intr __P((int));
89160383Snetchildstatic void		 makeargv __P((void));
90160383Snetchildstatic int		 ingroup __P((char *));
91160383Snetchild
92160383Snetchildint
93160383Snetchildmain(argc, argv)
94160383Snetchild	int argc;
95160383Snetchild	char *argv[];
96160383Snetchild{
97160383Snetchild	register struct cmd *c;
98160383Snetchild
99160383Snetchild	euid = geteuid();
100160383Snetchild	uid = getuid();
101160383Snetchild	seteuid(uid);
102160383Snetchild	name = argv[0];
103160383Snetchild	openlog("lpd", 0, LOG_LPR);
104160383Snetchild
105160383Snetchild	if (--argc > 0) {
106160383Snetchild		c = getcmd(*++argv);
107160383Snetchild		if (c == (struct cmd *)-1) {
108160383Snetchild			printf("?Ambiguous command\n");
109160383Snetchild			exit(1);
110160383Snetchild		}
111160383Snetchild		if (c == 0) {
112172150Sariff			printf("?Invalid command\n");
113172150Sariff			exit(1);
114172150Sariff		}
115160383Snetchild		if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) {
116160383Snetchild			printf("?Privileged command\n");
117160383Snetchild			exit(1);
118160383Snetchild		}
119160383Snetchild		if (c->c_generic != 0)
120160383Snetchild			generic(c->c_generic, argc, argv);
121160383Snetchild		else
122160383Snetchild			(*c->c_handler)(argc, argv);
123160383Snetchild		exit(0);
124160383Snetchild	}
125160383Snetchild	fromatty = isatty(fileno(stdin));
126160383Snetchild	if (!fromatty)
127160383Snetchild		signal(SIGINT, intr);
128160383Snetchild	for (;;) {
129160383Snetchild		cmdscanner();
130160383Snetchild	}
131160383Snetchild}
132160383Snetchild
133160383Snetchildstatic void
134160383Snetchildintr(signo)
135160383Snetchild	int signo;
136160383Snetchild{
137160383Snetchild	exit(0);
138160383Snetchild}
139160383Snetchild
140160383Snetchildstatic char *
141160383Snetchildlpc_prompt()
142160383Snetchild{
143160383Snetchild	return("lpc> ");
144160383Snetchild}
145160383Snetchild
146160383Snetchild/*
147160383Snetchild * Command parser.
148160383Snetchild */
149160383Snetchildstatic void
150160383Snetchildcmdscanner()
151160383Snetchild{
152160383Snetchild	register struct cmd *c;
153160383Snetchild	static EditLine *el = NULL;
154160383Snetchild	static History *hist = NULL;
155160383Snetchild	int num = 0;
156160383Snetchild	const char *bp = NULL;
157160383Snetchild
158160383Snetchild	for (;;) {
159160383Snetchild		if (fromatty) {
160165833Snetchild			if (!el) {
161230137Sjoel				el = el_init("lpc", stdin, stdout);
162160383Snetchild				hist = history_init();
163160383Snetchild				history(hist, H_EVENT, 100);
164160383Snetchild				el_set(el, EL_HIST, history, hist);
165160383Snetchild				el_set(el, EL_EDITOR, "emacs");
166160383Snetchild				el_set(el, EL_PROMPT, lpc_prompt);
167160383Snetchild				el_set(el, EL_SIGNAL, 1);
168160383Snetchild			}
169160383Snetchild			if ((bp = el_gets(el, &num)) == NULL || num == 0)
170160383Snetchild				return;
171160383Snetchild
172160383Snetchild			memcpy(cmdline, bp, (MAX_CMDLINE > num ? MAX_CMDLINE : num));
173160383Snetchild			cmdline[num] = 0;
174160383Snetchild			history(hist, H_ENTER, bp);
175160383Snetchild
176160383Snetchild		} else {
177160383Snetchild			if (fgets(cmdline, MAX_CMDLINE, stdin) == 0)
178160383Snetchild				quit(0, NULL);
179160383Snetchild			if (cmdline[0] == 0 || cmdline[0] == '\n')
180160383Snetchild				break;
181160383Snetchild		}
182160383Snetchild
183160383Snetchild		makeargv();
184160383Snetchild		if (margc == 0)
185229981Spfg			continue;
186160383Snetchild		if (el_parse(el, margc, margv) != -1)
187160383Snetchild			continue;
188160383Snetchild
189160383Snetchild		c = getcmd(margv[0]);
190160383Snetchild		if (c == (struct cmd *)-1) {
191160383Snetchild			printf("?Ambiguous command\n");
192160383Snetchild			continue;
193160383Snetchild		}
194160383Snetchild		if (c == 0) {
195160383Snetchild			printf("?Invalid command\n");
196160383Snetchild			continue;
197160383Snetchild		}
198160383Snetchild		if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) {
199160383Snetchild			printf("?Privileged command\n");
200160383Snetchild			continue;
201160383Snetchild		}
202160383Snetchild		if (c->c_generic != 0)
203160383Snetchild			generic(c->c_generic, margc, margv);
204160383Snetchild		else
205160383Snetchild			(*c->c_handler)(margc, margv);
206160383Snetchild	}
207160383Snetchild}
208160383Snetchild
209160383Snetchildstatic struct cmd *
210160383Snetchildgetcmd(name)
211160383Snetchild	register char *name;
212160383Snetchild{
213160383Snetchild	register char *p, *q;
214160383Snetchild	register struct cmd *c, *found;
215160383Snetchild	register int nmatches, longest;
216160383Snetchild
217160383Snetchild	longest = 0;
218160383Snetchild	nmatches = 0;
219160383Snetchild	found = 0;
220160383Snetchild	for (c = cmdtab; (p = c->c_name); c++) {
221229981Spfg		for (q = name; *q == *p++; q++)
222229981Spfg			if (*q == 0)		/* exact match? */
223229981Spfg				return(c);
224229981Spfg		if (!*q) {			/* the name was a prefix */
225229981Spfg			if (q - name > longest) {
226160383Snetchild				longest = q - name;
227229981Spfg				nmatches = 1;
228229981Spfg				found = c;
229229981Spfg			} else if (q - name == longest)
230229981Spfg				nmatches++;
231229981Spfg		}
232229981Spfg	}
233229981Spfg	if (nmatches > 1)
234229981Spfg		return((struct cmd *)-1);
235160383Snetchild	return(found);
236160383Snetchild}
237160383Snetchild
238160383Snetchild/*
239160383Snetchild * Slice a string up into argc/argv.
240160383Snetchild */
241160383Snetchildstatic void
242160383Snetchildmakeargv()
243160383Snetchild{
244160383Snetchild	register char *cp;
245160383Snetchild	register char **argp = margv;
246160383Snetchild	register int n = 0;
247172150Sariff
248172150Sariff	margc = 0;
249172150Sariff	for (cp = cmdline; *cp && (cp - cmdline) < sizeof(cmdline) &&
250165833Snetchild	    n < MAX_MARGV; n++) {
251160383Snetchild		while (isspace(*cp))
252160383Snetchild			cp++;
253160383Snetchild		if (*cp == '\0')
254160383Snetchild			break;
255160383Snetchild		*argp++ = cp;
256161055Snetchild		margc += 1;
257160383Snetchild		while (*cp != '\0' && !isspace(*cp))
258160383Snetchild			cp++;
259160383Snetchild		if (*cp == '\0')
260160383Snetchild			break;
261160383Snetchild		*cp++ = '\0';
262160383Snetchild	}
263160383Snetchild	*argp++ = 0;
264160383Snetchild}
265160383Snetchild
266172150Sariff#define HELPINDENT (sizeof ("directory"))
267172150Sariff
268160383Snetchild/*
269160383Snetchild * Help command.
270160383Snetchild */
271160383Snetchildvoid
272160383Snetchildhelp(argc, argv)
273160383Snetchild	int argc;
274160383Snetchild	char *argv[];
275160383Snetchild{
276160383Snetchild	register struct cmd *c;
277160383Snetchild
278160383Snetchild	if (argc == 1) {
279161054Snetchild		register int i, j, w;
280160383Snetchild		int columns, width = 0, lines;
281160383Snetchild
282160383Snetchild		printf("Commands may be abbreviated.  Commands are:\n\n");
283160383Snetchild		for (c = cmdtab; c->c_name; c++) {
284160383Snetchild			int len = strlen(c->c_name);
285172150Sariff
286160383Snetchild			if (len > width)
287160383Snetchild				width = len;
288160383Snetchild		}
289160383Snetchild		width = (width + 8) &~ 7;
290160383Snetchild		columns = 80 / width;
291160383Snetchild		if (columns == 0)
292160383Snetchild			columns = 1;
293160383Snetchild		lines = (NCMDS + columns - 1) / columns;
294160383Snetchild		for (i = 0; i < lines; i++) {
295160383Snetchild			for (j = 0; j < columns; j++) {
296160383Snetchild				c = cmdtab + j * lines + i;
297160383Snetchild				if (c->c_name)
298160383Snetchild					printf("%s", c->c_name);
299160383Snetchild				if (c + lines >= &cmdtab[NCMDS]) {
300160383Snetchild					printf("\n");
301160383Snetchild					break;
302160383Snetchild				}
303160383Snetchild				w = strlen(c->c_name);
304160383Snetchild				while (w < width) {
305160383Snetchild					w = (w + 8) &~ 7;
306160383Snetchild					putchar('\t');
307160383Snetchild				}
308160383Snetchild			}
309160383Snetchild		}
310160383Snetchild		return;
311160383Snetchild	}
312165833Snetchild	while (--argc > 0) {
313160383Snetchild		register char *arg;
314160383Snetchild		arg = *++argv;
315160383Snetchild		c = getcmd(arg);
316160383Snetchild		if (c == (struct cmd *)-1)
317160383Snetchild			printf("?Ambiguous help command %s\n", arg);
318160383Snetchild		else if (c == (struct cmd *)0)
319160383Snetchild			printf("?Invalid help command %s\n", arg);
320160383Snetchild		else
321160383Snetchild			printf("%-*s\t%s\n", (int) HELPINDENT,
322160383Snetchild				c->c_name, c->c_help);
323160383Snetchild	}
324160383Snetchild}
325160383Snetchild
326160383Snetchild/*
327160383Snetchild * return non-zero if the user is a member of the given group
328160383Snetchild */
329160383Snetchildstatic int
330160383Snetchildingroup(grname)
331160383Snetchild	char *grname;
332160383Snetchild{
333160383Snetchild	static struct group *gptr=NULL;
334160383Snetchild	static gid_t groups[NGROUPS];
335160383Snetchild	register gid_t gid;
336172150Sariff	register int i;
337160383Snetchild
338160383Snetchild	if (gptr == NULL) {
339160383Snetchild		if ((gptr = getgrnam(grname)) == NULL) {
340160383Snetchild			warnx("warning: unknown group '%s'", grname);
341160383Snetchild			return(0);
342160383Snetchild		}
343160383Snetchild		if (getgroups(NGROUPS, groups) < 0)
344160383Snetchild			err(1, "getgroups");
345160383Snetchild	}
346160383Snetchild	gid = gptr->gr_gid;
347160383Snetchild	for (i = 0; i < NGROUPS; i++)
348160383Snetchild		if (gid == groups[i])
349160383Snetchild			return(1);
350160383Snetchild	return(0);
351172150Sariff}
352160383Snetchild