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