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