lpc.c revision 27618
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 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 42static char sccsid[] = "@(#)lpc.c 8.3 (Berkeley) 4/28/95"; 43#endif /* not lint */ 44 45#include <sys/param.h> 46 47#include <dirent.h> 48#include <signal.h> 49#include <setjmp.h> 50#include <syslog.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 <sys/param.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_CMDLINE 200 71#define MAX_MARGV 20 72int fromatty; 73 74char cmdline[MAX_CMDLINE]; 75int margc; 76char *margv[MAX_MARGV]; 77int top; 78uid_t uid, euid; 79 80jmp_buf toplevel; 81 82static void cmdscanner __P((int)); 83static struct cmd *getcmd __P((char *)); 84static void intr __P((int)); 85static void makeargv __P((void)); 86static int ingroup __P((char *)); 87 88int 89main(argc, argv) 90 int argc; 91 char *argv[]; 92{ 93 register struct cmd *c; 94 95 euid = geteuid(); 96 uid = getuid(); 97 seteuid(uid); 98 name = argv[0]; 99 openlog("lpd", 0, LOG_LPR); 100 101 if (--argc > 0) { 102 c = getcmd(*++argv); 103 if (c == (struct cmd *)-1) { 104 printf("?Ambiguous command\n"); 105 exit(1); 106 } 107 if (c == 0) { 108 printf("?Invalid command\n"); 109 exit(1); 110 } 111 if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) { 112 printf("?Privileged command\n"); 113 exit(1); 114 } 115 (*c->c_handler)(argc, argv); 116 exit(0); 117 } 118 fromatty = isatty(fileno(stdin)); 119 top = setjmp(toplevel) == 0; 120 if (top) 121 signal(SIGINT, intr); 122 for (;;) { 123 cmdscanner(top); 124 top = 1; 125 } 126} 127 128static void 129intr(signo) 130 int signo; 131{ 132 if (!fromatty) 133 exit(0); 134 longjmp(toplevel, 1); 135} 136 137/* 138 * Command parser. 139 */ 140static void 141cmdscanner(top) 142 int top; 143{ 144 register 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 if (cmdline[0] == 0 || cmdline[0] == '\n') 156 break; 157 makeargv(); 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 176static struct cmd * 177getcmd(name) 178 register char *name; 179{ 180 register char *p, *q; 181 register struct cmd *c, *found; 182 register int nmatches, longest; 183 184 longest = 0; 185 nmatches = 0; 186 found = 0; 187 for (c = cmdtab; (p = c->c_name); c++) { 188 for (q = name; *q == *p++; q++) 189 if (*q == 0) /* exact match? */ 190 return(c); 191 if (!*q) { /* the name was a prefix */ 192 if (q - name > longest) { 193 longest = q - name; 194 nmatches = 1; 195 found = c; 196 } else if (q - name == longest) 197 nmatches++; 198 } 199 } 200 if (nmatches > 1) 201 return((struct cmd *)-1); 202 return(found); 203} 204 205/* 206 * Slice a string up into argc/argv. 207 */ 208static void 209makeargv() 210{ 211 register char *cp; 212 register char **argp = margv; 213 register int n = 0; 214 215 margc = 0; 216 for (cp = cmdline; *cp && (cp - cmdline) < sizeof(cmdline) && 217 n < MAX_MARGV; n++) { 218 while (isspace(*cp)) 219 cp++; 220 if (*cp == '\0') 221 break; 222 *argp++ = cp; 223 margc += 1; 224 while (*cp != '\0' && !isspace(*cp)) 225 cp++; 226 if (*cp == '\0') 227 break; 228 *cp++ = '\0'; 229 } 230 *argp++ = 0; 231} 232 233#define HELPINDENT (sizeof ("directory")) 234 235/* 236 * Help command. 237 */ 238void 239help(argc, argv) 240 int argc; 241 char *argv[]; 242{ 243 register struct cmd *c; 244 245 if (argc == 1) { 246 register int i, j, w; 247 int columns, width = 0, lines; 248 249 printf("Commands may be abbreviated. Commands are:\n\n"); 250 for (c = cmdtab; c->c_name; c++) { 251 int len = strlen(c->c_name); 252 253 if (len > width) 254 width = len; 255 } 256 width = (width + 8) &~ 7; 257 columns = 80 / width; 258 if (columns == 0) 259 columns = 1; 260 lines = (NCMDS + columns - 1) / columns; 261 for (i = 0; i < lines; i++) { 262 for (j = 0; j < columns; j++) { 263 c = cmdtab + j * lines + i; 264 if (c->c_name) 265 printf("%s", c->c_name); 266 if (c + lines >= &cmdtab[NCMDS]) { 267 printf("\n"); 268 break; 269 } 270 w = strlen(c->c_name); 271 while (w < width) { 272 w = (w + 8) &~ 7; 273 putchar('\t'); 274 } 275 } 276 } 277 return; 278 } 279 while (--argc > 0) { 280 register char *arg; 281 arg = *++argv; 282 c = getcmd(arg); 283 if (c == (struct cmd *)-1) 284 printf("?Ambiguous help command %s\n", arg); 285 else if (c == (struct cmd *)0) 286 printf("?Invalid help command %s\n", arg); 287 else 288 printf("%-*s\t%s\n", HELPINDENT, 289 c->c_name, c->c_help); 290 } 291} 292 293/* 294 * return non-zero if the user is a member of the given group 295 */ 296static int 297ingroup(grname) 298 char *grname; 299{ 300 static struct group *gptr=NULL; 301 static gid_t groups[NGROUPS]; 302 register gid_t gid; 303 register int i; 304 305 if (gptr == NULL) { 306 if ((gptr = getgrnam(grname)) == NULL) { 307 fprintf(stderr, "Warning: unknown group '%s'\n", 308 grname); 309 return(0); 310 } 311 if (getgroups(NGROUPS, groups) < 0) { 312 perror("getgroups"); 313 exit(1); 314 } 315 } 316 gid = gptr->gr_gid; 317 for (i = 0; i < NGROUPS; i++) 318 if (gid == groups[i]) 319 return(1); 320 return(0); 321} 322