lpc.c revision 78280
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 "$FreeBSD: head/usr.sbin/lpr/lpc/lpc.c 78280 2001-06-15 16:28:37Z gad $"; 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#include <histedit.h> 63 64#include "lp.h" 65#include "lpc.h" 66#include "extern.h" 67 68#ifndef LPR_OPER 69#define LPR_OPER "operator" /* group name of lpr operators */ 70#endif 71 72/* 73 * lpc -- line printer control program 74 */ 75 76#define MAX_CMDLINE 200 77#define MAX_MARGV 20 78static int fromatty; 79 80static char cmdline[MAX_CMDLINE]; 81static int margc; 82static char *margv[MAX_MARGV]; 83uid_t uid, euid; 84 85int main(int _argc, char *_argv[]); 86static void cmdscanner(void); 87static struct cmd *getcmd(const char *_name); 88static void intr(int _signo); 89static void makeargv(void); 90static int ingroup(const char *_grname); 91 92int 93main(int argc, char *argv[]) 94{ 95 register struct cmd *c; 96 97 euid = geteuid(); 98 uid = getuid(); 99 seteuid(uid); 100 progname = 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 if (c->c_generic != 0) 118 generic(c->c_generic, argc, argv); 119 else 120 (*c->c_handler)(argc, argv); 121 exit(0); 122 } 123 fromatty = isatty(fileno(stdin)); 124 if (!fromatty) 125 signal(SIGINT, intr); 126 for (;;) { 127 cmdscanner(); 128 } 129} 130 131static void 132intr(int signo __unused) 133{ 134 /* (the '__unused' is just to avoid a compile-time warning) */ 135 exit(0); 136} 137 138static const char * 139lpc_prompt(void) 140{ 141 return ("lpc> "); 142} 143 144/* 145 * Command parser. 146 */ 147static void 148cmdscanner(void) 149{ 150 register struct cmd *c; 151 static EditLine *el = NULL; 152 static History *hist = NULL; 153 int num = 0; 154 int len; 155 const char *bp = NULL; 156 157 for (;;) { 158 if (fromatty) { 159 if (!el) { 160 el = el_init("lpc", stdin, stdout); 161 hist = history_init(); 162 history(hist, H_EVENT, 100); 163 el_set(el, EL_HIST, history, hist); 164 el_set(el, EL_EDITOR, "emacs"); 165 el_set(el, EL_PROMPT, lpc_prompt); 166 el_set(el, EL_SIGNAL, 1); 167 el_source(el, NULL); 168 } 169 if ((bp = el_gets(el, &num)) == NULL || num == 0) 170 quit(0, NULL); 171 172 len = (num > MAX_CMDLINE) ? MAX_CMDLINE : num; 173 memcpy(cmdline, bp, len); 174 cmdline[len] = 0; 175 history(hist, H_ENTER, bp); 176 177 } else { 178 if (fgets(cmdline, MAX_CMDLINE, stdin) == 0) 179 quit(0, NULL); 180 if (cmdline[0] == 0 || cmdline[0] == '\n') 181 break; 182 } 183 184 makeargv(); 185 if (margc == 0) 186 continue; 187 if (el_parse(el, margc, margv) != -1) 188 continue; 189 190 c = getcmd(margv[0]); 191 if (c == (struct cmd *)-1) { 192 printf("?Ambiguous command\n"); 193 continue; 194 } 195 if (c == 0) { 196 printf("?Invalid command\n"); 197 continue; 198 } 199 if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) { 200 printf("?Privileged command\n"); 201 continue; 202 } 203 if (c->c_generic != 0) 204 generic(c->c_generic, margc, margv); 205 else 206 (*c->c_handler)(margc, margv); 207 } 208} 209 210static struct cmd * 211getcmd(const char *name) 212{ 213 register const char *p, *q; 214 register struct cmd *c, *found; 215 register int nmatches, longest; 216 217 longest = 0; 218 nmatches = 0; 219 found = 0; 220 for (c = cmdtab; (p = c->c_name); c++) { 221 for (q = name; *q == *p++; q++) 222 if (*q == 0) /* exact match? */ 223 return(c); 224 if (!*q) { /* the name was a prefix */ 225 if (q - name > longest) { 226 longest = q - name; 227 nmatches = 1; 228 found = c; 229 } else if (q - name == longest) 230 nmatches++; 231 } 232 } 233 if (nmatches > 1) 234 return((struct cmd *)-1); 235 return(found); 236} 237 238/* 239 * Slice a string up into argc/argv. 240 */ 241static void 242makeargv(void) 243{ 244 register char *cp; 245 register char **argp = margv; 246 register int n = 0; 247 248 margc = 0; 249 for (cp = cmdline; *cp && (cp - cmdline) < sizeof(cmdline) && 250 n < MAX_MARGV; n++) { 251 while (isspace(*cp)) 252 cp++; 253 if (*cp == '\0') 254 break; 255 *argp++ = cp; 256 margc += 1; 257 while (*cp != '\0' && !isspace(*cp)) 258 cp++; 259 if (*cp == '\0') 260 break; 261 *cp++ = '\0'; 262 } 263 *argp++ = 0; 264} 265 266#define HELPINDENT (sizeof ("directory")) 267 268/* 269 * Help command. 270 */ 271void 272help(int argc, char *argv[]) 273{ 274 register struct cmd *c; 275 276 if (argc == 1) { 277 register int i, j, w; 278 int columns, width = 0, lines; 279 280 printf("Commands may be abbreviated. Commands are:\n\n"); 281 for (c = cmdtab; c->c_name; c++) { 282 int len = strlen(c->c_name); 283 284 if (len > width) 285 width = len; 286 } 287 width = (width + 8) &~ 7; 288 columns = 80 / width; 289 if (columns == 0) 290 columns = 1; 291 lines = (NCMDS + columns - 1) / columns; 292 for (i = 0; i < lines; i++) { 293 for (j = 0; j < columns; j++) { 294 c = cmdtab + j * lines + i; 295 if (c->c_name) 296 printf("%s", c->c_name); 297 if (c + lines >= &cmdtab[NCMDS]) { 298 printf("\n"); 299 break; 300 } 301 w = strlen(c->c_name); 302 while (w < width) { 303 w = (w + 8) &~ 7; 304 putchar('\t'); 305 } 306 } 307 } 308 return; 309 } 310 while (--argc > 0) { 311 register char *arg; 312 arg = *++argv; 313 c = getcmd(arg); 314 if (c == (struct cmd *)-1) 315 printf("?Ambiguous help command %s\n", arg); 316 else if (c == (struct cmd *)0) 317 printf("?Invalid help command %s\n", arg); 318 else 319 printf("%-*s\t%s\n", (int) HELPINDENT, 320 c->c_name, c->c_help); 321 } 322} 323 324/* 325 * return non-zero if the user is a member of the given group 326 */ 327static int 328ingroup(const char *grname) 329{ 330 static struct group *gptr=NULL; 331 static int ngroups = 0; 332 static gid_t groups[NGROUPS]; 333 register gid_t gid; 334 register int i; 335 336 if (gptr == NULL) { 337 if ((gptr = getgrnam(grname)) == NULL) { 338 warnx("warning: unknown group '%s'", grname); 339 return(0); 340 } 341 ngroups = getgroups(NGROUPS, groups); 342 if (ngroups < 0) 343 err(1, "getgroups"); 344 } 345 gid = gptr->gr_gid; 346 for (i = 0; i < ngroups; i++) 347 if (gid == groups[i]) 348 return(1); 349 return(0); 350} 351