1*7f5fd4a5Schristos /* $NetBSD: timedc.c,v 1.22 2012/01/16 17:38:16 christos Exp $ */
218b882a9Smrg
34bb7cfabScgd /*-
44bb7cfabScgd * Copyright (c) 1985, 1993 The Regents of the University of California.
5e9d867efSmycroft * All rights reserved.
661f28255Scgd *
761f28255Scgd * Redistribution and use in source and binary forms, with or without
861f28255Scgd * modification, are permitted provided that the following conditions
961f28255Scgd * are met:
1061f28255Scgd * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd * notice, this list of conditions and the following disclaimer.
1261f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd * notice, this list of conditions and the following disclaimer in the
1461f28255Scgd * documentation and/or other materials provided with the distribution.
15326b2259Sagc * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd * may be used to endorse or promote products derived from this software
1761f28255Scgd * without specific prior written permission.
1861f28255Scgd *
1961f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd * SUCH DAMAGE.
3061f28255Scgd */
3161f28255Scgd
3231bc9c50Slukem #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
349c194566Slukem __COPYRIGHT("@(#) Copyright (c) 1985, 1993\
359c194566Slukem The Regents of the University of California. All rights reserved.");
3661f28255Scgd #endif /* not lint */
3761f28255Scgd
3861f28255Scgd #ifndef lint
3931bc9c50Slukem #if 0
4018b882a9Smrg static char sccsid[] = "@(#)timedc.c 8.1 (Berkeley) 6/6/93";
4131bc9c50Slukem #else
42*7f5fd4a5Schristos __RCSID("$NetBSD: timedc.c,v 1.22 2012/01/16 17:38:16 christos Exp $");
4331bc9c50Slukem #endif
4461f28255Scgd #endif /* not lint */
4561f28255Scgd
4661f28255Scgd #include "timedc.h"
4761f28255Scgd #include <ctype.h>
4861f28255Scgd #include <setjmp.h>
499f6ff4adSlukem #include <signal.h>
504bb7cfabScgd #include <stdlib.h>
519f6ff4adSlukem #include <string.h>
5261f28255Scgd #include <syslog.h>
539f6ff4adSlukem #include <unistd.h>
540f2ebef2Scbiere #include <fcntl.h>
550f2ebef2Scbiere #include <pwd.h>
5606fe4f26Schristos #include <err.h>
5761f28255Scgd
584bb7cfabScgd int trace = 0;
594bb7cfabScgd FILE *fd = 0;
6061f28255Scgd int margc;
6161f28255Scgd int fromatty;
6291223596Sitojun #define MAX_MARGV 20
6391223596Sitojun char *margv[MAX_MARGV];
6461f28255Scgd char cmdline[200];
6561f28255Scgd jmp_buf toplevel;
66de8753b3Smatt static const struct cmd *getcmd(char *);
670f2ebef2Scbiere static int drop_privileges(void);
6861f28255Scgd
694bb7cfabScgd int
main(int argc,char * argv[])704bb7cfabScgd main(int argc, char *argv[])
7161f28255Scgd {
72de8753b3Smatt const struct cmd *c;
7361f28255Scgd
740f2ebef2Scbiere fcntl(3, F_CLOSEM);
7530724dbaSlukem openlog("timedc", 0, LOG_AUTH);
7661f28255Scgd
7761f28255Scgd /*
7861f28255Scgd * security dictates!
7961f28255Scgd */
8006fe4f26Schristos if (priv_resources() < 0)
8128ea2557Scbiere errx(EXIT_FAILURE, "Could not get privileged resources");
820f2ebef2Scbiere if (drop_privileges() < 0)
8328ea2557Scbiere errx(EXIT_FAILURE, "Could not drop privileges");
8461f28255Scgd
8561f28255Scgd if (--argc > 0) {
8661f28255Scgd c = getcmd(*++argv);
8761f28255Scgd if (c == (struct cmd *)-1) {
8861f28255Scgd printf("?Ambiguous command\n");
8928ea2557Scbiere exit(EXIT_FAILURE);
9061f28255Scgd }
9161f28255Scgd if (c == 0) {
9261f28255Scgd printf("?Invalid command\n");
9328ea2557Scbiere exit(EXIT_FAILURE);
9461f28255Scgd }
9561f28255Scgd (*c->c_handler)(argc, argv);
9628ea2557Scbiere exit(EXIT_SUCCESS);
9761f28255Scgd }
984bb7cfabScgd
9961f28255Scgd fromatty = isatty(fileno(stdin));
1004bb7cfabScgd if (setjmp(toplevel))
101e9d867efSmycroft putchar('\n');
1024bb7cfabScgd (void) signal(SIGINT, intr);
103e9d867efSmycroft for (;;) {
10461f28255Scgd if (fromatty) {
10561f28255Scgd printf("timedc> ");
10661f28255Scgd (void) fflush(stdout);
10761f28255Scgd }
108*7f5fd4a5Schristos if (fgets(cmdline, sizeof(cmdline), stdin) == NULL)
10931bc9c50Slukem quit(0, NULL);
11061f28255Scgd if (cmdline[0] == 0)
11161f28255Scgd break;
11291223596Sitojun if (makeargv()) {
11391223596Sitojun printf("?Too many arguments\n");
11491223596Sitojun continue;
11591223596Sitojun }
1164bb7cfabScgd if (margv[0] == 0)
1174bb7cfabScgd continue;
11861f28255Scgd c = getcmd(margv[0]);
11961f28255Scgd if (c == (struct cmd *)-1) {
12061f28255Scgd printf("?Ambiguous command\n");
12161f28255Scgd continue;
12261f28255Scgd }
12361f28255Scgd if (c == 0) {
12461f28255Scgd printf("?Invalid command\n");
12561f28255Scgd continue;
12661f28255Scgd }
12761f28255Scgd (*c->c_handler)(margc, margv);
12861f28255Scgd }
1294bb7cfabScgd return 0;
13061f28255Scgd }
13161f28255Scgd
1324bb7cfabScgd void
intr(int signo)133557fe0a8Swiz intr(int signo)
1344bb7cfabScgd {
13507c9d403Scbiere (void) signo;
1364bb7cfabScgd if (!fromatty)
13728ea2557Scbiere exit(EXIT_SUCCESS);
1384bb7cfabScgd longjmp(toplevel, 1);
1394bb7cfabScgd }
1404bb7cfabScgd
1414bb7cfabScgd
142de8753b3Smatt static const struct cmd *
getcmd(char * name)1434bb7cfabScgd getcmd(char *name)
14461f28255Scgd {
145b772b1e8Schristos const char *p;
146b772b1e8Schristos char *q;
147de8753b3Smatt const struct cmd *c, *found;
1489cdb3cafSperry int nmatches, longest;
149de8753b3Smatt extern const struct cmd cmdtab[];
15061f28255Scgd extern int NCMDS;
15161f28255Scgd
15261f28255Scgd longest = 0;
15361f28255Scgd nmatches = 0;
15461f28255Scgd found = 0;
15561f28255Scgd for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
15661f28255Scgd p = c->c_name;
15761f28255Scgd for (q = name; *q == *p++; q++)
15861f28255Scgd if (*q == 0) /* exact match? */
15961f28255Scgd return(c);
16061f28255Scgd if (!*q) { /* the name was a prefix */
16161f28255Scgd if (q - name > longest) {
16261f28255Scgd longest = q - name;
16361f28255Scgd nmatches = 1;
16461f28255Scgd found = c;
16561f28255Scgd } else if (q - name == longest)
16661f28255Scgd nmatches++;
16761f28255Scgd }
16861f28255Scgd }
16961f28255Scgd if (nmatches > 1)
17061f28255Scgd return((struct cmd *)-1);
17161f28255Scgd return(found);
17261f28255Scgd }
17361f28255Scgd
17461f28255Scgd /*
17561f28255Scgd * Slice a string up into argc/argv.
17661f28255Scgd */
17791223596Sitojun int
makeargv(void)178557fe0a8Swiz makeargv(void)
17961f28255Scgd {
1809cdb3cafSperry char *cp;
1819cdb3cafSperry char **argp = margv;
18261f28255Scgd
18361f28255Scgd margc = 0;
1848852dbf5Schristos for (cp = cmdline; argp < &margv[MAX_MARGV - 1] && *cp;) {
1853cca093eSdsl while (isspace((unsigned char)*cp))
18661f28255Scgd cp++;
18761f28255Scgd if (*cp == '\0')
18861f28255Scgd break;
18961f28255Scgd *argp++ = cp;
19061f28255Scgd margc += 1;
1913cca093eSdsl while (*cp != '\0' && !isspace((unsigned char)*cp))
19261f28255Scgd cp++;
19361f28255Scgd if (*cp == '\0')
19461f28255Scgd break;
19561f28255Scgd *cp++ = '\0';
19661f28255Scgd }
19791223596Sitojun if (margc == MAX_MARGV - 1)
19891223596Sitojun return 1;
19961f28255Scgd *argp++ = 0;
20091223596Sitojun return 0;
20161f28255Scgd }
20261f28255Scgd
20361f28255Scgd #define HELPINDENT (sizeof ("directory"))
20461f28255Scgd
20561f28255Scgd /*
20661f28255Scgd * Help command.
20761f28255Scgd */
2084bb7cfabScgd void
help(int argc,char * argv[])209557fe0a8Swiz help(int argc, char *argv[])
21061f28255Scgd {
211de8753b3Smatt const struct cmd *c;
212de8753b3Smatt extern const struct cmd cmdtab[];
21361f28255Scgd
21461f28255Scgd if (argc == 1) {
2159cdb3cafSperry int i, j, w;
21661f28255Scgd int columns, width = 0, lines;
21761f28255Scgd extern int NCMDS;
21861f28255Scgd
21961f28255Scgd printf("Commands may be abbreviated. Commands are:\n\n");
22061f28255Scgd for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
22161f28255Scgd int len = strlen(c->c_name);
22261f28255Scgd
22361f28255Scgd if (len > width)
22461f28255Scgd width = len;
22561f28255Scgd }
22661f28255Scgd width = (width + 8) &~ 7;
22761f28255Scgd columns = 80 / width;
22861f28255Scgd if (columns == 0)
22961f28255Scgd columns = 1;
23061f28255Scgd lines = (NCMDS + columns - 1) / columns;
23161f28255Scgd for (i = 0; i < lines; i++) {
23261f28255Scgd for (j = 0; j < columns; j++) {
23361f28255Scgd c = cmdtab + j * lines + i;
23461f28255Scgd printf("%s", c->c_name);
23561f28255Scgd if (c + lines >= &cmdtab[NCMDS]) {
23661f28255Scgd printf("\n");
23761f28255Scgd break;
23861f28255Scgd }
23961f28255Scgd w = strlen(c->c_name);
24061f28255Scgd while (w < width) {
24161f28255Scgd w = (w + 8) &~ 7;
24261f28255Scgd putchar('\t');
24361f28255Scgd }
24461f28255Scgd }
24561f28255Scgd }
24661f28255Scgd return;
24761f28255Scgd }
24861f28255Scgd while (--argc > 0) {
2499cdb3cafSperry char *arg;
25061f28255Scgd arg = *++argv;
25161f28255Scgd c = getcmd(arg);
25261f28255Scgd if (c == (struct cmd *)-1)
25361f28255Scgd printf("?Ambiguous help command %s\n", arg);
25461f28255Scgd else if (c == (struct cmd *)0)
25561f28255Scgd printf("?Invalid help command %s\n", arg);
25661f28255Scgd else
2574bb7cfabScgd printf("%-*s\t%s\n", (int)HELPINDENT,
25861f28255Scgd c->c_name, c->c_help);
25961f28255Scgd }
26061f28255Scgd }
2610f2ebef2Scbiere
2620f2ebef2Scbiere static int
drop_privileges(void)2630f2ebef2Scbiere drop_privileges(void)
2640f2ebef2Scbiere {
26528ea2557Scbiere static const char user[] = "_timedc";
2660f2ebef2Scbiere const struct passwd *pw;
2670f2ebef2Scbiere uid_t uid;
2680f2ebef2Scbiere gid_t gid;
2690f2ebef2Scbiere
27028ea2557Scbiere if ((pw = getpwnam(user)) == NULL) {
27128ea2557Scbiere warnx("getpwnam(\"%s\") failed", user);
2720f2ebef2Scbiere return -1;
2730f2ebef2Scbiere }
2740f2ebef2Scbiere uid = pw->pw_uid;
2750f2ebef2Scbiere gid = pw->pw_gid;
2760f2ebef2Scbiere if (setgroups(1, &gid)) {
2770f2ebef2Scbiere warn("setgroups");
2780f2ebef2Scbiere return -1;
2790f2ebef2Scbiere }
2800f2ebef2Scbiere if (setgid(gid)) {
2810f2ebef2Scbiere warn("setgid");
2820f2ebef2Scbiere return -1;
2830f2ebef2Scbiere }
2840f2ebef2Scbiere if (setuid(uid)) {
2850f2ebef2Scbiere warn("setuid");
2860f2ebef2Scbiere return -1;
2870f2ebef2Scbiere }
2880f2ebef2Scbiere return 0;
2890f2ebef2Scbiere }
290