1: /*************************************************************************
2: * (C) 2009 AITNET - Sofia/Bulgaria - <office@aitbg.com>
3: * by Michael Pounov <misho@aitbg.com>
4: *
5: * $Author: misho $
6: * $Id: cfexec.c,v 1.4.2.3 2014/01/30 01:03:21 misho Exp $
7: *
8: *************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
15: Copyright 2004 - 2014
16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
46: #include "global.h"
47:
48:
49: cfg_root_t cfg;
50: int Verbose, Timeout, kq;
51: ait_val_t User, Mount, Dev, Chroot;
52: char szSess[MAXPATHLEN], szConfig[MAXPATHLEN];
53: extern char compiled[], compiledby[], compilehost[];
54:
55:
56: static void
57: Usage()
58: {
59:
60: printf( "CFExec is tool for managment R/W operation with CompactFlash\n"
61: "=== %s === %s@%s ===\n\n"
62: " Syntax: cfexec [options] [exec_file]\n\n"
63: "\t-v\t\tVerbose ...\n"
64: "\t-c <dir>\tAfter execute chroot to dir [default=/]\n"
65: "\t-u <user>\tAfter execute suid to user [default=root]\n"
66: "\t-d <dev>\tOther device [default=/dev/ufs/elwix]\n"
67: "\t-m <mnt>\tOther mount dir [default=/]\n"
68: "\t-t <sec>\tTimeout for autolock mount dir after seconds [default=300]\n"
69: "\n", compiled, compiledby, compilehost);
70: }
71:
72: static int
73: update(int flags)
74: {
75: struct ufs_args mnt;
76:
77: memset(&mnt, 0, sizeof mnt);
78: mnt.fspec = AIT_GET_STR(&Dev);
79: #ifdef __NetBSD__
80: if (mount("ufs", AIT_GET_STR(&Mount), flags, &mnt, sizeof mnt) == -1) {
81: #else
82: if (mount("ufs", AIT_GET_STR(&Mount), flags, &mnt) == -1) {
83: #endif
84: printf("Error:: can`t update mount %s #%d - %s\n", AIT_GET_STR(&Mount),
85: errno, strerror(errno));
86: return -1;
87: }
88:
89: VERB(5) printf("Info(5):: safe mount for device %s to %s operation (%s)\n",
90: AIT_GET_STR(&Dev), AIT_GET_STR(&Mount), (flags & MNT_RDONLY) ? "ro" : "rw");
91: return 0;
92: }
93:
94: static void
95: setuser()
96: {
97: struct passwd *pw;
98:
99: pw = getpwnam(AIT_GET_LIKE(&User, char*));
100: if (pw) {
101: setuid(pw->pw_uid);
102: setgid(pw->pw_gid);
103: endpwent();
104:
105: VERB(5) printf("Info(5):: Suid to user %s.\n", AIT_GET_STR(&User));
106: } else
107: VERB(5) printf("Info(5):: Can`t suid to user %s !\n", AIT_GET_STR(&User));
108: }
109:
110: static int
111: mkevent(struct kevent *chg, struct kevent *evt)
112: {
113: int f;
114: char szStr[STRSIZ];
115:
116: f = open(szSess, O_CREAT | O_WRONLY | O_TRUNC, 0644);
117: if (f == -1) {
118: printf("Error:: can`t lock session #%d - %s\n", errno, strerror(errno));
119: return -1;
120: } else {
121: memset(szStr, 0, sizeof szStr);
122: snprintf(szStr, sizeof szStr, "%d", getpid());
123: write(f, szStr, strlen(szStr));
124: }
125: VERB(3) printf("Created lock file %s\n", szSess);
126:
127: kq = kqueue();
128: if (kq == -1) {
129: printf("Error:: can`t execute safe mount #%d - %s\n", errno, strerror(errno));
130: close(f);
131: unlink(szSess);
132: return -1;
133: } else {
134: memset(chg, 0, sizeof(struct kevent));
135: memset(evt, 0, sizeof(struct kevent));
136:
137: EV_SET(chg, f, EVFILT_VNODE, EV_ADD, NOTE_DELETE | NOTE_RENAME | NOTE_REVOKE,
138: 0, NULL);
139: }
140:
141: return f;
142: }
143:
144: static void
145: cleanexit()
146: {
147: AIT_FREE_VAL(&User);
148: AIT_FREE_VAL(&Dev);
149: AIT_FREE_VAL(&Mount);
150: AIT_FREE_VAL(&Chroot);
151:
152: cfgUnloadConfig(&cfg);
153: }
154:
155:
156: int
157: main(int argc, char **argv)
158: {
159: char ch;
160: const char *err = NULL;
161: struct kevent chg, evt;
162: struct timespec ts;
163: pid_t pid;
164: int f, stat = 0;
165:
166: strlcpy(szConfig, DEFAULT_CONFIG, MAXPATHLEN);
167: /* Load variables from config if exists */
168: if (!cfgLoadConfig(szConfig, &cfg)) {
169: cfg_loadAttribute(&cfg, "cfexec", "timeout", &User, DEFAULT_TIMEOUT);
170: #ifndef HAVE_STRTONUM
171: Timeout = (int) strtol(szUser, NULL, 0);
172: #else
173: Timeout = strtonum(AIT_GET_STR(&User), 0, 3600, &err);
174: #endif
175: AIT_FREE_VAL(&User);
176: if (!Timeout && err) {
177: printf("Error:: in seconds for timeout %s - %s\n", optarg, err);
178: cfgUnloadConfig(&cfg);
179: return 1;
180: }
181: cfg_loadAttribute(&cfg, "cfexec", "suid", &User, DEFAULT_USER);
182: cfg_loadAttribute(&cfg, "cfexec", "mount", &Mount, DEFAULT_MOUNT);
183: cfg_loadAttribute(&cfg, "cfexec", "device", &Dev, DEFAULT_DEVICE);
184: cfg_loadAttribute(&cfg, "cfexec", "chroot", &Chroot, DEFAULT_CHROOT);
185:
186: cfgUnloadConfig(&cfg);
187: } else {
188: Timeout = atoi(DEFAULT_TIMEOUT);
189: AIT_SET_STR(&User, DEFAULT_USER);
190: AIT_SET_STR(&Mount, DEFAULT_MOUNT);
191: AIT_SET_STR(&Dev, DEFAULT_DEVICE);
192: AIT_SET_STR(&Chroot, DEFAULT_CHROOT);
193: }
194:
195: atexit(cleanexit);
196:
197: /* Load variables from arguments if exists */
198: while ((ch = getopt(argc, argv, "hvu:c:d:m:t:")) != -1)
199: switch (ch) {
200: case 'v':
201: Verbose++;
202: break;
203: case 'u':
204: AIT_SET_STR(&User, optarg);
205: break;
206: case 'c':
207: AIT_SET_STR(&Chroot, optarg);
208: break;
209: case 'd':
210: AIT_SET_STR(&Dev, optarg);
211: break;
212: case 'm':
213: AIT_SET_STR(&Mount, optarg);
214: break;
215: case 't':
216: #ifndef HAVE_STRTONUM
217: Timeout = (int) strtol(optarg, NULL, 0);
218: #else
219: Timeout = strtonum(optarg, 0, 3600, &err);
220: #endif
221: if (!Timeout && err) {
222: printf("Error:: in seconds for timeout %s - %s\n",
223: optarg, err);
224: return 1;
225: }
226: break;
227: case 'h':
228: default:
229: Usage();
230: return 1;
231: }
232: argc -= optind;
233: argv += optind;
234:
235: memset(szSess, 0, MAXPATHLEN);
236: snprintf(szSess, MAXPATHLEN, "%s%s-cfexec.LCK", DEFAULT_TMP, AIT_GET_STR(&Mount));
237:
238: VERB(3) printf("Info(3):: Chroot=%s SUID=%s Device=%s Mount=%s Timeout=%d Session=%s\n",
239: AIT_GET_STR(&Chroot), AIT_GET_STR(&User), AIT_GET_STR(&Dev),
240: AIT_GET_STR(&Mount), Timeout, szSess);
241:
242: if (!access(szSess, F_OK)) {
243: printf("cfexec already running ...\n");
244: return 127;
245: }
246:
247: if (!argc) {
248: switch (fork()) {
249: case -1:
250: printf("Error:: can`t execute safe mount #%d - %s\n",
251: errno, strerror(errno));
252: return 3;
253: case 0:
254: VERB(5) printf("Info(5):: Go safe mount.\n");
255: setsid();
256:
257: if (update(MNT_UPDATE) == -1)
258: return 4;
259:
260: if ((f = mkevent(&chg, &evt)) == -1)
261: return 5;
262:
263: if (Timeout) {
264: memset(&ts, 0, sizeof ts);
265: ts.tv_sec = Timeout;
266: }
267: switch (kevent(kq, &chg, 1, &evt, 1, !Timeout ? NULL : &ts)) {
268: case -1:
269: printf("Error:: can`t execute safe mount #%d - %s\n",
270: errno, strerror(errno));
271: stat = 7;
272: break;
273: case 0:
274: VERB(1) printf("Timeout reached - secure mount\n");
275: default:
276: VERB(1) printf("Lock file is deleted - secure mount\n");
277: if (update(MNT_UPDATE | MNT_RDONLY) == -1)
278: stat = 8;
279: }
280:
281: close(kq);
282: close(f);
283: unlink(szSess);
284: break;
285: }
286: } else {
287: /*
288: sigemptyset(&sig);
289: sigaddset(&sig, SIGINT);
290: sigaddset(&sig, SIGTSTP);
291: sigprocmask(SIG_BLOCK, &sig, &oldsig);
292: */
293:
294: if (update(MNT_UPDATE) == -1)
295: return 4;
296:
297: switch ((pid = vfork())) {
298: case -1:
299: printf("Error:: can`t execute safe mount #%d - %s\n",
300: errno, strerror(errno));
301: return 5;
302: case 0:
303: VERB(5) printf("Go to running process %s\n", *argv);
304: if (chroot(AIT_GET_STR(&Chroot)) == -1) {
305: printf("Error:: can`t chroot to dir %s #%d - %s\n",
306: AIT_GET_STR(&Chroot), errno, strerror(errno));
307: } else {
308: if (strncmp(AIT_GET_STR(&User), "root", 5))
309: setuser();
310:
311: /* chdir("/"); */
312: execvp(*argv, argv);
313: }
314: exit(127);
315: break;
316: default:
317: waitpid(pid, &stat, 0);
318: VERB(3) printf("Return code: %d\n", stat);
319: if (stat == 32512)
320: stat = 127;
321:
322: if (update(MNT_UPDATE | MNT_RDONLY) == -1)
323: return 8;
324: }
325: }
326:
327: return stat;
328: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>