xref: /openbsd-src/usr.sbin/lpr/lpc/lpc.c (revision c9899b11e3d79a7bf5a70dcb12f582cc0994240e)
1*c9899b11Skrw /*	$OpenBSD: lpc.c,v 1.20 2016/03/16 15:41:11 krw Exp $	*/
2a7643117Smillert /*	$NetBSD: lpc.c,v 1.11 2001/11/14 03:01:15 enami Exp $	*/
3ca5d3c4eSmillert 
4df930be7Sderaadt /*
5df930be7Sderaadt  * Copyright (c) 1983, 1993
6df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
7df930be7Sderaadt  *
8df930be7Sderaadt  *
9df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
10df930be7Sderaadt  * modification, are permitted provided that the following conditions
11df930be7Sderaadt  * are met:
12df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
13df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
14df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
15df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
16df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
1729295d1cSmillert  * 3. Neither the name of the University nor the names of its contributors
18df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
19df930be7Sderaadt  *    without specific prior written permission.
20df930be7Sderaadt  *
21df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31df930be7Sderaadt  * SUCH DAMAGE.
32df930be7Sderaadt  */
33df930be7Sderaadt 
34df930be7Sderaadt #include <dirent.h>
35df930be7Sderaadt #include <signal.h>
36df930be7Sderaadt #include <syslog.h>
37df930be7Sderaadt #include <unistd.h>
38df930be7Sderaadt #include <stdlib.h>
39df930be7Sderaadt #include <stdio.h>
40a7643117Smillert #include <err.h>
410122b1e5Sderaadt #include <errno.h>
42b9fc9a72Sderaadt #include <limits.h>
43df930be7Sderaadt #include <ctype.h>
44df930be7Sderaadt #include <string.h>
453b62b2c3Stholo #include <grp.h>
46a7643117Smillert 
47df930be7Sderaadt #include "lp.h"
48df930be7Sderaadt #include "lpc.h"
49df930be7Sderaadt #include "extern.h"
50df930be7Sderaadt 
513b62b2c3Stholo #ifndef LPR_OPER
523b62b2c3Stholo #define LPR_OPER	"operator"	/* group name of lpr operators */
533b62b2c3Stholo #endif
543b62b2c3Stholo 
55df930be7Sderaadt /*
56df930be7Sderaadt  * lpc -- line printer control program
57df930be7Sderaadt  */
58df930be7Sderaadt 
59df930be7Sderaadt #define MAX_CMDLINE	200
60df930be7Sderaadt #define MAX_MARGV	20
61df930be7Sderaadt int	fromatty;
62df930be7Sderaadt 
63df930be7Sderaadt char	cmdline[MAX_CMDLINE];
64df930be7Sderaadt int	margc;
65df930be7Sderaadt char	*margv[MAX_MARGV];
66df930be7Sderaadt 
67a7643117Smillert static void		 cmdscanner(void);
68a7643117Smillert static struct cmd	*getcmd(char *);
69a7643117Smillert static void		 intr(int);
70a7643117Smillert static void		 makeargv(void);
71a7643117Smillert static int		 ingroup(char *);
72df930be7Sderaadt 
73df930be7Sderaadt int
main(int argc,char ** argv)74a7643117Smillert main(int argc, char **argv)
75df930be7Sderaadt {
76c1624b2fSmillert 	struct cmd *c;
77df930be7Sderaadt 
786468ba68Smillert 	effective_uid = geteuid();
796468ba68Smillert 	real_uid = getuid();
806468ba68Smillert 	effective_gid = getegid();
816468ba68Smillert 	real_gid = getgid();
826468ba68Smillert 	PRIV_END;	/* be safe */
83df930be7Sderaadt 
846468ba68Smillert 	openlog("lpc", 0, LOG_LPR);
85df930be7Sderaadt 	if (--argc > 0) {
86df930be7Sderaadt 		c = getcmd(*++argv);
87df930be7Sderaadt 		if (c == (struct cmd *)-1) {
88df930be7Sderaadt 			printf("?Ambiguous command\n");
89df930be7Sderaadt 			exit(1);
90df930be7Sderaadt 		}
91df930be7Sderaadt 		if (c == 0) {
92df930be7Sderaadt 			printf("?Invalid command\n");
93df930be7Sderaadt 			exit(1);
94df930be7Sderaadt 		}
956468ba68Smillert 		if (c->c_priv && real_uid && ingroup(LPR_OPER) == 0) {
96df930be7Sderaadt 			printf("?Privileged command\n");
97df930be7Sderaadt 			exit(1);
98df930be7Sderaadt 		}
99df930be7Sderaadt 		(*c->c_handler)(argc, argv);
100df930be7Sderaadt 		exit(0);
101df930be7Sderaadt 	}
102df930be7Sderaadt 	fromatty = isatty(fileno(stdin));
103df930be7Sderaadt 	signal(SIGINT, intr);
1040122b1e5Sderaadt 	for (;;)
1050122b1e5Sderaadt 		cmdscanner();
106df930be7Sderaadt }
1070122b1e5Sderaadt 
1080122b1e5Sderaadt volatile sig_atomic_t gotintr;
109df930be7Sderaadt 
110a7643117Smillert static void
intr(int signo)111a7643117Smillert intr(int signo)
112df930be7Sderaadt {
113df930be7Sderaadt 	if (!fromatty)
1140122b1e5Sderaadt 		_exit(0);
1150122b1e5Sderaadt 	gotintr = 1;
116df930be7Sderaadt }
117df930be7Sderaadt 
118df930be7Sderaadt /*
119df930be7Sderaadt  * Command parser.
120df930be7Sderaadt  */
121a7643117Smillert static void
cmdscanner(void)1220122b1e5Sderaadt cmdscanner(void)
123df930be7Sderaadt {
124c1624b2fSmillert 	struct cmd *c;
125df930be7Sderaadt 
126df930be7Sderaadt 	for (;;) {
1270122b1e5Sderaadt 		if (gotintr) {
1280122b1e5Sderaadt 			putchar('\n');
1290122b1e5Sderaadt 			gotintr = 0;
1300122b1e5Sderaadt 		}
131df930be7Sderaadt 		if (fromatty) {
132df930be7Sderaadt 			printf("lpc> ");
133df930be7Sderaadt 			fflush(stdout);
134df930be7Sderaadt 		}
1350122b1e5Sderaadt 
1360122b1e5Sderaadt 		siginterrupt(SIGINT, 1);
1370122b1e5Sderaadt 		if (fgets(cmdline, MAX_CMDLINE, stdin) == NULL) {
1380122b1e5Sderaadt 			if (errno == EINTR && gotintr) {
1390122b1e5Sderaadt 				siginterrupt(SIGINT, 0);
1400122b1e5Sderaadt 				return;
1410122b1e5Sderaadt 			}
1420122b1e5Sderaadt 			siginterrupt(SIGINT, 0);
143df930be7Sderaadt 			quit(0, NULL);
1440122b1e5Sderaadt 		}
1450122b1e5Sderaadt 		siginterrupt(SIGINT, 0);
1460122b1e5Sderaadt 
147df930be7Sderaadt 		makeargv();
148f74fb86bSmillert 		if (margc == 0)
149f74fb86bSmillert 			break;
150df930be7Sderaadt 		c = getcmd(margv[0]);
151df930be7Sderaadt 		if (c == (struct cmd *)-1) {
152df930be7Sderaadt 			printf("?Ambiguous command\n");
153df930be7Sderaadt 			continue;
154df930be7Sderaadt 		}
155df930be7Sderaadt 		if (c == 0) {
156df930be7Sderaadt 			printf("?Invalid command\n");
157df930be7Sderaadt 			continue;
158df930be7Sderaadt 		}
1593b62b2c3Stholo 		if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) {
160df930be7Sderaadt 			printf("?Privileged command\n");
161df930be7Sderaadt 			continue;
162df930be7Sderaadt 		}
163df930be7Sderaadt 		(*c->c_handler)(margc, margv);
164df930be7Sderaadt 	}
165df930be7Sderaadt }
166df930be7Sderaadt 
167a7643117Smillert static struct cmd *
getcmd(char * name)168a7643117Smillert getcmd(char *name)
169df930be7Sderaadt {
170c1624b2fSmillert 	char *p, *q;
171c1624b2fSmillert 	struct cmd *c, *found;
172c1624b2fSmillert 	int nmatches, longest;
173df930be7Sderaadt 
174df930be7Sderaadt 	longest = 0;
175df930be7Sderaadt 	nmatches = 0;
176df930be7Sderaadt 	found = 0;
177a7643117Smillert 	for (c = cmdtab; (p = c->c_name) != NULL; c++) {
178df930be7Sderaadt 		for (q = name; *q == *p++; q++)
179df930be7Sderaadt 			if (*q == 0)		/* exact match? */
180df930be7Sderaadt 				return(c);
181df930be7Sderaadt 		if (!*q) {			/* the name was a prefix */
182df930be7Sderaadt 			if (q - name > longest) {
183df930be7Sderaadt 				longest = q - name;
184df930be7Sderaadt 				nmatches = 1;
185df930be7Sderaadt 				found = c;
186df930be7Sderaadt 			} else if (q - name == longest)
187df930be7Sderaadt 				nmatches++;
188df930be7Sderaadt 		}
189df930be7Sderaadt 	}
190df930be7Sderaadt 	if (nmatches > 1)
191df930be7Sderaadt 		return((struct cmd *)-1);
192df930be7Sderaadt 	return(found);
193df930be7Sderaadt }
194df930be7Sderaadt 
195df930be7Sderaadt /*
196df930be7Sderaadt  * Slice a string up into argc/argv.
197df930be7Sderaadt  */
198a7643117Smillert static void
makeargv(void)199a7643117Smillert makeargv(void)
200df930be7Sderaadt {
201f74fb86bSmillert 	char *cp = cmdline;
202f74fb86bSmillert 	char **ap = margv;
203df930be7Sderaadt 
204df930be7Sderaadt 	margc = 0;
205f74fb86bSmillert 	while (margc < MAX_MARGV - 1 && (*ap = strsep(&cp, " \t\n")) != NULL) {
206f74fb86bSmillert 		if (**ap != '\0') {
207f74fb86bSmillert 			ap++;
208f74fb86bSmillert 			margc++;
209df930be7Sderaadt 		}
210f74fb86bSmillert 	}
211f74fb86bSmillert 	*ap = NULL;
212df930be7Sderaadt }
213df930be7Sderaadt 
214a7643117Smillert #define HELPINDENT ((int)sizeof("directory"))
215df930be7Sderaadt 
216df930be7Sderaadt /*
217df930be7Sderaadt  * Help command.
218df930be7Sderaadt  */
219df930be7Sderaadt void
help(int argc,char ** argv)220a7643117Smillert help(int argc, char **argv)
221df930be7Sderaadt {
222c1624b2fSmillert 	struct cmd *c;
223df930be7Sderaadt 
224df930be7Sderaadt 	if (argc == 1) {
225c1624b2fSmillert 		int i, j, w;
226df930be7Sderaadt 		int columns, width = 0, lines;
227df930be7Sderaadt 
228df930be7Sderaadt 		printf("Commands may be abbreviated.  Commands are:\n\n");
229df930be7Sderaadt 		for (c = cmdtab; c->c_name; c++) {
230df930be7Sderaadt 			int len = strlen(c->c_name);
231df930be7Sderaadt 
232df930be7Sderaadt 			if (len > width)
233df930be7Sderaadt 				width = len;
234df930be7Sderaadt 		}
235df930be7Sderaadt 		width = (width + 8) &~ 7;
236df930be7Sderaadt 		columns = 80 / width;
237df930be7Sderaadt 		if (columns == 0)
238df930be7Sderaadt 			columns = 1;
239df930be7Sderaadt 		lines = (NCMDS + columns - 1) / columns;
240df930be7Sderaadt 		for (i = 0; i < lines; i++) {
241df930be7Sderaadt 			for (j = 0; j < columns; j++) {
242df930be7Sderaadt 				c = cmdtab + j * lines + i;
243df930be7Sderaadt 				if (c->c_name)
244df930be7Sderaadt 					printf("%s", c->c_name);
245df930be7Sderaadt 				if (c + lines >= &cmdtab[NCMDS]) {
246df930be7Sderaadt 					printf("\n");
247df930be7Sderaadt 					break;
248df930be7Sderaadt 				}
249df930be7Sderaadt 				w = strlen(c->c_name);
250df930be7Sderaadt 				while (w < width) {
251df930be7Sderaadt 					w = (w + 8) &~ 7;
252df930be7Sderaadt 					putchar('\t');
253df930be7Sderaadt 				}
254df930be7Sderaadt 			}
255df930be7Sderaadt 		}
256df930be7Sderaadt 		return;
257df930be7Sderaadt 	}
258df930be7Sderaadt 	while (--argc > 0) {
259c1624b2fSmillert 		char *arg;
26017ad289bSderaadt 
261df930be7Sderaadt 		arg = *++argv;
262df930be7Sderaadt 		c = getcmd(arg);
263df930be7Sderaadt 		if (c == (struct cmd *)-1)
264df930be7Sderaadt 			printf("?Ambiguous help command %s\n", arg);
265*c9899b11Skrw 		else if (c == NULL)
266df930be7Sderaadt 			printf("?Invalid help command %s\n", arg);
267df930be7Sderaadt 		else
268df930be7Sderaadt 			printf("%-*s\t%s\n", HELPINDENT,
269df930be7Sderaadt 				c->c_name, c->c_help);
270df930be7Sderaadt 	}
271df930be7Sderaadt }
2723b62b2c3Stholo 
2733b62b2c3Stholo /*
2743b62b2c3Stholo  * return non-zero if the user is a member of the given group
2753b62b2c3Stholo  */
276a7643117Smillert static int
ingroup(char * grname)277a7643117Smillert ingroup(char *grname)
2783b62b2c3Stholo {
2793b62b2c3Stholo 	static struct group *gptr = NULL;
280b9fc9a72Sderaadt 	static gid_t groups[NGROUPS_MAX];
281a7643117Smillert 	static int ngroups;
282a7643117Smillert 	gid_t gid;
283a7643117Smillert 	int i;
2843b62b2c3Stholo 
2853b62b2c3Stholo 	if (gptr == NULL) {
2863b62b2c3Stholo 		if ((gptr = getgrnam(grname)) == NULL) {
287a7643117Smillert 			warnx("Warning: unknown group `%s'", grname);
2883b62b2c3Stholo 			return(0);
2893b62b2c3Stholo 		}
290b9fc9a72Sderaadt 		if ((ngroups = getgroups(NGROUPS_MAX, groups)) < 0)
291a7643117Smillert 			err(1, "getgroups");
2923b62b2c3Stholo 	}
2933b62b2c3Stholo 	gid = gptr->gr_gid;
294a7643117Smillert 	for (i = 0; i < ngroups; i++)
2953b62b2c3Stholo 		if (gid == groups[i])
2963b62b2c3Stholo 			return(1);
2973b62b2c3Stholo 	return(0);
2983b62b2c3Stholo }
299