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