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