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