lpc.c revision 1.9 1 /* $NetBSD: lpc.c,v 1.9 1997/10/05 16:45:44 mrg Exp $ */
2
3 /*
4 * Copyright (c) 1983, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #include <sys/cdefs.h>
38 #ifndef lint
39 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
40 The Regents of the University of California. All rights reserved.\n");
41 #if 0
42 static char sccsid[] = "@(#)lpc.c 8.3 (Berkeley) 4/28/95";
43 #else
44 __RCSID("$NetBSD: lpc.c,v 1.9 1997/10/05 16:45:44 mrg Exp $");
45 #endif
46 #endif /* not lint */
47
48 #include <sys/param.h>
49
50 #include <dirent.h>
51 #include <signal.h>
52 #include <setjmp.h>
53 #include <syslog.h>
54 #include <unistd.h>
55 #include <stdlib.h>
56 #include <stdio.h>
57 #include <ctype.h>
58 #include <string.h>
59 #include <grp.h>
60 #include <err.h>
61 #include "lp.h"
62 #include "lpc.h"
63 #include "extern.h"
64
65 #ifndef LPR_OPER
66 #define LPR_OPER "operator" /* group name of lpr operators */
67 #endif
68
69 /*
70 * lpc -- line printer control program
71 */
72
73 #define MAX_CMDLINE 200
74 #define MAX_MARGV 20
75 int fromatty;
76
77 char cmdline[MAX_CMDLINE];
78 int margc;
79 char *margv[MAX_MARGV];
80 int top;
81 uid_t uid, euid;
82
83 jmp_buf toplevel;
84
85 static void cmdscanner __P((int));
86 static struct cmd *getcmd __P((char *));
87 static void intr __P((int));
88 static void makeargv __P((void));
89 static int ingroup __P((char *));
90 int main __P((int, char *p[]));
91
92 int
93 main(argc, argv)
94 int argc;
95 char *argv[];
96 {
97 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
132 static void
133 intr(signo)
134 int signo;
135 {
136 if (!fromatty)
137 exit(0);
138 longjmp(toplevel, 1);
139 }
140
141 /*
142 * Command parser.
143 */
144 static void
145 cmdscanner(top)
146 int top;
147 {
148 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
180 static struct cmd *
181 getcmd(name)
182 char *name;
183 {
184 char *p, *q;
185 struct cmd *c, *found;
186 int nmatches, longest;
187
188 longest = 0;
189 nmatches = 0;
190 found = 0;
191 for (c = cmdtab; (p = c->c_name) != NULL; 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 */
212 static void
213 makeargv()
214 {
215 char *cp;
216 char **argp = margv;
217 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 */
242 void
243 help(argc, argv)
244 int argc;
245 char *argv[];
246 {
247 struct cmd *c;
248
249 if (argc == 1) {
250 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 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", (int)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 */
300 static int
301 ingroup(grname)
302 char *grname;
303 {
304 static struct group *gptr=NULL;
305 static gid_t groups[NGROUPS];
306 gid_t gid;
307 int i;
308
309 if (gptr == NULL) {
310 if ((gptr = getgrnam(grname)) == NULL) {
311 warnx("Warning: unknown group `%s'\n",
312 grname);
313 return(0);
314 }
315 if (getgroups(NGROUPS, groups) < 0)
316 err(1, "getgroups");
317 }
318 gid = gptr->gr_gid;
319 for (i = 0; i < NGROUPS; i++)
320 if (gid == groups[i])
321 return(1);
322 return(0);
323 }
324