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