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