lpc.c revision 1.16 1 /* $NetBSD: lpc.c,v 1.16 2004/10/30 08:44:26 dsl 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. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #include <sys/cdefs.h>
34 #ifndef lint
35 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
36 The Regents of the University of California. All rights reserved.\n");
37 #if 0
38 static char sccsid[] = "@(#)lpc.c 8.3 (Berkeley) 4/28/95";
39 #else
40 __RCSID("$NetBSD: lpc.c,v 1.16 2004/10/30 08:44:26 dsl Exp $");
41 #endif
42 #endif /* not lint */
43
44 #include <sys/param.h>
45
46 #include <dirent.h>
47 #include <signal.h>
48 #include <setjmp.h>
49 #include <syslog.h>
50 #include <unistd.h>
51 #include <stdlib.h>
52 #include <stdio.h>
53 #include <ctype.h>
54 #include <string.h>
55 #include <grp.h>
56 #include <err.h>
57 #include "lp.h"
58 #include "lpc.h"
59 #include "extern.h"
60
61 #ifndef LPR_OPER
62 #define LPR_OPER "operator" /* group name of lpr operators */
63 #endif
64
65 /*
66 * lpc -- line printer control program
67 */
68
69 #define MAX_CMDLINE 200
70 #define MAX_MARGV 20
71 int fromatty;
72
73 char cmdline[MAX_CMDLINE];
74 int margc;
75 char *margv[MAX_MARGV];
76 int top;
77 uid_t uid, euid;
78
79 jmp_buf toplevel;
80
81 static void cmdscanner(int);
82 static struct cmd *getcmd(char *);
83 static void intr(int);
84 static void makeargv(void);
85 static int ingroup(char *);
86 int main(int, char *p[]);
87
88 int
89 main(int argc, char *argv[])
90 {
91 struct cmd *c;
92
93 euid = geteuid();
94 uid = getuid();
95 seteuid(uid);
96 name = argv[0];
97 openlog("lpd", 0, LOG_LPR);
98
99 if (--argc > 0) {
100 c = getcmd(*++argv);
101 if (c == (struct cmd *)-1) {
102 printf("?Ambiguous command\n");
103 exit(1);
104 }
105 if (c == 0) {
106 printf("?Invalid command\n");
107 exit(1);
108 }
109 if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) {
110 printf("?Privileged command\n");
111 exit(1);
112 }
113 (*c->c_handler)(argc, argv);
114 exit(0);
115 }
116 fromatty = isatty(fileno(stdin));
117 top = setjmp(toplevel) == 0;
118 if (top)
119 signal(SIGINT, intr);
120 for (;;) {
121 cmdscanner(top);
122 top = 1;
123 }
124 }
125
126 static void
127 intr(int signo)
128 {
129 if (!fromatty)
130 exit(0);
131 longjmp(toplevel, 1);
132 }
133
134 /*
135 * Command parser.
136 */
137 static void
138 cmdscanner(int top)
139 {
140 struct cmd *c;
141
142 if (!top)
143 putchar('\n');
144 for (;;) {
145 if (fromatty) {
146 printf("lpc> ");
147 fflush(stdout);
148 }
149 if (fgets(cmdline, MAX_CMDLINE, stdin) == 0)
150 quit(0, NULL);
151 makeargv();
152 if (margc == 0)
153 break;
154 c = getcmd(margv[0]);
155 if (c == (struct cmd *)-1) {
156 printf("?Ambiguous command\n");
157 continue;
158 }
159 if (c == 0) {
160 printf("?Invalid command\n");
161 continue;
162 }
163 if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) {
164 printf("?Privileged command\n");
165 continue;
166 }
167 (*c->c_handler)(margc, margv);
168 }
169 longjmp(toplevel, 0);
170 }
171
172 static struct cmd *
173 getcmd(char *name)
174 {
175 char *p, *q;
176 struct cmd *c, *found;
177 int nmatches, longest;
178
179 longest = 0;
180 nmatches = 0;
181 found = 0;
182 for (c = cmdtab; (p = c->c_name) != NULL; c++) {
183 for (q = name; *q == *p++; q++)
184 if (*q == 0) /* exact match? */
185 return(c);
186 if (!*q) { /* the name was a prefix */
187 if (q - name > longest) {
188 longest = q - name;
189 nmatches = 1;
190 found = c;
191 } else if (q - name == longest)
192 nmatches++;
193 }
194 }
195 if (nmatches > 1)
196 return((struct cmd *)-1);
197 return(found);
198 }
199
200 /*
201 * Slice a string up into argc/argv.
202 */
203 static void
204 makeargv(void)
205 {
206 char *cp;
207 char **argp = margv;
208 int n = 0;
209
210 margc = 0;
211 for (cp = cmdline; *cp && (cp - cmdline) < sizeof(cmdline) &&
212 n < MAX_MARGV; n++) {
213 while (isspace((unsigned char)*cp))
214 cp++;
215 if (*cp == '\0')
216 break;
217 *argp++ = cp;
218 margc += 1;
219 while (*cp != '\0' && !isspace((unsigned char)*cp))
220 cp++;
221 if (*cp == '\0')
222 break;
223 *cp++ = '\0';
224 }
225 *argp++ = 0;
226 }
227
228 #define HELPINDENT (sizeof ("directory"))
229
230 /*
231 * Help command.
232 */
233 void
234 help(int argc, char *argv[])
235 {
236 struct cmd *c;
237
238 if (argc == 1) {
239 int i, j, w;
240 int columns, width = 0, lines;
241
242 printf("Commands may be abbreviated. Commands are:\n\n");
243 for (c = cmdtab; c->c_name; c++) {
244 int len = strlen(c->c_name);
245
246 if (len > width)
247 width = len;
248 }
249 width = (width + 8) &~ 7;
250 columns = 80 / width;
251 if (columns == 0)
252 columns = 1;
253 lines = (NCMDS + columns - 1) / columns;
254 for (i = 0; i < lines; i++) {
255 for (j = 0; j < columns; j++) {
256 c = cmdtab + j * lines + i;
257 if (c->c_name)
258 printf("%s", c->c_name);
259 if (c + lines >= &cmdtab[NCMDS]) {
260 printf("\n");
261 break;
262 }
263 w = strlen(c->c_name);
264 while (w < width) {
265 w = (w + 8) &~ 7;
266 putchar('\t');
267 }
268 }
269 }
270 return;
271 }
272 while (--argc > 0) {
273 char *arg;
274 arg = *++argv;
275 c = getcmd(arg);
276 if (c == (struct cmd *)-1)
277 printf("?Ambiguous help command %s\n", arg);
278 else if (c == (struct cmd *)0)
279 printf("?Invalid help command %s\n", arg);
280 else
281 printf("%-*s\t%s\n", (int)HELPINDENT,
282 c->c_name, c->c_help);
283 }
284 }
285
286 /*
287 * return non-zero if the user is a member of the given group
288 */
289 static int
290 ingroup(char *grname)
291 {
292 static struct group *gptr=NULL;
293 static gid_t groups[NGROUPS];
294 static int ngroups;
295 gid_t gid;
296 int i;
297
298 if (gptr == NULL) {
299 if ((gptr = getgrnam(grname)) == NULL) {
300 warnx("Warning: unknown group `%s'",
301 grname);
302 return(0);
303 }
304 ngroups = getgroups(NGROUPS, groups);
305 if (ngroups < 0)
306 err(1, "getgroups");
307 }
308 gid = gptr->gr_gid;
309 for (i = 0; i < ngroups; i++)
310 if (gid == groups[i])
311 return(1);
312 return(0);
313 }
314