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