lpc.c revision 15703
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 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
42static char sccsid[] = "@(#)lpc.c	8.3 (Berkeley) 4/28/95";
43#endif /* not lint */
44
45#include <sys/param.h>
46
47#include <dirent.h>
48#include <signal.h>
49#include <setjmp.h>
50#include <syslog.h>
51#include <unistd.h>
52#include <stdlib.h>
53#include <stdio.h>
54#include <ctype.h>
55#include <string.h>
56#include <grp.h>
57#include <sys/param.h>
58#include "lp.h"
59#include "lpc.h"
60#include "extern.h"
61
62#ifndef LPR_OPER
63#define LPR_OPER	"operator"	/* group name of lpr operators */
64#endif
65
66/*
67 * lpc -- line printer control program
68 */
69
70int	fromatty;
71
72char	cmdline[200];
73int	margc;
74char	*margv[20];
75int	top;
76
77jmp_buf	toplevel;
78
79static void		 cmdscanner __P((int));
80static struct cmd	*getcmd __P((char *));
81static void		 intr __P((int));
82static void		 makeargv __P((void));
83static int		 ingroup __P((char *));
84
85int
86main(argc, argv)
87	int argc;
88	char *argv[];
89{
90	register struct cmd *c;
91
92	name = argv[0];
93	openlog("lpd", 0, LOG_LPR);
94
95	if (--argc > 0) {
96		c = getcmd(*++argv);
97		if (c == (struct cmd *)-1) {
98			printf("?Ambiguous command\n");
99			exit(1);
100		}
101		if (c == 0) {
102			printf("?Invalid command\n");
103			exit(1);
104		}
105		if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) {
106			printf("?Privileged command\n");
107			exit(1);
108		}
109		(*c->c_handler)(argc, argv);
110		exit(0);
111	}
112	fromatty = isatty(fileno(stdin));
113	top = setjmp(toplevel) == 0;
114	if (top)
115		signal(SIGINT, intr);
116	for (;;) {
117		cmdscanner(top);
118		top = 1;
119	}
120}
121
122static void
123intr(signo)
124	int signo;
125{
126	if (!fromatty)
127		exit(0);
128	longjmp(toplevel, 1);
129}
130
131/*
132 * Command parser.
133 */
134static void
135cmdscanner(top)
136	int top;
137{
138	register struct cmd *c;
139
140	if (!top)
141		putchar('\n');
142	for (;;) {
143		if (fromatty) {
144			printf("lpc> ");
145			fflush(stdout);
146		}
147		if (fgets(cmdline, sizeof(cmdline), stdin) == 0)
148			quit(0, NULL);
149		if (cmdline[0] == 0 || cmdline[0] == '\n')
150			break;
151		makeargv();
152		c = getcmd(margv[0]);
153		if (c == (struct cmd *)-1) {
154			printf("?Ambiguous command\n");
155			continue;
156		}
157		if (c == 0) {
158			printf("?Invalid command\n");
159			continue;
160		}
161		if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) {
162			printf("?Privileged command\n");
163			continue;
164		}
165		(*c->c_handler)(margc, margv);
166	}
167	longjmp(toplevel, 0);
168}
169
170static struct cmd *
171getcmd(name)
172	register char *name;
173{
174	register char *p, *q;
175	register struct cmd *c, *found;
176	register int nmatches, longest;
177
178	longest = 0;
179	nmatches = 0;
180	found = 0;
181	for (c = cmdtab; p = c->c_name; c++) {
182		for (q = name; *q == *p++; q++)
183			if (*q == 0)		/* exact match? */
184				return(c);
185		if (!*q) {			/* the name was a prefix */
186			if (q - name > longest) {
187				longest = q - name;
188				nmatches = 1;
189				found = c;
190			} else if (q - name == longest)
191				nmatches++;
192		}
193	}
194	if (nmatches > 1)
195		return((struct cmd *)-1);
196	return(found);
197}
198
199/*
200 * Slice a string up into argc/argv.
201 */
202static void
203makeargv()
204{
205	register char *cp;
206	register char **argp = margv;
207
208	margc = 0;
209	for (cp = cmdline; *cp;) {
210		while (isspace(*cp))
211			cp++;
212		if (*cp == '\0')
213			break;
214		*argp++ = cp;
215		margc += 1;
216		while (*cp != '\0' && !isspace(*cp))
217			cp++;
218		if (*cp == '\0')
219			break;
220		*cp++ = '\0';
221	}
222	*argp++ = 0;
223}
224
225#define HELPINDENT (sizeof ("directory"))
226
227/*
228 * Help command.
229 */
230void
231help(argc, argv)
232	int argc;
233	char *argv[];
234{
235	register struct cmd *c;
236
237	if (argc == 1) {
238		register int i, j, w;
239		int columns, width = 0, lines;
240
241		printf("Commands may be abbreviated.  Commands are:\n\n");
242		for (c = cmdtab; c->c_name; c++) {
243			int len = strlen(c->c_name);
244
245			if (len > width)
246				width = len;
247		}
248		width = (width + 8) &~ 7;
249		columns = 80 / width;
250		if (columns == 0)
251			columns = 1;
252		lines = (NCMDS + columns - 1) / columns;
253		for (i = 0; i < lines; i++) {
254			for (j = 0; j < columns; j++) {
255				c = cmdtab + j * lines + i;
256				if (c->c_name)
257					printf("%s", c->c_name);
258				if (c + lines >= &cmdtab[NCMDS]) {
259					printf("\n");
260					break;
261				}
262				w = strlen(c->c_name);
263				while (w < width) {
264					w = (w + 8) &~ 7;
265					putchar('\t');
266				}
267			}
268		}
269		return;
270	}
271	while (--argc > 0) {
272		register char *arg;
273		arg = *++argv;
274		c = getcmd(arg);
275		if (c == (struct cmd *)-1)
276			printf("?Ambiguous help command %s\n", arg);
277		else if (c == (struct cmd *)0)
278			printf("?Invalid help command %s\n", arg);
279		else
280			printf("%-*s\t%s\n", HELPINDENT,
281				c->c_name, c->c_help);
282	}
283}
284
285/*
286 * return non-zero if the user is a member of the given group
287 */
288static int
289ingroup(grname)
290	char *grname;
291{
292	static struct group *gptr=NULL;
293	static gid_t groups[NGROUPS];
294	register gid_t gid;
295	register int i;
296
297	if (gptr == NULL) {
298		if ((gptr = getgrnam(grname)) == NULL) {
299			fprintf(stderr, "Warning: unknown group '%s'\n",
300				grname);
301			return(0);
302		}
303		if (getgroups(NGROUPS, groups) < 0) {
304			perror("getgroups");
305			exit(1);
306		}
307	}
308	gid = gptr->gr_gid;
309	for (i = 0; i < NGROUPS; i++)
310		if (gid == groups[i])
311			return(1);
312	return(0);
313}
314