1 /*        $NetBSD: timedc.c,v 1.22 2012/01/16 17:38:16 christos 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("@(#) Copyright (c) 1985, 1993\
35  The Regents of the University of California.  All rights reserved.");
36 #endif /* not lint */
37 
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)timedc.c    8.1 (Berkeley) 6/6/93";
41 #else
42 __RCSID("$NetBSD: timedc.c,v 1.22 2012/01/16 17:38:16 christos Exp $");
43 #endif
44 #endif /* not lint */
45 
46 #include "timedc.h"
47 #include <ctype.h>
48 #include <setjmp.h>
49 #include <signal.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <syslog.h>
53 #include <unistd.h>
54 #include <fcntl.h>
55 #include <pwd.h>
56 #include <err.h>
57 
58 int trace = 0;
59 FILE *fd = 0;
60 int       margc;
61 int       fromatty;
62 #define MAX_MARGV   20
63 char      *margv[MAX_MARGV];
64 char      cmdline[200];
65 jmp_buf   toplevel;
66 static const struct cmd *getcmd(char *);
67 static int drop_privileges(void);
68 
69 int
main(int argc,char * argv[])70 main(int argc, char *argv[])
71 {
72           const struct cmd *c;
73 
74           fcntl(3, F_CLOSEM);
75           openlog("timedc", 0, LOG_AUTH);
76 
77           /*
78            * security dictates!
79            */
80           if (priv_resources() < 0)
81                     errx(EXIT_FAILURE, "Could not get privileged resources");
82           if (drop_privileges() < 0)
83                     errx(EXIT_FAILURE, "Could not drop privileges");
84 
85           if (--argc > 0) {
86                     c = getcmd(*++argv);
87                     if (c == (struct cmd *)-1) {
88                               printf("?Ambiguous command\n");
89                               exit(EXIT_FAILURE);
90                     }
91                     if (c == 0) {
92                               printf("?Invalid command\n");
93                               exit(EXIT_FAILURE);
94                     }
95                     (*c->c_handler)(argc, argv);
96                     exit(EXIT_SUCCESS);
97           }
98 
99           fromatty = isatty(fileno(stdin));
100           if (setjmp(toplevel))
101                     putchar('\n');
102           (void) signal(SIGINT, intr);
103           for (;;) {
104                     if (fromatty) {
105                               printf("timedc> ");
106                               (void) fflush(stdout);
107                     }
108                     if (fgets(cmdline, sizeof(cmdline), stdin) == NULL)
109                               quit(0, NULL);
110                     if (cmdline[0] == 0)
111                               break;
112                     if (makeargv()) {
113                               printf("?Too many arguments\n");
114                               continue;
115                     }
116                     if (margv[0] == 0)
117                               continue;
118                     c = getcmd(margv[0]);
119                     if (c == (struct cmd *)-1) {
120                               printf("?Ambiguous command\n");
121                               continue;
122                     }
123                     if (c == 0) {
124                               printf("?Invalid command\n");
125                               continue;
126                     }
127                     (*c->c_handler)(margc, margv);
128           }
129           return 0;
130 }
131 
132 void
intr(int signo)133 intr(int signo)
134 {
135           (void) signo;
136           if (!fromatty)
137                     exit(EXIT_SUCCESS);
138           longjmp(toplevel, 1);
139 }
140 
141 
142 static const struct cmd *
getcmd(char * name)143 getcmd(char *name)
144 {
145           const char *p;
146           char *q;
147           const struct cmd *c, *found;
148           int nmatches, longest;
149           extern const struct cmd cmdtab[];
150           extern int NCMDS;
151 
152           longest = 0;
153           nmatches = 0;
154           found = 0;
155           for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
156                     p = c->c_name;
157                     for (q = name; *q == *p++; q++)
158                               if (*q == 0)                  /* exact match? */
159                                         return(c);
160                     if (!*q) {                              /* the name was a prefix */
161                               if (q - name > longest) {
162                                         longest = q - name;
163                                         nmatches = 1;
164                                         found = c;
165                               } else if (q - name == longest)
166                                         nmatches++;
167                     }
168           }
169           if (nmatches > 1)
170                     return((struct cmd *)-1);
171           return(found);
172 }
173 
174 /*
175  * Slice a string up into argc/argv.
176  */
177 int
makeargv(void)178 makeargv(void)
179 {
180           char *cp;
181           char **argp = margv;
182 
183           margc = 0;
184           for (cp = cmdline; argp < &margv[MAX_MARGV - 1] && *cp;) {
185                     while (isspace((unsigned char)*cp))
186                               cp++;
187                     if (*cp == '\0')
188                               break;
189                     *argp++ = cp;
190                     margc += 1;
191                     while (*cp != '\0' && !isspace((unsigned char)*cp))
192                               cp++;
193                     if (*cp == '\0')
194                               break;
195                     *cp++ = '\0';
196           }
197           if (margc == MAX_MARGV - 1)
198                     return 1;
199           *argp++ = 0;
200           return 0;
201 }
202 
203 #define HELPINDENT (sizeof ("directory"))
204 
205 /*
206  * Help command.
207  */
208 void
help(int argc,char * argv[])209 help(int argc, char *argv[])
210 {
211           const struct cmd *c;
212           extern const struct cmd cmdtab[];
213 
214           if (argc == 1) {
215                     int i, j, w;
216                     int columns, width = 0, lines;
217                     extern int NCMDS;
218 
219                     printf("Commands may be abbreviated.  Commands are:\n\n");
220                     for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
221                               int len = strlen(c->c_name);
222 
223                               if (len > width)
224                                         width = len;
225                     }
226                     width = (width + 8) &~ 7;
227                     columns = 80 / width;
228                     if (columns == 0)
229                               columns = 1;
230                     lines = (NCMDS + columns - 1) / columns;
231                     for (i = 0; i < lines; i++) {
232                               for (j = 0; j < columns; j++) {
233                                         c = cmdtab + j * lines + i;
234                                         printf("%s", c->c_name);
235                                         if (c + lines >= &cmdtab[NCMDS]) {
236                                                   printf("\n");
237                                                   break;
238                                         }
239                                         w = strlen(c->c_name);
240                                         while (w < width) {
241                                                   w = (w + 8) &~ 7;
242                                                   putchar('\t');
243                                         }
244                               }
245                     }
246                     return;
247           }
248           while (--argc > 0) {
249                     char *arg;
250                     arg = *++argv;
251                     c = getcmd(arg);
252                     if (c == (struct cmd *)-1)
253                               printf("?Ambiguous help command %s\n", arg);
254                     else if (c == (struct cmd *)0)
255                               printf("?Invalid help command %s\n", arg);
256                     else
257                               printf("%-*s\t%s\n", (int)HELPINDENT,
258                                         c->c_name, c->c_help);
259           }
260 }
261 
262 static int
drop_privileges(void)263 drop_privileges(void)
264 {
265           static const char user[] = "_timedc";
266           const struct passwd *pw;
267           uid_t uid;
268           gid_t gid;
269 
270           if ((pw = getpwnam(user)) == NULL) {
271                     warnx("getpwnam(\"%s\") failed", user);
272                     return -1;
273           }
274           uid = pw->pw_uid;
275           gid = pw->pw_gid;
276           if (setgroups(1, &gid)) {
277                     warn("setgroups");
278                     return -1;
279           }
280           if (setgid(gid)) {
281                     warn("setgid");
282                     return -1;
283           }
284           if (setuid(uid)) {
285                     warn("setuid");
286                     return -1;
287           }
288           return 0;
289 }
290