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