1 /* $OpenBSD: lpc.c,v 1.8 2000/11/21 07:22:53 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 1983, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 static char copyright[] = 39 "@(#) Copyright (c) 1983, 1993\n\ 40 The Regents of the University of California. All rights reserved.\n"; 41 #endif /* not lint */ 42 43 #ifndef lint 44 #if 0 45 static char sccsid[] = "@(#)lpc.c 8.3 (Berkeley) 4/28/95"; 46 #else 47 static char rcsid[] = "$OpenBSD: lpc.c,v 1.8 2000/11/21 07:22:53 deraadt Exp $"; 48 #endif 49 #endif /* not lint */ 50 51 #include <sys/param.h> 52 53 #include <dirent.h> 54 #include <signal.h> 55 #include <setjmp.h> 56 #include <syslog.h> 57 #include <unistd.h> 58 #include <stdlib.h> 59 #include <stdio.h> 60 #include <ctype.h> 61 #include <string.h> 62 #include <grp.h> 63 #include <sys/param.h> 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 78 int fromatty; 79 80 char cmdline[MAX_CMDLINE]; 81 int margc; 82 char *margv[MAX_MARGV]; 83 int top; 84 uid_t uid, euid; 85 86 jmp_buf toplevel; 87 88 void cmdscanner __P((int)); 89 struct cmd *getcmd __P((char *)); 90 void intr __P((int)); 91 void makeargv __P((void)); 92 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 (*c->c_handler)(argc, argv); 122 exit(0); 123 } 124 fromatty = isatty(fileno(stdin)); 125 top = sigsetjmp(toplevel, 1) == 0; 126 if (top) 127 signal(SIGINT, intr); 128 for (;;) { 129 cmdscanner(top); 130 top = 1; 131 } 132 } 133 134 void 135 intr(signo) 136 int signo; 137 { 138 if (!fromatty) 139 exit(0); 140 siglongjmp(toplevel, 1); 141 } 142 143 /* 144 * Command parser. 145 */ 146 void 147 cmdscanner(top) 148 int top; 149 { 150 register struct cmd *c; 151 152 if (!top) 153 putchar('\n'); 154 for (;;) { 155 if (fromatty) { 156 printf("lpc> "); 157 fflush(stdout); 158 } 159 if (fgets(cmdline, MAX_CMDLINE, stdin) == 0) 160 quit(0, NULL); 161 if (cmdline[0] == 0 || cmdline[0] == '\n') 162 break; 163 makeargv(); 164 c = getcmd(margv[0]); 165 if (c == (struct cmd *)-1) { 166 printf("?Ambiguous command\n"); 167 continue; 168 } 169 if (c == 0) { 170 printf("?Invalid command\n"); 171 continue; 172 } 173 if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) { 174 printf("?Privileged command\n"); 175 continue; 176 } 177 (*c->c_handler)(margc, margv); 178 } 179 siglongjmp(toplevel, 0); 180 } 181 182 struct cmd * 183 getcmd(name) 184 register char *name; 185 { 186 register char *p, *q; 187 register struct cmd *c, *found; 188 register int nmatches, longest; 189 190 longest = 0; 191 nmatches = 0; 192 found = 0; 193 for (c = cmdtab; (p = c->c_name); c++) { 194 for (q = name; *q == *p++; q++) 195 if (*q == 0) /* exact match? */ 196 return(c); 197 if (!*q) { /* the name was a prefix */ 198 if (q - name > longest) { 199 longest = q - name; 200 nmatches = 1; 201 found = c; 202 } else if (q - name == longest) 203 nmatches++; 204 } 205 } 206 if (nmatches > 1) 207 return((struct cmd *)-1); 208 return(found); 209 } 210 211 /* 212 * Slice a string up into argc/argv. 213 */ 214 void 215 makeargv() 216 { 217 register char *cp; 218 register char **argp = margv; 219 register int n = 0; 220 221 margc = 0; 222 for (cp = cmdline; *cp && (cp - cmdline) < sizeof(cmdline) && 223 n < MAX_MARGV; n++) { 224 while (isspace(*cp)) 225 cp++; 226 if (*cp == '\0') 227 break; 228 *argp++ = cp; 229 margc += 1; 230 while (*cp != '\0' && !isspace(*cp)) 231 cp++; 232 if (*cp == '\0') 233 break; 234 *cp++ = '\0'; 235 } 236 *argp++ = 0; 237 } 238 239 #define HELPINDENT (sizeof ("directory")) 240 241 /* 242 * Help command. 243 */ 244 void 245 help(argc, argv) 246 int argc; 247 char *argv[]; 248 { 249 register struct cmd *c; 250 251 if (argc == 1) { 252 register int i, j, w; 253 int columns, width = 0, lines; 254 extern int NCMDS; 255 256 printf("Commands may be abbreviated. Commands are:\n\n"); 257 for (c = cmdtab; c->c_name; c++) { 258 int len = strlen(c->c_name); 259 260 if (len > width) 261 width = len; 262 } 263 width = (width + 8) &~ 7; 264 columns = 80 / width; 265 if (columns == 0) 266 columns = 1; 267 lines = (NCMDS + columns - 1) / columns; 268 for (i = 0; i < lines; i++) { 269 for (j = 0; j < columns; j++) { 270 c = cmdtab + j * lines + i; 271 if (c->c_name) 272 printf("%s", c->c_name); 273 if (c + lines >= &cmdtab[NCMDS]) { 274 printf("\n"); 275 break; 276 } 277 w = strlen(c->c_name); 278 while (w < width) { 279 w = (w + 8) &~ 7; 280 putchar('\t'); 281 } 282 } 283 } 284 return; 285 } 286 while (--argc > 0) { 287 register char *arg; 288 arg = *++argv; 289 c = getcmd(arg); 290 if (c == (struct cmd *)-1) 291 printf("?Ambiguous help command %s\n", arg); 292 else if (c == (struct cmd *)0) 293 printf("?Invalid help command %s\n", arg); 294 else 295 printf("%-*s\t%s\n", HELPINDENT, 296 c->c_name, c->c_help); 297 } 298 } 299 300 /* 301 * return non-zero if the user is a member of the given group 302 */ 303 int 304 ingroup(grname) 305 char *grname; 306 { 307 static struct group *gptr = NULL; 308 static gid_t groups[NGROUPS]; 309 register gid_t gid; 310 register int i; 311 static int maxgroups; 312 313 if (gptr == NULL) { 314 if ((gptr = getgrnam(grname)) == NULL) { 315 fprintf(stderr, "Warning: unknown group '%s'\n", 316 grname); 317 return(0); 318 } 319 if ((maxgroups = getgroups(NGROUPS, groups)) < 0) { 320 perror("getgroups"); 321 exit(1); 322 } 323 } 324 gid = gptr->gr_gid; 325 for (i = 0; i < maxgroups; i++) 326 if (gid == groups[i]) 327 return(1); 328 return(0); 329 } 330