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