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