1 /* $OpenBSD: lpc.c,v 1.18 2009/10/27 23:59:52 deraadt 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 #include <sys/param.h> 35 36 #include <dirent.h> 37 #include <signal.h> 38 #include <syslog.h> 39 #include <unistd.h> 40 #include <stdlib.h> 41 #include <stdio.h> 42 #include <err.h> 43 #include <errno.h> 44 #include <ctype.h> 45 #include <string.h> 46 #include <grp.h> 47 48 #include "lp.h" 49 #include "lpc.h" 50 #include "extern.h" 51 52 #ifndef LPR_OPER 53 #define LPR_OPER "operator" /* group name of lpr operators */ 54 #endif 55 56 /* 57 * lpc -- line printer control program 58 */ 59 60 #define MAX_CMDLINE 200 61 #define MAX_MARGV 20 62 int fromatty; 63 64 char cmdline[MAX_CMDLINE]; 65 int margc; 66 char *margv[MAX_MARGV]; 67 68 static void cmdscanner(void); 69 static struct cmd *getcmd(char *); 70 static void intr(int); 71 static void makeargv(void); 72 static int ingroup(char *); 73 74 int 75 main(int argc, char **argv) 76 { 77 struct cmd *c; 78 79 effective_uid = geteuid(); 80 real_uid = getuid(); 81 effective_gid = getegid(); 82 real_gid = getgid(); 83 PRIV_END; /* be safe */ 84 85 openlog("lpc", 0, LOG_LPR); 86 if (--argc > 0) { 87 c = getcmd(*++argv); 88 if (c == (struct cmd *)-1) { 89 printf("?Ambiguous command\n"); 90 exit(1); 91 } 92 if (c == 0) { 93 printf("?Invalid command\n"); 94 exit(1); 95 } 96 if (c->c_priv && real_uid && ingroup(LPR_OPER) == 0) { 97 printf("?Privileged command\n"); 98 exit(1); 99 } 100 (*c->c_handler)(argc, argv); 101 exit(0); 102 } 103 fromatty = isatty(fileno(stdin)); 104 signal(SIGINT, intr); 105 for (;;) 106 cmdscanner(); 107 } 108 109 volatile sig_atomic_t gotintr; 110 111 static void 112 intr(int signo) 113 { 114 if (!fromatty) 115 _exit(0); 116 gotintr = 1; 117 } 118 119 /* 120 * Command parser. 121 */ 122 static void 123 cmdscanner(void) 124 { 125 struct cmd *c; 126 127 for (;;) { 128 if (gotintr) { 129 putchar('\n'); 130 gotintr = 0; 131 } 132 if (fromatty) { 133 printf("lpc> "); 134 fflush(stdout); 135 } 136 137 siginterrupt(SIGINT, 1); 138 if (fgets(cmdline, MAX_CMDLINE, stdin) == NULL) { 139 if (errno == EINTR && gotintr) { 140 siginterrupt(SIGINT, 0); 141 return; 142 } 143 siginterrupt(SIGINT, 0); 144 quit(0, NULL); 145 } 146 siginterrupt(SIGINT, 0); 147 148 makeargv(); 149 if (margc == 0) 150 break; 151 c = getcmd(margv[0]); 152 if (c == (struct cmd *)-1) { 153 printf("?Ambiguous command\n"); 154 continue; 155 } 156 if (c == 0) { 157 printf("?Invalid command\n"); 158 continue; 159 } 160 if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) { 161 printf("?Privileged command\n"); 162 continue; 163 } 164 (*c->c_handler)(margc, margv); 165 } 166 } 167 168 static struct cmd * 169 getcmd(char *name) 170 { 171 char *p, *q; 172 struct cmd *c, *found; 173 int nmatches, longest; 174 175 longest = 0; 176 nmatches = 0; 177 found = 0; 178 for (c = cmdtab; (p = c->c_name) != NULL; c++) { 179 for (q = name; *q == *p++; q++) 180 if (*q == 0) /* exact match? */ 181 return(c); 182 if (!*q) { /* the name was a prefix */ 183 if (q - name > longest) { 184 longest = q - name; 185 nmatches = 1; 186 found = c; 187 } else if (q - name == longest) 188 nmatches++; 189 } 190 } 191 if (nmatches > 1) 192 return((struct cmd *)-1); 193 return(found); 194 } 195 196 /* 197 * Slice a string up into argc/argv. 198 */ 199 static void 200 makeargv(void) 201 { 202 char *cp = cmdline; 203 char **ap = margv; 204 205 margc = 0; 206 while (margc < MAX_MARGV - 1 && (*ap = strsep(&cp, " \t\n")) != NULL) { 207 if (**ap != '\0') { 208 ap++; 209 margc++; 210 } 211 } 212 *ap = NULL; 213 } 214 215 #define HELPINDENT ((int)sizeof("directory")) 216 217 /* 218 * Help command. 219 */ 220 void 221 help(int argc, char **argv) 222 { 223 struct cmd *c; 224 225 if (argc == 1) { 226 int i, j, w; 227 int columns, width = 0, lines; 228 229 printf("Commands may be abbreviated. Commands are:\n\n"); 230 for (c = cmdtab; c->c_name; c++) { 231 int len = strlen(c->c_name); 232 233 if (len > width) 234 width = len; 235 } 236 width = (width + 8) &~ 7; 237 columns = 80 / width; 238 if (columns == 0) 239 columns = 1; 240 lines = (NCMDS + columns - 1) / columns; 241 for (i = 0; i < lines; i++) { 242 for (j = 0; j < columns; j++) { 243 c = cmdtab + j * lines + i; 244 if (c->c_name) 245 printf("%s", c->c_name); 246 if (c + lines >= &cmdtab[NCMDS]) { 247 printf("\n"); 248 break; 249 } 250 w = strlen(c->c_name); 251 while (w < width) { 252 w = (w + 8) &~ 7; 253 putchar('\t'); 254 } 255 } 256 } 257 return; 258 } 259 while (--argc > 0) { 260 char *arg; 261 262 arg = *++argv; 263 c = getcmd(arg); 264 if (c == (struct cmd *)-1) 265 printf("?Ambiguous help command %s\n", arg); 266 else if (c == (struct cmd *)0) 267 printf("?Invalid help command %s\n", arg); 268 else 269 printf("%-*s\t%s\n", HELPINDENT, 270 c->c_name, c->c_help); 271 } 272 } 273 274 /* 275 * return non-zero if the user is a member of the given group 276 */ 277 static int 278 ingroup(char *grname) 279 { 280 static struct group *gptr = NULL; 281 static gid_t groups[NGROUPS]; 282 static int ngroups; 283 gid_t gid; 284 int i; 285 286 if (gptr == NULL) { 287 if ((gptr = getgrnam(grname)) == NULL) { 288 warnx("Warning: unknown group `%s'", grname); 289 return(0); 290 } 291 if ((ngroups = getgroups(NGROUPS, groups)) < 0) 292 err(1, "getgroups"); 293 } 294 gid = gptr->gr_gid; 295 for (i = 0; i < ngroups; i++) 296 if (gid == groups[i]) 297 return(1); 298 return(0); 299 } 300