lpc.c revision 31492
1/*
2 * Copyright (c) 1983, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 *    must display the following acknowledgement:
16 *	This product includes software developed by the University of
17 *	California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#ifndef lint
36static const char copyright[] =
37"@(#) Copyright (c) 1983, 1993\n\
38	The Regents of the University of California.  All rights reserved.\n";
39#endif /* not lint */
40
41#ifndef lint
42#if 0
43static char sccsid[] = "@(#)lpc.c	8.3 (Berkeley) 4/28/95";
44#endif
45static const char rcsid[] =
46	"$Id: lpc.c,v 1.5 1997/09/24 06:47:46 charnier Exp $";
47#endif /* not lint */
48
49#include <sys/param.h>
50
51#include <ctype.h>
52#include <dirent.h>
53#include <err.h>
54#include <grp.h>
55#include <setjmp.h>
56#include <signal.h>
57#include <stdio.h>
58#include <stdlib.h>
59#include <syslog.h>
60#include <string.h>
61#include <unistd.h>
62
63#include "lp.h"
64#include "lpc.h"
65#include "extern.h"
66
67#ifndef LPR_OPER
68#define LPR_OPER	"operator"	/* group name of lpr operators */
69#endif
70
71/*
72 * lpc -- line printer control program
73 */
74
75#define MAX_CMDLINE	200
76#define MAX_MARGV	20
77int	fromatty;
78
79char	cmdline[MAX_CMDLINE];
80int	margc;
81char	*margv[MAX_MARGV];
82int	top;
83uid_t	uid, euid;
84
85jmp_buf	toplevel;
86
87static void		 cmdscanner __P((int));
88static struct cmd	*getcmd __P((char *));
89static void		 intr __P((int));
90static void		 makeargv __P((void));
91static int		 ingroup __P((char *));
92
93int
94main(argc, argv)
95	int argc;
96	char *argv[];
97{
98	register struct cmd *c;
99
100	euid = geteuid();
101	uid = getuid();
102	seteuid(uid);
103	name = argv[0];
104	openlog("lpd", 0, LOG_LPR);
105
106	if (--argc > 0) {
107		c = getcmd(*++argv);
108		if (c == (struct cmd *)-1) {
109			printf("?Ambiguous command\n");
110			exit(1);
111		}
112		if (c == 0) {
113			printf("?Invalid command\n");
114			exit(1);
115		}
116		if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) {
117			printf("?Privileged command\n");
118			exit(1);
119		}
120		if (c->c_generic != 0)
121			generic(c->c_generic, argc, argv);
122		else
123			(*c->c_handler)(argc, argv);
124		exit(0);
125	}
126	fromatty = isatty(fileno(stdin));
127	top = setjmp(toplevel) == 0;
128	if (top)
129		signal(SIGINT, intr);
130	for (;;) {
131		cmdscanner(top);
132		top = 1;
133	}
134}
135
136static void
137intr(signo)
138	int signo;
139{
140	if (!fromatty)
141		exit(0);
142	longjmp(toplevel, 1);
143}
144
145/*
146 * Command parser.
147 */
148static void
149cmdscanner(top)
150	int top;
151{
152	register struct cmd *c;
153
154	if (!top)
155		putchar('\n');
156	for (;;) {
157		if (fromatty) {
158			printf("lpc> ");
159			fflush(stdout);
160		}
161		if (fgets(cmdline, MAX_CMDLINE, stdin) == 0)
162			quit(0, NULL);
163		if (cmdline[0] == 0 || cmdline[0] == '\n')
164			break;
165		makeargv();
166		c = getcmd(margv[0]);
167		if (c == (struct cmd *)-1) {
168			printf("?Ambiguous command\n");
169			continue;
170		}
171		if (c == 0) {
172			printf("?Invalid command\n");
173			continue;
174		}
175		if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) {
176			printf("?Privileged command\n");
177			continue;
178		}
179		if (c->c_generic != 0)
180			generic(c->c_generic, margc, margv);
181		else
182			(*c->c_handler)(margc, margv);
183	}
184	longjmp(toplevel, 0);
185}
186
187static struct cmd *
188getcmd(name)
189	register char *name;
190{
191	register char *p, *q;
192	register struct cmd *c, *found;
193	register int nmatches, longest;
194
195	longest = 0;
196	nmatches = 0;
197	found = 0;
198	for (c = cmdtab; (p = c->c_name); c++) {
199		for (q = name; *q == *p++; q++)
200			if (*q == 0)		/* exact match? */
201				return(c);
202		if (!*q) {			/* the name was a prefix */
203			if (q - name > longest) {
204				longest = q - name;
205				nmatches = 1;
206				found = c;
207			} else if (q - name == longest)
208				nmatches++;
209		}
210	}
211	if (nmatches > 1)
212		return((struct cmd *)-1);
213	return(found);
214}
215
216/*
217 * Slice a string up into argc/argv.
218 */
219static void
220makeargv()
221{
222	register char *cp;
223	register char **argp = margv;
224	register int n = 0;
225
226	margc = 0;
227	for (cp = cmdline; *cp && (cp - cmdline) < sizeof(cmdline) &&
228	    n < MAX_MARGV; n++) {
229		while (isspace(*cp))
230			cp++;
231		if (*cp == '\0')
232			break;
233		*argp++ = cp;
234		margc += 1;
235		while (*cp != '\0' && !isspace(*cp))
236			cp++;
237		if (*cp == '\0')
238			break;
239		*cp++ = '\0';
240	}
241	*argp++ = 0;
242}
243
244#define HELPINDENT (sizeof ("directory"))
245
246/*
247 * Help command.
248 */
249void
250help(argc, argv)
251	int argc;
252	char *argv[];
253{
254	register struct cmd *c;
255
256	if (argc == 1) {
257		register int i, j, w;
258		int columns, width = 0, lines;
259
260		printf("Commands may be abbreviated.  Commands are:\n\n");
261		for (c = cmdtab; c->c_name; c++) {
262			int len = strlen(c->c_name);
263
264			if (len > width)
265				width = len;
266		}
267		width = (width + 8) &~ 7;
268		columns = 80 / width;
269		if (columns == 0)
270			columns = 1;
271		lines = (NCMDS + columns - 1) / columns;
272		for (i = 0; i < lines; i++) {
273			for (j = 0; j < columns; j++) {
274				c = cmdtab + j * lines + i;
275				if (c->c_name)
276					printf("%s", c->c_name);
277				if (c + lines >= &cmdtab[NCMDS]) {
278					printf("\n");
279					break;
280				}
281				w = strlen(c->c_name);
282				while (w < width) {
283					w = (w + 8) &~ 7;
284					putchar('\t');
285				}
286			}
287		}
288		return;
289	}
290	while (--argc > 0) {
291		register char *arg;
292		arg = *++argv;
293		c = getcmd(arg);
294		if (c == (struct cmd *)-1)
295			printf("?Ambiguous help command %s\n", arg);
296		else if (c == (struct cmd *)0)
297			printf("?Invalid help command %s\n", arg);
298		else
299			printf("%-*s\t%s\n", HELPINDENT,
300				c->c_name, c->c_help);
301	}
302}
303
304/*
305 * return non-zero if the user is a member of the given group
306 */
307static int
308ingroup(grname)
309	char *grname;
310{
311	static struct group *gptr=NULL;
312	static gid_t groups[NGROUPS];
313	register gid_t gid;
314	register int i;
315
316	if (gptr == NULL) {
317		if ((gptr = getgrnam(grname)) == NULL) {
318			warnx("warning: unknown group '%s'", grname);
319			return(0);
320		}
321		if (getgroups(NGROUPS, groups) < 0)
322			err(1, "getgroups");
323	}
324	gid = gptr->gr_gid;
325	for (i = 0; i < NGROUPS; i++)
326		if (gid == groups[i])
327			return(1);
328	return(0);
329}
330