Annotation of embedtools/src/cfexec.c, revision 1.5.20.5
1.1 misho 1: /*************************************************************************
2: * (C) 2009 AITNET - Sofia/Bulgaria - <office@aitbg.com>
3: * by Michael Pounov <misho@aitbg.com>
4: *
5: * $Author: misho $
1.5.20.5! misho 6: * $Id: cfexec.c,v 1.5.20.4 2017/10/08 22:31:25 misho Exp $
1.1 misho 7: *
1.3 misho 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:
1.5.20.1 misho 15: Copyright 2004 - 2017
1.3 misho 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: */
1.1 misho 46: #include "global.h"
47:
48:
1.3 misho 49: cfg_root_t cfg;
1.1 misho 50: int Verbose, Timeout, kq;
1.3 misho 51: ait_val_t User, Mount, Dev, Chroot;
1.5.20.1 misho 52: char szSess[MAXPATHLEN], szSLCK[MAXPATHLEN], szConfig[MAXPATHLEN];
1.1 misho 53: extern char compiled[], compiledby[], compilehost[];
54:
1.2 misho 55:
1.3 misho 56: static void
57: Usage()
1.1 misho 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"
1.2 misho 66: "\t-d <dev>\tOther device [default=/dev/ufs/elwix]\n"
1.5 misho 67: "\t-m <mnt>\tOther mount dir [default=/]\n"
1.1 misho 68: "\t-t <sec>\tTimeout for autolock mount dir after seconds [default=300]\n"
1.5.20.2 misho 69: "\t-L <reason>\tService lock and set RW state of device with reason\n"
70: "\t-U \t\tService unlock and set RO state of device\n"
1.1 misho 71: "\n", compiled, compiledby, compilehost);
72: }
73:
1.3 misho 74: static int
75: update(int flags)
1.1 misho 76: {
77: struct ufs_args mnt;
78:
79: memset(&mnt, 0, sizeof mnt);
1.3 misho 80: mnt.fspec = AIT_GET_STR(&Dev);
81: #ifdef __NetBSD__
82: if (mount("ufs", AIT_GET_STR(&Mount), flags, &mnt, sizeof mnt) == -1) {
83: #else
84: if (mount("ufs", AIT_GET_STR(&Mount), flags, &mnt) == -1) {
85: #endif
86: printf("Error:: can`t update mount %s #%d - %s\n", AIT_GET_STR(&Mount),
87: errno, strerror(errno));
1.1 misho 88: return -1;
89: }
90:
91: VERB(5) printf("Info(5):: safe mount for device %s to %s operation (%s)\n",
1.3 misho 92: AIT_GET_STR(&Dev), AIT_GET_STR(&Mount), (flags & MNT_RDONLY) ? "ro" : "rw");
1.1 misho 93: return 0;
94: }
95:
1.3 misho 96: static void
97: setuser()
1.1 misho 98: {
99: struct passwd *pw;
100:
1.3 misho 101: pw = getpwnam(AIT_GET_LIKE(&User, char*));
1.1 misho 102: if (pw) {
103: setuid(pw->pw_uid);
104: setgid(pw->pw_gid);
105: endpwent();
106:
1.3 misho 107: VERB(5) printf("Info(5):: Suid to user %s.\n", AIT_GET_STR(&User));
1.1 misho 108: } else
1.3 misho 109: VERB(5) printf("Info(5):: Can`t suid to user %s !\n", AIT_GET_STR(&User));
1.1 misho 110: }
111:
1.3 misho 112: static int
113: mkevent(struct kevent *chg, struct kevent *evt)
1.1 misho 114: {
115: int f;
1.4 misho 116: char szStr[STRSIZ];
1.1 misho 117:
118: f = open(szSess, O_CREAT | O_WRONLY | O_TRUNC, 0644);
119: if (f == -1) {
120: printf("Error:: can`t lock session #%d - %s\n", errno, strerror(errno));
121: return -1;
122: } else {
1.4 misho 123: memset(szStr, 0, sizeof szStr);
124: snprintf(szStr, sizeof szStr, "%d", getpid());
1.1 misho 125: write(f, szStr, strlen(szStr));
126: }
127: VERB(3) printf("Created lock file %s\n", szSess);
128:
1.5.20.3 misho 129: if (chg && evt) {
130: kq = kqueue();
131: if (kq == -1) {
132: printf("Error:: can`t execute safe mount #%d - %s\n", errno, strerror(errno));
133: close(f);
134: unlink(szSess);
135: return -1;
136: } else {
137: memset(chg, 0, sizeof(struct kevent));
138: memset(evt, 0, sizeof(struct kevent));
1.1 misho 139:
1.5.20.3 misho 140: EV_SET(chg, f, EVFILT_VNODE, EV_ADD, NOTE_DELETE | NOTE_RENAME | NOTE_REVOKE,
141: 0, NULL);
142: }
1.1 misho 143: }
144:
145: return f;
146: }
147:
1.3 misho 148: static void
149: cleanexit()
150: {
151: AIT_FREE_VAL(&User);
152: AIT_FREE_VAL(&Dev);
153: AIT_FREE_VAL(&Mount);
154: AIT_FREE_VAL(&Chroot);
155:
156: cfgUnloadConfig(&cfg);
157: }
1.1 misho 158:
1.5.20.1 misho 159: static int
160: s_unlck()
161: {
162: if (access(szSLCK, F_OK))
1.5.20.5! misho 163: return 2;
1.5.20.1 misho 164:
1.5.20.3 misho 165: if (access(szSess, F_OK) && update(MNT_UPDATE | MNT_RDONLY) == -1)
1.5.20.1 misho 166: return 8;
167:
168: unlink(szSLCK);
169: VERB(3) printf("Unlock & deleted service lock file %s\n", szSLCK);
170: return 0;
171: }
172:
173: static int
174: s_lck(const char *reason)
175: {
176: int f;
177: char szStr[STRSIZ];
178:
179: if (!access(szSLCK, F_OK)) {
1.5.20.4 misho 180: printf("cfexec already held service lock ...\n");
1.5.20.1 misho 181: return 127;
182: }
183:
184: f = open(szSLCK, O_CREAT | O_WRONLY | O_TRUNC, 0644);
185: if (f == -1) {
186: printf("Error:: can`t service lock session #%d - %s\n", errno, strerror(errno));
1.5.20.5! misho 187: return 4;
1.5.20.1 misho 188: } else {
189: memset(szStr, 0, sizeof szStr);
190: snprintf(szStr, sizeof szStr, "[%d] - %s", getpid(), reason);
191: write(f, szStr, strlen(szStr));
192: }
193: close(f);
194:
195: if (update(MNT_UPDATE) == -1) {
196: unlink(szSLCK);
1.5.20.5! misho 197: return 5;
1.5.20.1 misho 198: }
199:
200: VERB(3) printf("Lock & created service lock file %s\n", szSLCK);
201: return 0;
202: }
203:
1.3 misho 204:
205: int
206: main(int argc, char **argv)
1.1 misho 207: {
1.5.20.1 misho 208: char ch, mod = 0, reason[STRSIZ];
1.3 misho 209: const char *err = NULL;
1.1 misho 210: struct kevent chg, evt;
211: struct timespec ts;
212: pid_t pid;
1.5.20.1 misho 213: int f, ret = 0, stat = 0;
1.1 misho 214:
215: strlcpy(szConfig, DEFAULT_CONFIG, MAXPATHLEN);
1.3 misho 216: /* Load variables from config if exists */
217: if (!cfgLoadConfig(szConfig, &cfg)) {
218: cfg_loadAttribute(&cfg, "cfexec", "timeout", &User, DEFAULT_TIMEOUT);
219: #ifndef HAVE_STRTONUM
220: Timeout = (int) strtol(szUser, NULL, 0);
221: #else
222: Timeout = strtonum(AIT_GET_STR(&User), 0, 3600, &err);
223: #endif
224: AIT_FREE_VAL(&User);
1.2 misho 225: if (!Timeout && err) {
1.1 misho 226: printf("Error:: in seconds for timeout %s - %s\n", optarg, err);
1.3 misho 227: cfgUnloadConfig(&cfg);
1.1 misho 228: return 1;
229: }
1.3 misho 230: cfg_loadAttribute(&cfg, "cfexec", "suid", &User, DEFAULT_USER);
231: cfg_loadAttribute(&cfg, "cfexec", "mount", &Mount, DEFAULT_MOUNT);
232: cfg_loadAttribute(&cfg, "cfexec", "device", &Dev, DEFAULT_DEVICE);
233: cfg_loadAttribute(&cfg, "cfexec", "chroot", &Chroot, DEFAULT_CHROOT);
1.1 misho 234:
1.3 misho 235: cfgUnloadConfig(&cfg);
1.1 misho 236: } else {
237: Timeout = atoi(DEFAULT_TIMEOUT);
1.3 misho 238: AIT_SET_STR(&User, DEFAULT_USER);
239: AIT_SET_STR(&Mount, DEFAULT_MOUNT);
240: AIT_SET_STR(&Dev, DEFAULT_DEVICE);
241: AIT_SET_STR(&Chroot, DEFAULT_CHROOT);
1.1 misho 242: }
243:
1.3 misho 244: atexit(cleanexit);
245:
246: /* Load variables from arguments if exists */
1.5.20.1 misho 247: while ((ch = getopt(argc, argv, "hvUu:c:d:m:t:L:")) != -1)
1.1 misho 248: switch (ch) {
249: case 'v':
250: Verbose++;
251: break;
252: case 'u':
1.3 misho 253: AIT_SET_STR(&User, optarg);
1.1 misho 254: break;
255: case 'c':
1.3 misho 256: AIT_SET_STR(&Chroot, optarg);
1.1 misho 257: break;
258: case 'd':
1.3 misho 259: AIT_SET_STR(&Dev, optarg);
1.1 misho 260: break;
261: case 'm':
1.3 misho 262: AIT_SET_STR(&Mount, optarg);
1.1 misho 263: break;
1.5.20.1 misho 264: case 'L':
265: strlcpy(reason, optarg, sizeof reason);
266: mod = 1;
267: break;
268: case 'U':
269: mod = -1;
270: break;
1.1 misho 271: case 't':
1.3 misho 272: #ifndef HAVE_STRTONUM
273: Timeout = (int) strtol(optarg, NULL, 0);
274: #else
1.2 misho 275: Timeout = strtonum(optarg, 0, 3600, &err);
1.3 misho 276: #endif
1.2 misho 277: if (!Timeout && err) {
1.1 misho 278: printf("Error:: in seconds for timeout %s - %s\n",
279: optarg, err);
280: return 1;
281: }
282: break;
283: case 'h':
284: default:
285: Usage();
286: return 1;
287: }
288: argc -= optind;
289: argv += optind;
290:
291: memset(szSess, 0, MAXPATHLEN);
1.3 misho 292: snprintf(szSess, MAXPATHLEN, "%s%s-cfexec.LCK", DEFAULT_TMP, AIT_GET_STR(&Mount));
1.5.20.1 misho 293: memset(szSLCK, 0, MAXPATHLEN);
294: snprintf(szSLCK, MAXPATHLEN, CFEXEC_SLOCK, DEFAULT_TMP);
295:
296: /* we have request for service lock! */
297: if (mod) {
298: VERB(3) printf("Info(3):: mode=%hhd\n", mod);
299: if (mod == -1)
300: ret = s_unlck();
301: else
302: ret = s_lck(reason);
303: return ret;
304: }
1.1 misho 305:
306: VERB(3) printf("Info(3):: Chroot=%s SUID=%s Device=%s Mount=%s Timeout=%d Session=%s\n",
1.3 misho 307: AIT_GET_STR(&Chroot), AIT_GET_STR(&User), AIT_GET_STR(&Dev),
308: AIT_GET_STR(&Mount), Timeout, szSess);
1.1 misho 309:
310: if (!access(szSess, F_OK)) {
311: printf("cfexec already running ...\n");
312: return 127;
313: }
314:
315: if (!argc) {
316: switch (fork()) {
317: case -1:
318: printf("Error:: can`t execute safe mount #%d - %s\n",
319: errno, strerror(errno));
320: return 3;
321: case 0:
322: VERB(5) printf("Info(5):: Go safe mount.\n");
323: setsid();
324:
1.5.20.3 misho 325: if ((f = mkevent(&chg, &evt)) == -1)
1.1 misho 326: return 4;
327:
1.5.20.3 misho 328: if (update(MNT_UPDATE) == -1)
1.1 misho 329: return 5;
330:
1.2 misho 331: if (Timeout) {
332: memset(&ts, 0, sizeof ts);
333: ts.tv_sec = Timeout;
334: }
335: switch (kevent(kq, &chg, 1, &evt, 1, !Timeout ? NULL : &ts)) {
1.1 misho 336: case -1:
337: printf("Error:: can`t execute safe mount #%d - %s\n",
338: errno, strerror(errno));
339: stat = 7;
340: break;
341: case 0:
1.5.20.1 misho 342: if (!access(szSLCK, F_OK)) {
343: VERB(1) printf("Timeout reached - service locked\n");
344: break;
345: }
1.1 misho 346: VERB(1) printf("Timeout reached - secure mount\n");
347: default:
348: VERB(1) printf("Lock file is deleted - secure mount\n");
1.5.20.1 misho 349: if (access(szSLCK, F_OK) && update(MNT_UPDATE | MNT_RDONLY) == -1)
1.1 misho 350: stat = 8;
351: }
352:
353: close(kq);
354: close(f);
355: unlink(szSess);
356: break;
357: }
358: } else {
359: /*
360: sigemptyset(&sig);
361: sigaddset(&sig, SIGINT);
362: sigaddset(&sig, SIGTSTP);
363: sigprocmask(SIG_BLOCK, &sig, &oldsig);
364: */
365:
1.5.20.3 misho 366: if ((f = mkevent(NULL, NULL)) == -1)
1.1 misho 367: return 4;
1.5.20.3 misho 368: else
369: close(f);
370:
371: if (update(MNT_UPDATE) == -1)
372: return 5;
1.1 misho 373:
374: switch ((pid = vfork())) {
375: case -1:
376: printf("Error:: can`t execute safe mount #%d - %s\n",
377: errno, strerror(errno));
1.5.20.3 misho 378: stat = 3;
379: break;
1.1 misho 380: case 0:
381: VERB(5) printf("Go to running process %s\n", *argv);
1.3 misho 382: if (chroot(AIT_GET_STR(&Chroot)) == -1) {
1.1 misho 383: printf("Error:: can`t chroot to dir %s #%d - %s\n",
1.3 misho 384: AIT_GET_STR(&Chroot), errno, strerror(errno));
1.1 misho 385: } else {
1.3 misho 386: if (strncmp(AIT_GET_STR(&User), "root", 5))
1.1 misho 387: setuser();
388:
1.2 misho 389: /* chdir("/"); */
1.1 misho 390: execvp(*argv, argv);
391: }
1.5.20.3 misho 392: _exit(127);
1.1 misho 393: break;
394: default:
395: waitpid(pid, &stat, 0);
1.5.20.3 misho 396: stat = WEXITSTATUS(stat);
1.1 misho 397: VERB(3) printf("Return code: %d\n", stat);
398:
1.5.20.1 misho 399: if (access(szSLCK, F_OK) && update(MNT_UPDATE | MNT_RDONLY) == -1)
1.5.20.3 misho 400: stat = 8;
401: break;
1.1 misho 402: }
1.5.20.3 misho 403:
404: unlink(szSess);
1.1 misho 405: }
406:
407: return stat;
408: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>