lpc.c revision 298910
11553Srgrimes/* 21553Srgrimes * Copyright (c) 1983, 1993 31553Srgrimes * The Regents of the University of California. All rights reserved. 41553Srgrimes * 51553Srgrimes * 61553Srgrimes * Redistribution and use in source and binary forms, with or without 71553Srgrimes * modification, are permitted provided that the following conditions 81553Srgrimes * are met: 91553Srgrimes * 1. Redistributions of source code must retain the above copyright 101553Srgrimes * notice, this list of conditions and the following disclaimer. 111553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 121553Srgrimes * notice, this list of conditions and the following disclaimer in the 131553Srgrimes * documentation and/or other materials provided with the distribution. 141553Srgrimes * 4. Neither the name of the University nor the names of its contributors 151553Srgrimes * may be used to endorse or promote products derived from this software 161553Srgrimes * without specific prior written permission. 171553Srgrimes * 181553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 191553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 201553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 211553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 221553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 231553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 241553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 251553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 261553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 271553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 281553Srgrimes * SUCH DAMAGE. 291553Srgrimes */ 301553Srgrimes 311553Srgrimes#ifndef lint 3229780Scharnierstatic const char copyright[] = 331553Srgrimes"@(#) Copyright (c) 1983, 1993\n\ 341553Srgrimes The Regents of the University of California. All rights reserved.\n"; 351553Srgrimes#endif /* not lint */ 361553Srgrimes 37117599Sgad#if 0 381553Srgrimes#ifndef lint 3915637Sjoergstatic char sccsid[] = "@(#)lpc.c 8.3 (Berkeley) 4/28/95"; 40117599Sgad#endif /* not lint */ 4129780Scharnier#endif 421553Srgrimes 43117599Sgad#include "lp.cdefs.h" /* A cross-platform version of <sys/cdefs.h> */ 44117599Sgad__FBSDID("$FreeBSD: head/usr.sbin/lpr/lpc/lpc.c 298910 2016-05-02 01:45:52Z araujo $"); 45117599Sgad 461553Srgrimes#include <sys/param.h> 471553Srgrimes 4829780Scharnier#include <ctype.h> 491553Srgrimes#include <dirent.h> 5031492Swollman#include <err.h> 5129780Scharnier#include <grp.h> 5229780Scharnier#include <setjmp.h> 531553Srgrimes#include <signal.h> 5429780Scharnier#include <stdio.h> 5529780Scharnier#include <stdlib.h> 561553Srgrimes#include <syslog.h> 5729780Scharnier#include <string.h> 581553Srgrimes#include <unistd.h> 5950039Smdodd#include <histedit.h> 6031492Swollman 611553Srgrimes#include "lp.h" 621553Srgrimes#include "lpc.h" 631553Srgrimes#include "extern.h" 641553Srgrimes 6515637Sjoerg#ifndef LPR_OPER 6615637Sjoerg#define LPR_OPER "operator" /* group name of lpr operators */ 6715637Sjoerg#endif 6815637Sjoerg 691553Srgrimes/* 701553Srgrimes * lpc -- line printer control program 711553Srgrimes */ 721553Srgrimes 7327618Simp#define MAX_CMDLINE 200 7427618Simp#define MAX_MARGV 20 7539084Swollmanstatic int fromatty; 761553Srgrimes 7739084Swollmanstatic char cmdline[MAX_CMDLINE]; 7839084Swollmanstatic int margc; 7939084Swollmanstatic char *margv[MAX_MARGV]; 8039084Swollmanuid_t uid, euid; 811553Srgrimes 8278146Sgadint main(int _argc, char *_argv[]); 8378146Sgadstatic void cmdscanner(void); 8478146Sgadstatic struct cmd *getcmd(const char *_name); 8578146Sgadstatic void intr(int _signo); 8678146Sgadstatic void makeargv(void); 8778146Sgadstatic int ingroup(const char *_grname); 881553Srgrimes 891553Srgrimesint 9078146Sgadmain(int argc, char *argv[]) 911553Srgrimes{ 921553Srgrimes register struct cmd *c; 931553Srgrimes 9427618Simp euid = geteuid(); 9527618Simp uid = getuid(); 96241852Seadler PRIV_END 9778280Sgad progname = argv[0]; 981553Srgrimes openlog("lpd", 0, LOG_LPR); 991553Srgrimes 1001553Srgrimes if (--argc > 0) { 1011553Srgrimes c = getcmd(*++argv); 1021553Srgrimes if (c == (struct cmd *)-1) { 1031553Srgrimes printf("?Ambiguous command\n"); 1041553Srgrimes exit(1); 1051553Srgrimes } 106297795Spfg if (c == NULL) { 1071553Srgrimes printf("?Invalid command\n"); 1081553Srgrimes exit(1); 1091553Srgrimes } 11098267Sgad if ((c->c_opts & LPC_PRIVCMD) && getuid() && 11198267Sgad ingroup(LPR_OPER) == 0) { 1121553Srgrimes printf("?Privileged command\n"); 1131553Srgrimes exit(1); 1141553Srgrimes } 115297795Spfg if (c->c_generic != NULL) 11698267Sgad generic(c->c_generic, c->c_opts, c->c_handler, 11798267Sgad argc, argv); 11831492Swollman else 11931492Swollman (*c->c_handler)(argc, argv); 1201553Srgrimes exit(0); 1211553Srgrimes } 1221553Srgrimes fromatty = isatty(fileno(stdin)); 12350039Smdodd if (!fromatty) 1241553Srgrimes signal(SIGINT, intr); 1251553Srgrimes for (;;) { 12650039Smdodd cmdscanner(); 1271553Srgrimes } 1281553Srgrimes} 1291553Srgrimes 1301553Srgrimesstatic void 13178146Sgadintr(int signo __unused) 1321553Srgrimes{ 13378146Sgad /* (the '__unused' is just to avoid a compile-time warning) */ 13450039Smdodd exit(0); 1351553Srgrimes} 1361553Srgrimes 13778146Sgadstatic const char * 13868400Sgadlpc_prompt(void) 13950039Smdodd{ 14068400Sgad return ("lpc> "); 14150039Smdodd} 14250039Smdodd 1431553Srgrimes/* 1441553Srgrimes * Command parser. 1451553Srgrimes */ 1461553Srgrimesstatic void 14778146Sgadcmdscanner(void) 1481553Srgrimes{ 1491553Srgrimes register struct cmd *c; 15079742Sgad static EditLine *el; 15179742Sgad static History *hist; 15284261Sobrien HistEvent he; 15379742Sgad size_t len; 15479742Sgad int num; 15579742Sgad const char *bp; 1561553Srgrimes 15779742Sgad num = 0; 15879742Sgad bp = NULL; 15979742Sgad el = NULL; 16079742Sgad hist = NULL; 1611553Srgrimes for (;;) { 1621553Srgrimes if (fromatty) { 16350039Smdodd if (!el) { 16484261Sobrien el = el_init("lpc", stdin, stdout, stderr); 16550039Smdodd hist = history_init(); 166151476Sstefanf history(hist, &he, H_SETSIZE, 100); 16750039Smdodd el_set(el, EL_HIST, history, hist); 16850039Smdodd el_set(el, EL_EDITOR, "emacs"); 16950039Smdodd el_set(el, EL_PROMPT, lpc_prompt); 17050039Smdodd el_set(el, EL_SIGNAL, 1); 17150042Smdodd el_source(el, NULL); 17283563Sgad /* 17383563Sgad * EditLine init may call 'cgetset()' to set a 17483563Sgad * capability-db meant for termcap (eg: to set 17583563Sgad * terminal type 'xterm'). Reset that now, or 17683563Sgad * that same db-information will be used for 17783563Sgad * printcap (giving us an "xterm" printer, with 17883563Sgad * all kinds of invalid capabilities...). 17983563Sgad */ 18083563Sgad cgetset(NULL); 18150039Smdodd } 18250039Smdodd if ((bp = el_gets(el, &num)) == NULL || num == 0) 18362294Smph quit(0, NULL); 18450039Smdodd 185298910Saraujo len = MIN(MAX_CMDLINE - 1, num); 18650071Smdodd memcpy(cmdline, bp, len); 18750071Smdodd cmdline[len] = 0; 18884261Sobrien history(hist, &he, H_ENTER, bp); 18950039Smdodd 19050039Smdodd } else { 191230044Skevlo if (fgets(cmdline, MAX_CMDLINE, stdin) == NULL) 19250039Smdodd quit(0, NULL); 19350039Smdodd if (cmdline[0] == 0 || cmdline[0] == '\n') 19450039Smdodd break; 1951553Srgrimes } 19650039Smdodd 1971553Srgrimes makeargv(); 19850039Smdodd if (margc == 0) 19950039Smdodd continue; 200142199Sdelphij if (el != NULL && el_parse(el, margc, margv) != -1) 20150039Smdodd continue; 20250039Smdodd 2031553Srgrimes c = getcmd(margv[0]); 2041553Srgrimes if (c == (struct cmd *)-1) { 2051553Srgrimes printf("?Ambiguous command\n"); 2061553Srgrimes continue; 2071553Srgrimes } 208297795Spfg if (c == NULL) { 2091553Srgrimes printf("?Invalid command\n"); 2101553Srgrimes continue; 2111553Srgrimes } 21298267Sgad if ((c->c_opts & LPC_PRIVCMD) && getuid() && 21398267Sgad ingroup(LPR_OPER) == 0) { 2141553Srgrimes printf("?Privileged command\n"); 2151553Srgrimes continue; 2161553Srgrimes } 21778750Sgad 21878750Sgad /* 21978750Sgad * Two different commands might have the same generic rtn 22078750Sgad * (eg: "clean" and "tclean"), and just use different 22178750Sgad * handler routines for distinct command-setup. The handler 22278750Sgad * routine might also be set on a generic routine for 22378750Sgad * initial parameter processing. 22478750Sgad */ 225297795Spfg if (c->c_generic != NULL) 22698267Sgad generic(c->c_generic, c->c_opts, c->c_handler, 22798267Sgad margc, margv); 22831492Swollman else 22931492Swollman (*c->c_handler)(margc, margv); 2301553Srgrimes } 2311553Srgrimes} 2321553Srgrimes 23315637Sjoergstatic struct cmd * 23478146Sgadgetcmd(const char *name) 2351553Srgrimes{ 23678146Sgad register const char *p, *q; 2371553Srgrimes register struct cmd *c, *found; 2381553Srgrimes register int nmatches, longest; 2391553Srgrimes 2401553Srgrimes longest = 0; 2411553Srgrimes nmatches = 0; 242297795Spfg found = NULL; 24319202Simp for (c = cmdtab; (p = c->c_name); c++) { 2441553Srgrimes for (q = name; *q == *p++; q++) 2451553Srgrimes if (*q == 0) /* exact match? */ 2461553Srgrimes return(c); 2471553Srgrimes if (!*q) { /* the name was a prefix */ 2481553Srgrimes if (q - name > longest) { 2491553Srgrimes longest = q - name; 2501553Srgrimes nmatches = 1; 2511553Srgrimes found = c; 2521553Srgrimes } else if (q - name == longest) 2531553Srgrimes nmatches++; 2541553Srgrimes } 2551553Srgrimes } 2561553Srgrimes if (nmatches > 1) 2571553Srgrimes return((struct cmd *)-1); 2581553Srgrimes return(found); 2591553Srgrimes} 2601553Srgrimes 2611553Srgrimes/* 2621553Srgrimes * Slice a string up into argc/argv. 2631553Srgrimes */ 2641553Srgrimesstatic void 26578146Sgadmakeargv(void) 2661553Srgrimes{ 2671553Srgrimes register char *cp; 2681553Srgrimes register char **argp = margv; 26927618Simp register int n = 0; 2701553Srgrimes 2711553Srgrimes margc = 0; 27280173Sgad for (cp = cmdline; *cp && (size_t)(cp - cmdline) < sizeof(cmdline) && 273121065Stjr n < MAX_MARGV - 1; n++) { 2741553Srgrimes while (isspace(*cp)) 2751553Srgrimes cp++; 2761553Srgrimes if (*cp == '\0') 2771553Srgrimes break; 2781553Srgrimes *argp++ = cp; 2791553Srgrimes margc += 1; 2801553Srgrimes while (*cp != '\0' && !isspace(*cp)) 2811553Srgrimes cp++; 2821553Srgrimes if (*cp == '\0') 2831553Srgrimes break; 2841553Srgrimes *cp++ = '\0'; 2851553Srgrimes } 286297795Spfg *argp++ = NULL; 2871553Srgrimes} 2881553Srgrimes 2891553Srgrimes#define HELPINDENT (sizeof ("directory")) 2901553Srgrimes 2911553Srgrimes/* 2921553Srgrimes * Help command. 2931553Srgrimes */ 2941553Srgrimesvoid 29578146Sgadhelp(int argc, char *argv[]) 2961553Srgrimes{ 2971553Srgrimes register struct cmd *c; 2981553Srgrimes 2991553Srgrimes if (argc == 1) { 3001553Srgrimes register int i, j, w; 3011553Srgrimes int columns, width = 0, lines; 3021553Srgrimes 3031553Srgrimes printf("Commands may be abbreviated. Commands are:\n\n"); 3041553Srgrimes for (c = cmdtab; c->c_name; c++) { 3051553Srgrimes int len = strlen(c->c_name); 3061553Srgrimes 3071553Srgrimes if (len > width) 3081553Srgrimes width = len; 3091553Srgrimes } 3101553Srgrimes width = (width + 8) &~ 7; 3111553Srgrimes columns = 80 / width; 3121553Srgrimes if (columns == 0) 3131553Srgrimes columns = 1; 3141553Srgrimes lines = (NCMDS + columns - 1) / columns; 3151553Srgrimes for (i = 0; i < lines; i++) { 3161553Srgrimes for (j = 0; j < columns; j++) { 3171553Srgrimes c = cmdtab + j * lines + i; 3181553Srgrimes if (c->c_name) 3191553Srgrimes printf("%s", c->c_name); 3201553Srgrimes if (c + lines >= &cmdtab[NCMDS]) { 3211553Srgrimes printf("\n"); 3221553Srgrimes break; 3231553Srgrimes } 3241553Srgrimes w = strlen(c->c_name); 3251553Srgrimes while (w < width) { 3261553Srgrimes w = (w + 8) &~ 7; 3271553Srgrimes putchar('\t'); 3281553Srgrimes } 3291553Srgrimes } 3301553Srgrimes } 3311553Srgrimes return; 3321553Srgrimes } 3331553Srgrimes while (--argc > 0) { 3341553Srgrimes register char *arg; 3351553Srgrimes arg = *++argv; 3361553Srgrimes c = getcmd(arg); 3371553Srgrimes if (c == (struct cmd *)-1) 3381553Srgrimes printf("?Ambiguous help command %s\n", arg); 3391553Srgrimes else if (c == (struct cmd *)0) 3401553Srgrimes printf("?Invalid help command %s\n", arg); 3411553Srgrimes else 34234784Sjb printf("%-*s\t%s\n", (int) HELPINDENT, 3431553Srgrimes c->c_name, c->c_help); 3441553Srgrimes } 3451553Srgrimes} 34615637Sjoerg 34715637Sjoerg/* 34815637Sjoerg * return non-zero if the user is a member of the given group 34915637Sjoerg */ 35015637Sjoergstatic int 35178146Sgadingroup(const char *grname) 35215637Sjoerg{ 35315637Sjoerg static struct group *gptr=NULL; 35465035Salfred static int ngroups = 0; 355194494Sbrooks static long ngroups_max; 356194494Sbrooks static gid_t *groups; 35715637Sjoerg register gid_t gid; 35815637Sjoerg register int i; 35915637Sjoerg 36015637Sjoerg if (gptr == NULL) { 36115637Sjoerg if ((gptr = getgrnam(grname)) == NULL) { 36229780Scharnier warnx("warning: unknown group '%s'", grname); 36315637Sjoerg return(0); 36415637Sjoerg } 365194494Sbrooks ngroups_max = sysconf(_SC_NGROUPS_MAX); 366194494Sbrooks if ((groups = malloc(sizeof(gid_t) * ngroups_max)) == NULL) 367194494Sbrooks err(1, "malloc"); 368194494Sbrooks ngroups = getgroups(ngroups_max, groups); 36965035Salfred if (ngroups < 0) 37029780Scharnier err(1, "getgroups"); 37115637Sjoerg } 37215637Sjoerg gid = gptr->gr_gid; 37365035Salfred for (i = 0; i < ngroups; i++) 37415637Sjoerg if (gid == groups[i]) 37515637Sjoerg return(1); 37615637Sjoerg return(0); 37715637Sjoerg} 378100203Sgad 379100203Sgad/* 380100203Sgad * Routine to get the information for a single printer (which will be 381100203Sgad * called by the routines which implement individual commands). 382100203Sgad * Note: This is for commands operating on a *single* printer. 383100203Sgad */ 384100203Sgadstruct printer * 385100203Sgadsetup_myprinter(char *pwanted, struct printer *pp, int sump_opts) 386100203Sgad{ 387100203Sgad int cdres, cmdstatus; 388100203Sgad 389100203Sgad init_printer(pp); 390100203Sgad cmdstatus = getprintcap(pwanted, pp); 391100203Sgad switch (cmdstatus) { 392100203Sgad default: 393100203Sgad fatal(pp, "%s", pcaperr(cmdstatus)); 394100203Sgad /* NOTREACHED */ 395100203Sgad case PCAPERR_NOTFOUND: 396100203Sgad printf("unknown printer %s\n", pwanted); 397100203Sgad return (NULL); 398100203Sgad case PCAPERR_TCOPEN: 399100203Sgad printf("warning: %s: unresolved tc= reference(s)", pwanted); 400100203Sgad break; 401100203Sgad case PCAPERR_SUCCESS: 402100203Sgad break; 403100203Sgad } 404100203Sgad if ((sump_opts & SUMP_NOHEADER) == 0) 405100203Sgad printf("%s:\n", pp->printer); 406100203Sgad 407100203Sgad if (sump_opts & SUMP_CHDIR_SD) { 408241852Seadler PRIV_START 409100203Sgad cdres = chdir(pp->spool_dir); 410241852Seadler PRIV_END 411100203Sgad if (cdres < 0) { 412100203Sgad printf("\tcannot chdir to %s\n", pp->spool_dir); 413100203Sgad free_printer(pp); 414100203Sgad return (NULL); 415100203Sgad } 416100203Sgad } 417100203Sgad 418100203Sgad return (pp); 419100203Sgad} 420