Annotation of embedtools/src/cfexec.c, revision 1.5.20.6
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.6! misho 6: * $Id: cfexec.c,v 1.5.20.5 2017/10/08 22:34:41 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.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.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:
108: VERB(5) printf("Info(5):: safe mount for device %s to %s operation (%s)\n",
1.3 misho 109: AIT_GET_STR(&Dev), AIT_GET_STR(&Mount), (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(&Dev);
170: AIT_FREE_VAL(&Mount);
171: AIT_FREE_VAL(&Chroot);
172:
173: cfgUnloadConfig(&cfg);
174: }
1.1 misho 175:
1.5.20.1 misho 176: static int
177: s_unlck()
178: {
179: if (access(szSLCK, F_OK))
1.5.20.5 misho 180: return 2;
1.5.20.1 misho 181:
1.5.20.3 misho 182: if (access(szSess, F_OK) && update(MNT_UPDATE | MNT_RDONLY) == -1)
1.5.20.1 misho 183: return 8;
184:
185: unlink(szSLCK);
186: VERB(3) printf("Unlock & deleted service lock file %s\n", szSLCK);
187: return 0;
188: }
189:
190: static int
191: s_lck(const char *reason)
192: {
193: int f;
194: char szStr[STRSIZ];
195:
196: if (!access(szSLCK, F_OK)) {
1.5.20.4 misho 197: printf("cfexec already held service lock ...\n");
1.5.20.1 misho 198: return 127;
199: }
200:
201: f = open(szSLCK, O_CREAT | O_WRONLY | O_TRUNC, 0644);
202: if (f == -1) {
203: printf("Error:: can`t service lock session #%d - %s\n", errno, strerror(errno));
1.5.20.5 misho 204: return 4;
1.5.20.1 misho 205: } else {
206: memset(szStr, 0, sizeof szStr);
207: snprintf(szStr, sizeof szStr, "[%d] - %s", getpid(), reason);
208: write(f, szStr, strlen(szStr));
209: }
210: close(f);
211:
212: if (update(MNT_UPDATE) == -1) {
213: unlink(szSLCK);
1.5.20.5 misho 214: return 5;
1.5.20.1 misho 215: }
216:
217: VERB(3) printf("Lock & created service lock file %s\n", szSLCK);
218: return 0;
219: }
220:
1.3 misho 221:
222: int
223: main(int argc, char **argv)
1.1 misho 224: {
1.5.20.1 misho 225: char ch, mod = 0, reason[STRSIZ];
1.3 misho 226: const char *err = NULL;
1.1 misho 227: struct kevent chg, evt;
228: struct timespec ts;
229: pid_t pid;
1.5.20.1 misho 230: int f, ret = 0, stat = 0;
1.1 misho 231:
232: strlcpy(szConfig, DEFAULT_CONFIG, MAXPATHLEN);
1.3 misho 233: /* Load variables from config if exists */
234: if (!cfgLoadConfig(szConfig, &cfg)) {
235: cfg_loadAttribute(&cfg, "cfexec", "timeout", &User, DEFAULT_TIMEOUT);
236: #ifndef HAVE_STRTONUM
237: Timeout = (int) strtol(szUser, NULL, 0);
238: #else
239: Timeout = strtonum(AIT_GET_STR(&User), 0, 3600, &err);
240: #endif
241: AIT_FREE_VAL(&User);
1.2 misho 242: if (!Timeout && err) {
1.1 misho 243: printf("Error:: in seconds for timeout %s - %s\n", optarg, err);
1.3 misho 244: cfgUnloadConfig(&cfg);
1.1 misho 245: return 1;
246: }
1.3 misho 247: cfg_loadAttribute(&cfg, "cfexec", "suid", &User, DEFAULT_USER);
248: cfg_loadAttribute(&cfg, "cfexec", "mount", &Mount, DEFAULT_MOUNT);
249: cfg_loadAttribute(&cfg, "cfexec", "device", &Dev, DEFAULT_DEVICE);
250: cfg_loadAttribute(&cfg, "cfexec", "chroot", &Chroot, DEFAULT_CHROOT);
1.1 misho 251:
1.3 misho 252: cfgUnloadConfig(&cfg);
1.1 misho 253: } else {
254: Timeout = atoi(DEFAULT_TIMEOUT);
1.3 misho 255: AIT_SET_STR(&User, DEFAULT_USER);
256: AIT_SET_STR(&Mount, DEFAULT_MOUNT);
257: AIT_SET_STR(&Dev, DEFAULT_DEVICE);
258: AIT_SET_STR(&Chroot, DEFAULT_CHROOT);
1.1 misho 259: }
260:
1.3 misho 261: atexit(cleanexit);
262:
263: /* Load variables from arguments if exists */
1.5.20.1 misho 264: while ((ch = getopt(argc, argv, "hvUu:c:d:m:t:L:")) != -1)
1.1 misho 265: switch (ch) {
266: case 'v':
267: Verbose++;
268: break;
269: case 'u':
1.3 misho 270: AIT_SET_STR(&User, optarg);
1.1 misho 271: break;
272: case 'c':
1.3 misho 273: AIT_SET_STR(&Chroot, optarg);
1.1 misho 274: break;
275: case 'd':
1.3 misho 276: AIT_SET_STR(&Dev, optarg);
1.1 misho 277: break;
278: case 'm':
1.3 misho 279: AIT_SET_STR(&Mount, optarg);
1.1 misho 280: break;
1.5.20.1 misho 281: case 'L':
282: strlcpy(reason, optarg, sizeof reason);
283: mod = 1;
284: break;
285: case 'U':
286: mod = -1;
287: break;
1.1 misho 288: case 't':
1.3 misho 289: #ifndef HAVE_STRTONUM
290: Timeout = (int) strtol(optarg, NULL, 0);
291: #else
1.2 misho 292: Timeout = strtonum(optarg, 0, 3600, &err);
1.3 misho 293: #endif
1.2 misho 294: if (!Timeout && err) {
1.1 misho 295: printf("Error:: in seconds for timeout %s - %s\n",
296: optarg, err);
297: return 1;
298: }
299: break;
300: case 'h':
301: default:
302: Usage();
303: return 1;
304: }
305: argc -= optind;
306: argv += optind;
307:
308: memset(szSess, 0, MAXPATHLEN);
1.3 misho 309: snprintf(szSess, MAXPATHLEN, "%s%s-cfexec.LCK", DEFAULT_TMP, AIT_GET_STR(&Mount));
1.5.20.1 misho 310: memset(szSLCK, 0, MAXPATHLEN);
311: snprintf(szSLCK, MAXPATHLEN, CFEXEC_SLOCK, DEFAULT_TMP);
312:
313: /* we have request for service lock! */
314: if (mod) {
315: VERB(3) printf("Info(3):: mode=%hhd\n", mod);
316: if (mod == -1)
317: ret = s_unlck();
318: else
319: ret = s_lck(reason);
320: return ret;
321: }
1.1 misho 322:
323: VERB(3) printf("Info(3):: Chroot=%s SUID=%s Device=%s Mount=%s Timeout=%d Session=%s\n",
1.3 misho 324: AIT_GET_STR(&Chroot), AIT_GET_STR(&User), AIT_GET_STR(&Dev),
325: AIT_GET_STR(&Mount), Timeout, szSess);
1.1 misho 326:
327: if (!access(szSess, F_OK)) {
328: printf("cfexec already running ...\n");
329: return 127;
330: }
331:
332: if (!argc) {
333: switch (fork()) {
334: case -1:
335: printf("Error:: can`t execute safe mount #%d - %s\n",
336: errno, strerror(errno));
337: return 3;
338: case 0:
339: VERB(5) printf("Info(5):: Go safe mount.\n");
340: setsid();
341:
1.5.20.3 misho 342: if ((f = mkevent(&chg, &evt)) == -1)
1.1 misho 343: return 4;
344:
1.5.20.6! misho 345: if (update(MNT_UPDATE) == -1) {
! 346: stat = 5;
! 347: goto skip;
! 348: }
1.1 misho 349:
1.2 misho 350: if (Timeout) {
351: memset(&ts, 0, sizeof ts);
352: ts.tv_sec = Timeout;
353: }
354: switch (kevent(kq, &chg, 1, &evt, 1, !Timeout ? NULL : &ts)) {
1.1 misho 355: case -1:
356: printf("Error:: can`t execute safe mount #%d - %s\n",
357: errno, strerror(errno));
358: stat = 7;
359: break;
360: case 0:
1.5.20.1 misho 361: if (!access(szSLCK, F_OK)) {
362: VERB(1) printf("Timeout reached - service locked\n");
363: break;
364: }
1.1 misho 365: VERB(1) printf("Timeout reached - secure mount\n");
366: default:
367: VERB(1) printf("Lock file is deleted - secure mount\n");
1.5.20.1 misho 368: if (access(szSLCK, F_OK) && update(MNT_UPDATE | MNT_RDONLY) == -1)
1.1 misho 369: stat = 8;
370: }
1.5.20.6! misho 371: skip:
1.1 misho 372: close(kq);
373: close(f);
374: unlink(szSess);
375: break;
376: }
377: } else {
378: /*
379: sigemptyset(&sig);
380: sigaddset(&sig, SIGINT);
381: sigaddset(&sig, SIGTSTP);
382: sigprocmask(SIG_BLOCK, &sig, &oldsig);
383: */
384:
1.5.20.3 misho 385: if ((f = mkevent(NULL, NULL)) == -1)
1.1 misho 386: return 4;
1.5.20.3 misho 387: else
388: close(f);
389:
1.5.20.6! misho 390: if (update(MNT_UPDATE) == -1) {
! 391: unlink(szSess);
1.5.20.3 misho 392: return 5;
1.5.20.6! misho 393: }
1.1 misho 394:
395: switch ((pid = vfork())) {
396: case -1:
397: printf("Error:: can`t execute safe mount #%d - %s\n",
398: errno, strerror(errno));
1.5.20.3 misho 399: stat = 3;
400: break;
1.1 misho 401: case 0:
402: VERB(5) printf("Go to running process %s\n", *argv);
1.3 misho 403: if (chroot(AIT_GET_STR(&Chroot)) == -1) {
1.1 misho 404: printf("Error:: can`t chroot to dir %s #%d - %s\n",
1.3 misho 405: AIT_GET_STR(&Chroot), errno, strerror(errno));
1.1 misho 406: } else {
1.3 misho 407: if (strncmp(AIT_GET_STR(&User), "root", 5))
1.1 misho 408: setuser();
409:
1.2 misho 410: /* chdir("/"); */
1.1 misho 411: execvp(*argv, argv);
412: }
1.5.20.3 misho 413: _exit(127);
1.1 misho 414: break;
415: default:
416: waitpid(pid, &stat, 0);
1.5.20.3 misho 417: stat = WEXITSTATUS(stat);
1.1 misho 418: VERB(3) printf("Return code: %d\n", stat);
419:
1.5.20.1 misho 420: if (access(szSLCK, F_OK) && update(MNT_UPDATE | MNT_RDONLY) == -1)
1.5.20.3 misho 421: stat = 8;
422: break;
1.1 misho 423: }
1.5.20.3 misho 424:
425: unlink(szSess);
1.1 misho 426: }
427:
428: return stat;
429: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>