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