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