1 /* $NetBSD: lpc.c,v 1.27 2017/05/04 16:26:09 sevan 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\
36 The Regents of the University of California. All rights reserved.");
37 #if 0
38 static char sccsid[] = "@(#)lpc.c 8.3 (Berkeley) 4/28/95";
39 #else
40 __RCSID("$NetBSD: lpc.c,v 1.27 2017/05/04 16:26:09 sevan 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 <histedit.h>
51 #include <unistd.h>
52 #include <stdlib.h>
53 #include <stdio.h>
54 #include <ctype.h>
55 #include <string.h>
56 #include <grp.h>
57 #include <err.h>
58 #include "lp.h"
59 #include "lpc.h"
60 #include "extern.h"
61
62 #ifndef LPR_OPER
63 #define LPR_OPER "operator" /* group name of lpr operators */
64 #endif
65
66 /*
67 * lpc -- line printer control program
68 */
69
70 #define MAX_MARGV 20
71 int fromatty;
72
73 char *cmdline;
74 int margc;
75 char *margv[MAX_MARGV];
76 int top;
77 uid_t uid, euid;
78
79 jmp_buf toplevel;
80
81 History *hist;
82 HistEvent he;
83 EditLine *elptr;
84
85 __dead static void cmdscanner(int);
86 static struct cmd *getcmd(const char *);
87 __dead static void intr(int);
88 static void makeargv(void);
89 static int ingroup(const char *);
90 const char *prompt(void);
91 static int parse(char *, char *p[], int);
92
93 int
main(int argc,char * argv[])94 main(int argc, char *argv[])
95 {
96 euid = geteuid();
97 uid = getuid();
98 seteuid(uid);
99 setprogname(argv[0]);
100 openlog("lpd", 0, LOG_LPR);
101
102 if (--argc > 0) {
103 argv++;
104 exit(!parse(*argv, argv, argc));
105 }
106 fromatty = isatty(fileno(stdin));
107 top = setjmp(toplevel) == 0;
108 if (top)
109 signal(SIGINT, intr);
110 for (;;) {
111 cmdscanner(top);
112 top = 1;
113 }
114 }
115
116 static int
parse(char * arg,char ** pargv,int pargc)117 parse(char *arg, char **pargv, int pargc)
118 {
119 struct cmd *c;
120
121 c = getcmd(arg);
122 if (c == (struct cmd *)-1) {
123 printf("?Ambiguous command\n");
124 return(0);
125 }
126 if (c == 0) {
127 printf("?Invalid command\n");
128 return(0);
129 }
130 if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) {
131 printf("?Privileged command\n");
132 return(0);
133 }
134 (*c->c_handler)(pargc, pargv);
135 return(1);
136 }
137
138 static void
intr(int signo)139 intr(int signo)
140 {
141 el_end(elptr);
142 history_end(hist);
143 if (!fromatty)
144 exit(0);
145 longjmp(toplevel, 1);
146 }
147
148 const char *
prompt(void)149 prompt(void)
150 {
151 return ("lpc> ");
152 }
153
154 /*
155 * Command parser.
156 */
157 static void
cmdscanner(int tp)158 cmdscanner(int tp)
159 {
160 int scratch;
161 const char *elline;
162
163 if (!tp)
164 putchar('\n');
165 hist = history_init();
166 history(hist, &he, H_SETSIZE, 100); /* 100 elt history buffer */
167
168 elptr = el_init(getprogname(), stdin, stdout, stderr);
169 el_set(elptr, EL_EDITOR, "emacs");
170 el_set(elptr, EL_PROMPT, prompt);
171 el_set(elptr, EL_HIST, history, hist);
172 el_source(elptr, NULL);
173
174 for (;;) {
175 cmdline = NULL;
176 do {
177 if (((elline = el_gets(elptr, &scratch)) != NULL)
178 && (scratch != 0)) {
179 history(hist, &he, H_ENTER, elline);
180 cmdline = strdup(elline);
181 makeargv();
182 } else {
183 margc = 0;
184 break;
185 }
186 } while (margc == 0);
187 if (margc == 0)
188 quit(0, NULL);
189 if (!parse(cmdline, margv, margc)) {
190 if (cmdline != NULL)
191 free(cmdline);
192 continue;
193 }
194 fflush(stdout);
195 if (cmdline != NULL)
196 free(cmdline);
197 }
198 longjmp(toplevel, 0);
199 }
200
201 static struct cmd *
getcmd(const char * name)202 getcmd(const char *name)
203 {
204 const char *p, *q;
205 struct cmd *c, *found;
206 int nmatches, longest;
207
208 longest = 0;
209 nmatches = 0;
210 found = 0;
211 for (c = cmdtab; (p = c->c_name) != NULL; c++) {
212 for (q = name; *q == *p++; q++)
213 if (*q == 0) /* exact match? */
214 return(c);
215 if (!*q) { /* the name was a prefix */
216 if (q - name > longest) {
217 longest = q - name;
218 nmatches = 1;
219 found = c;
220 } else if (q - name == longest)
221 nmatches++;
222 }
223 }
224 if (nmatches > 1)
225 return((struct cmd *)-1);
226 return(found);
227 }
228
229 /*
230 * Slice a string up into argc/argv.
231 */
232 static void
makeargv(void)233 makeargv(void)
234 {
235 char *cp;
236 char **argp = margv;
237 int n = 0;
238 size_t s;
239
240 s = strlen(cmdline) + 1;
241 margc = 0;
242 for (cp = cmdline; *cp && (size_t)(cp - cmdline) < s && n < MAX_MARGV; n++) {
243 while (isspace((unsigned char)*cp))
244 cp++;
245 if (*cp == '\0')
246 break;
247 *argp++ = cp;
248 margc += 1;
249 while (*cp != '\0' && !isspace((unsigned char)*cp))
250 cp++;
251 if (*cp == '\0')
252 break;
253 *cp++ = '\0';
254 }
255 *argp++ = 0;
256 }
257
258 #define HELPINDENT (sizeof ("directory"))
259
260 /*
261 * Help command.
262 */
263 void
help(int argc,char * argv[])264 help(int argc, char *argv[])
265 {
266 struct cmd *c;
267
268 if (argc == 1) {
269 size_t i, j, w;
270 size_t columns, width = 0, lines;
271
272 printf("Commands may be abbreviated. Commands are:\n\n");
273 for (c = cmdtab; c->c_name; c++) {
274 size_t len = strlen(c->c_name);
275
276 if (len > width)
277 width = len;
278 }
279 width = (width + 8) &~ 7;
280 columns = 80 / width;
281 if (columns == 0)
282 columns = 1;
283 lines = (NCMDS + columns - 1) / columns;
284 for (i = 0; i < lines; i++) {
285 for (j = 0; j < columns; j++) {
286 c = cmdtab + j * lines + i;
287 printf("%s", c->c_name);
288 if (c + lines >= &cmdtab[NCMDS - 1]) {
289 printf("\n");
290 break;
291 }
292 w = strlen(c->c_name);
293 while (w < width) {
294 w = (w + 8) &~ 7;
295 putchar('\t');
296 }
297 }
298 }
299 return;
300 }
301 while (--argc > 0) {
302 char *arg;
303 arg = *++argv;
304 c = getcmd(arg);
305 if (c == (struct cmd *)-1)
306 printf("?Ambiguous help command %s\n", arg);
307 else if (c == (struct cmd *)0)
308 printf("?Invalid help command %s\n", arg);
309 else
310 printf("%-*s\t%s\n", (int)HELPINDENT,
311 c->c_name, c->c_help);
312 }
313 }
314
315 /*
316 * return non-zero if the user is a member of the given group
317 */
318 static int
ingroup(const char * grname)319 ingroup(const char *grname)
320 {
321 static struct group *gptr = NULL;
322 static gid_t groups[NGROUPS];
323 static int ngroups;
324 gid_t gid;
325 int i;
326
327 if (gptr == NULL) {
328 if ((gptr = getgrnam(grname)) == NULL) {
329 warnx("Warning: unknown group `%s'",
330 grname);
331 return(0);
332 }
333 ngroups = getgroups(NGROUPS, groups);
334 if (ngroups < 0)
335 err(1, "getgroups");
336 }
337 gid = gptr->gr_gid;
338 for (i = 0; i < ngroups; i++)
339 if (gid == groups[i])
340 return(1);
341 return(0);
342 }
343