1 /* $NetBSD: timedc.c,v 1.19 2007/01/28 13:51:29 cbiere Exp $ */ 2 3 /*- 4 * Copyright (c) 1985, 1993 The Regents of the University of California. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __COPYRIGHT( 35 "@(#) Copyright (c) 1985, 1993 The Regents of the University of California.\n\ 36 All rights reserved.\n"); 37 #endif /* not lint */ 38 39 #ifndef lint 40 #if 0 41 static char sccsid[] = "@(#)timedc.c 8.1 (Berkeley) 6/6/93"; 42 #else 43 __RCSID("$NetBSD: timedc.c,v 1.19 2007/01/28 13:51:29 cbiere Exp $"); 44 #endif 45 #endif /* not lint */ 46 47 #include "timedc.h" 48 #include <ctype.h> 49 #include <setjmp.h> 50 #include <signal.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <syslog.h> 54 #include <unistd.h> 55 #include <fcntl.h> 56 #include <pwd.h> 57 #include <err.h> 58 59 int trace = 0; 60 FILE *fd = 0; 61 int margc; 62 int fromatty; 63 #define MAX_MARGV 20 64 char *margv[MAX_MARGV]; 65 char cmdline[200]; 66 jmp_buf toplevel; 67 static struct cmd *getcmd(char *); 68 static int drop_privileges(void); 69 70 int 71 main(int argc, char *argv[]) 72 { 73 struct cmd *c; 74 75 fcntl(3, F_CLOSEM); 76 openlog("timedc", 0, LOG_AUTH); 77 78 /* 79 * security dictates! 80 */ 81 if (priv_resources() < 0) 82 errx(EXIT_FAILURE, "Could not get privileged resources"); 83 if (drop_privileges() < 0) 84 errx(EXIT_FAILURE, "Could not drop privileges"); 85 86 if (--argc > 0) { 87 c = getcmd(*++argv); 88 if (c == (struct cmd *)-1) { 89 printf("?Ambiguous command\n"); 90 exit(EXIT_FAILURE); 91 } 92 if (c == 0) { 93 printf("?Invalid command\n"); 94 exit(EXIT_FAILURE); 95 } 96 (*c->c_handler)(argc, argv); 97 exit(EXIT_SUCCESS); 98 } 99 100 fromatty = isatty(fileno(stdin)); 101 if (setjmp(toplevel)) 102 putchar('\n'); 103 (void) signal(SIGINT, intr); 104 for (;;) { 105 if (fromatty) { 106 printf("timedc> "); 107 (void) fflush(stdout); 108 } 109 if (fgets(cmdline, sizeof(cmdline), stdin) == 0) 110 quit(0, NULL); 111 if (cmdline[0] == 0) 112 break; 113 if (makeargv()) { 114 printf("?Too many arguments\n"); 115 continue; 116 } 117 if (margv[0] == 0) 118 continue; 119 c = getcmd(margv[0]); 120 if (c == (struct cmd *)-1) { 121 printf("?Ambiguous command\n"); 122 continue; 123 } 124 if (c == 0) { 125 printf("?Invalid command\n"); 126 continue; 127 } 128 (*c->c_handler)(margc, margv); 129 } 130 return 0; 131 } 132 133 void 134 intr(int signo) 135 { 136 (void) signo; 137 if (!fromatty) 138 exit(EXIT_SUCCESS); 139 longjmp(toplevel, 1); 140 } 141 142 143 static struct cmd * 144 getcmd(char *name) 145 { 146 const char *p; 147 char *q; 148 struct cmd *c, *found; 149 int nmatches, longest; 150 extern struct cmd cmdtab[]; 151 extern int NCMDS; 152 153 longest = 0; 154 nmatches = 0; 155 found = 0; 156 for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { 157 p = c->c_name; 158 for (q = name; *q == *p++; q++) 159 if (*q == 0) /* exact match? */ 160 return(c); 161 if (!*q) { /* the name was a prefix */ 162 if (q - name > longest) { 163 longest = q - name; 164 nmatches = 1; 165 found = c; 166 } else if (q - name == longest) 167 nmatches++; 168 } 169 } 170 if (nmatches > 1) 171 return((struct cmd *)-1); 172 return(found); 173 } 174 175 /* 176 * Slice a string up into argc/argv. 177 */ 178 int 179 makeargv(void) 180 { 181 char *cp; 182 char **argp = margv; 183 184 margc = 0; 185 for (cp = cmdline; argp < &margv[MAX_MARGV - 1] && *cp;) { 186 while (isspace((unsigned char)*cp)) 187 cp++; 188 if (*cp == '\0') 189 break; 190 *argp++ = cp; 191 margc += 1; 192 while (*cp != '\0' && !isspace((unsigned char)*cp)) 193 cp++; 194 if (*cp == '\0') 195 break; 196 *cp++ = '\0'; 197 } 198 if (margc == MAX_MARGV - 1) 199 return 1; 200 *argp++ = 0; 201 return 0; 202 } 203 204 #define HELPINDENT (sizeof ("directory")) 205 206 /* 207 * Help command. 208 */ 209 void 210 help(int argc, char *argv[]) 211 { 212 struct cmd *c; 213 extern struct cmd cmdtab[]; 214 215 if (argc == 1) { 216 int i, j, w; 217 int columns, width = 0, lines; 218 extern int NCMDS; 219 220 printf("Commands may be abbreviated. Commands are:\n\n"); 221 for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { 222 int len = strlen(c->c_name); 223 224 if (len > width) 225 width = len; 226 } 227 width = (width + 8) &~ 7; 228 columns = 80 / width; 229 if (columns == 0) 230 columns = 1; 231 lines = (NCMDS + columns - 1) / columns; 232 for (i = 0; i < lines; i++) { 233 for (j = 0; j < columns; j++) { 234 c = cmdtab + j * lines + i; 235 printf("%s", c->c_name); 236 if (c + lines >= &cmdtab[NCMDS]) { 237 printf("\n"); 238 break; 239 } 240 w = strlen(c->c_name); 241 while (w < width) { 242 w = (w + 8) &~ 7; 243 putchar('\t'); 244 } 245 } 246 } 247 return; 248 } 249 while (--argc > 0) { 250 char *arg; 251 arg = *++argv; 252 c = getcmd(arg); 253 if (c == (struct cmd *)-1) 254 printf("?Ambiguous help command %s\n", arg); 255 else if (c == (struct cmd *)0) 256 printf("?Invalid help command %s\n", arg); 257 else 258 printf("%-*s\t%s\n", (int)HELPINDENT, 259 c->c_name, c->c_help); 260 } 261 } 262 263 static int 264 drop_privileges(void) 265 { 266 static const char user[] = "_timedc"; 267 const struct passwd *pw; 268 uid_t uid; 269 gid_t gid; 270 271 if ((pw = getpwnam(user)) == NULL) { 272 warnx("getpwnam(\"%s\") failed", user); 273 return -1; 274 } 275 uid = pw->pw_uid; 276 gid = pw->pw_gid; 277 if (setgroups(1, &gid)) { 278 warn("setgroups"); 279 return -1; 280 } 281 if (setgid(gid)) { 282 warn("setgid"); 283 return -1; 284 } 285 if (setuid(uid)) { 286 warn("setuid"); 287 return -1; 288 } 289 return 0; 290 } 291