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