1 /* $NetBSD: lpc.c,v 1.16 2004/10/30 08:44:26 dsl 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. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 #ifndef lint 35 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\ 36 The Regents of the University of California. All rights reserved.\n"); 37 #if 0 38 static char sccsid[] = "@(#)lpc.c 8.3 (Berkeley) 4/28/95"; 39 #else 40 __RCSID("$NetBSD: lpc.c,v 1.16 2004/10/30 08:44:26 dsl Exp $"); 41 #endif 42 #endif /* not lint */ 43 44 #include <sys/param.h> 45 46 #include <dirent.h> 47 #include <signal.h> 48 #include <setjmp.h> 49 #include <syslog.h> 50 #include <unistd.h> 51 #include <stdlib.h> 52 #include <stdio.h> 53 #include <ctype.h> 54 #include <string.h> 55 #include <grp.h> 56 #include <err.h> 57 #include "lp.h" 58 #include "lpc.h" 59 #include "extern.h" 60 61 #ifndef LPR_OPER 62 #define LPR_OPER "operator" /* group name of lpr operators */ 63 #endif 64 65 /* 66 * lpc -- line printer control program 67 */ 68 69 #define MAX_CMDLINE 200 70 #define MAX_MARGV 20 71 int fromatty; 72 73 char cmdline[MAX_CMDLINE]; 74 int margc; 75 char *margv[MAX_MARGV]; 76 int top; 77 uid_t uid, euid; 78 79 jmp_buf toplevel; 80 81 static void cmdscanner(int); 82 static struct cmd *getcmd(char *); 83 static void intr(int); 84 static void makeargv(void); 85 static int ingroup(char *); 86 int main(int, char *p[]); 87 88 int 89 main(int argc, char *argv[]) 90 { 91 struct cmd *c; 92 93 euid = geteuid(); 94 uid = getuid(); 95 seteuid(uid); 96 name = argv[0]; 97 openlog("lpd", 0, LOG_LPR); 98 99 if (--argc > 0) { 100 c = getcmd(*++argv); 101 if (c == (struct cmd *)-1) { 102 printf("?Ambiguous command\n"); 103 exit(1); 104 } 105 if (c == 0) { 106 printf("?Invalid command\n"); 107 exit(1); 108 } 109 if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) { 110 printf("?Privileged command\n"); 111 exit(1); 112 } 113 (*c->c_handler)(argc, argv); 114 exit(0); 115 } 116 fromatty = isatty(fileno(stdin)); 117 top = setjmp(toplevel) == 0; 118 if (top) 119 signal(SIGINT, intr); 120 for (;;) { 121 cmdscanner(top); 122 top = 1; 123 } 124 } 125 126 static void 127 intr(int signo) 128 { 129 if (!fromatty) 130 exit(0); 131 longjmp(toplevel, 1); 132 } 133 134 /* 135 * Command parser. 136 */ 137 static void 138 cmdscanner(int top) 139 { 140 struct cmd *c; 141 142 if (!top) 143 putchar('\n'); 144 for (;;) { 145 if (fromatty) { 146 printf("lpc> "); 147 fflush(stdout); 148 } 149 if (fgets(cmdline, MAX_CMDLINE, stdin) == 0) 150 quit(0, NULL); 151 makeargv(); 152 if (margc == 0) 153 break; 154 c = getcmd(margv[0]); 155 if (c == (struct cmd *)-1) { 156 printf("?Ambiguous command\n"); 157 continue; 158 } 159 if (c == 0) { 160 printf("?Invalid command\n"); 161 continue; 162 } 163 if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) { 164 printf("?Privileged command\n"); 165 continue; 166 } 167 (*c->c_handler)(margc, margv); 168 } 169 longjmp(toplevel, 0); 170 } 171 172 static struct cmd * 173 getcmd(char *name) 174 { 175 char *p, *q; 176 struct cmd *c, *found; 177 int nmatches, longest; 178 179 longest = 0; 180 nmatches = 0; 181 found = 0; 182 for (c = cmdtab; (p = c->c_name) != NULL; c++) { 183 for (q = name; *q == *p++; q++) 184 if (*q == 0) /* exact match? */ 185 return(c); 186 if (!*q) { /* the name was a prefix */ 187 if (q - name > longest) { 188 longest = q - name; 189 nmatches = 1; 190 found = c; 191 } else if (q - name == longest) 192 nmatches++; 193 } 194 } 195 if (nmatches > 1) 196 return((struct cmd *)-1); 197 return(found); 198 } 199 200 /* 201 * Slice a string up into argc/argv. 202 */ 203 static void 204 makeargv(void) 205 { 206 char *cp; 207 char **argp = margv; 208 int n = 0; 209 210 margc = 0; 211 for (cp = cmdline; *cp && (cp - cmdline) < sizeof(cmdline) && 212 n < MAX_MARGV; n++) { 213 while (isspace((unsigned char)*cp)) 214 cp++; 215 if (*cp == '\0') 216 break; 217 *argp++ = cp; 218 margc += 1; 219 while (*cp != '\0' && !isspace((unsigned char)*cp)) 220 cp++; 221 if (*cp == '\0') 222 break; 223 *cp++ = '\0'; 224 } 225 *argp++ = 0; 226 } 227 228 #define HELPINDENT (sizeof ("directory")) 229 230 /* 231 * Help command. 232 */ 233 void 234 help(int argc, char *argv[]) 235 { 236 struct cmd *c; 237 238 if (argc == 1) { 239 int i, j, w; 240 int columns, width = 0, lines; 241 242 printf("Commands may be abbreviated. Commands are:\n\n"); 243 for (c = cmdtab; c->c_name; c++) { 244 int len = strlen(c->c_name); 245 246 if (len > width) 247 width = len; 248 } 249 width = (width + 8) &~ 7; 250 columns = 80 / width; 251 if (columns == 0) 252 columns = 1; 253 lines = (NCMDS + columns - 1) / columns; 254 for (i = 0; i < lines; i++) { 255 for (j = 0; j < columns; j++) { 256 c = cmdtab + j * lines + i; 257 if (c->c_name) 258 printf("%s", c->c_name); 259 if (c + lines >= &cmdtab[NCMDS]) { 260 printf("\n"); 261 break; 262 } 263 w = strlen(c->c_name); 264 while (w < width) { 265 w = (w + 8) &~ 7; 266 putchar('\t'); 267 } 268 } 269 } 270 return; 271 } 272 while (--argc > 0) { 273 char *arg; 274 arg = *++argv; 275 c = getcmd(arg); 276 if (c == (struct cmd *)-1) 277 printf("?Ambiguous help command %s\n", arg); 278 else if (c == (struct cmd *)0) 279 printf("?Invalid help command %s\n", arg); 280 else 281 printf("%-*s\t%s\n", (int)HELPINDENT, 282 c->c_name, c->c_help); 283 } 284 } 285 286 /* 287 * return non-zero if the user is a member of the given group 288 */ 289 static int 290 ingroup(char *grname) 291 { 292 static struct group *gptr=NULL; 293 static gid_t groups[NGROUPS]; 294 static int ngroups; 295 gid_t gid; 296 int i; 297 298 if (gptr == NULL) { 299 if ((gptr = getgrnam(grname)) == NULL) { 300 warnx("Warning: unknown group `%s'", 301 grname); 302 return(0); 303 } 304 ngroups = getgroups(NGROUPS, groups); 305 if (ngroups < 0) 306 err(1, "getgroups"); 307 } 308 gid = gptr->gr_gid; 309 for (i = 0; i < ngroups; i++) 310 if (gid == groups[i]) 311 return(1); 312 return(0); 313 } 314