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