Re: A quick question
Posted in 1991
> Can anybody think of a way to enable many users of a 4gl application select > access to a database and its tables BUT disallowing those same users any > kind of access to the same database and tables from sql? > The motivation for this is that the users' actions can be controlled under > the 4gl application but cannot be when using raw sql. We have had the same question. The problem, as I see it, is that Informix does not utilize the effective id of the process for determining database access privileges. If others agree, some lobbying for Informix Feature Request #1729 (Use effective uid for determing database privileges) might prove helpful. In the meantime, our approach to the problem is to add a "user" to the system that has the needed database privleges and run our programs setuid to the special user. Since Informix does not recognize the effective user id of a process, we use a short setuid root program (DBSU), which sets the real uid, to execute all processes. The DBSU program performs the following: 1) ensures that the environmental variable, LOGNAME, is set to the name of the real uid, (so that the application can determine the real user from LOGNAME) 2) ensures that the real user has execute permission to the desired process, 3) ensures that the desired process is not a setuid root process, 4) then sets the real uid to the effective uid of the desired process and executes the process This approach has the following benefits (or weaknesses): 1) we have had to change very little code, 2) database access is granted, 3) files created by the process, typically have the wrong owner, 4) sub-shells spawned by the process, are going to be run as the new uid, 5) setuid shell scripts may also be executed with the setuid permissions, 5) .... -------------------------------------------------------------- Ken Evilsizor Manager of Systems Development (513) 563-4542 CARS Information Systems Corporation, Cincinnati, OH 45241 {uunet.uu.net}!cinnet.com!carsinfo!ken Standard Disclaimers Apply The code follows (I hope it isn't toooooo long, 140 lines): ------------------------ CUT HERE ------------------------ #include <sys/types.h> #include <sys/stat.h> #include <sys/file.h> #include <stdio.h> #define ROOT_UID 0 /* the uid of root */ char program[128]; main(argc, argv) int argc; char *argv[]; { struct stat sb; char *progname; (progname = strrchr(argv[0], '/')) ? (progname++) : (progname = argv[0]); checkaccess(argv[1], getuid()); if (program[0] == '\\0') { fprintf(stderr, "%s: %s not found\\n", progname, argv[1]); exit(1); } stat(program, &sb); if ((sb.st_mode & S_ISUID) && (sb.st_uid != ROOT_UID)) setuid(sb.st_uid); else setuid(getuid()); execv(program, argv+1); fprintf(stderr, "Cannot exec '%s'\\n", program); exit(1); } checkaccess(pname, uid) char *pname; int uid; { int pid; int n; int pfd[2]; /* ----- Create a pipe: pfd[0] = read side, pfd[1] = write side ----- */ if (pipe(pfd) < 0) { fprintf(stderr, "Can not create pipe\\n"); exit(1); } switch(pid = fork()) { case -1: fprintf(stderr, "Can not fork new process\\n"); exit(1); case 0: /* child */ close(pfd[0]); setuid(uid); /* Revert back to original UID */ getpath(pname); if (write(pfd[1], program, strlen(program)+1) < 0) { fprintf(stderr, "Error writing to pipe\\n"); } close(pfd[1]); exit(0); default: /* parent */ close(pfd[1]); if (read(pfd[0], program, sizeof(program) - 1) < 0) { fprintf(stderr, "Error reading from pipe\\n"); exit(1); } close(pfd[0]); if (wait(&n) != pid) { fprintf(stderr, "PID mismatch error\\n"); exit(1); } } return; } getpath(pname) char *pname; { char *cp, *path; program[0] = '\\0'; /* ----- Check for full pathname ----- */ if (*pname == '/') { if (access(pname, X_OK) == 0) /* Execute permission granted */ { strncpy(program, pname, sizeof(program)-1); program[sizeof(program)-1] = '\\0'; } return; } /* ----- Do a path search ----- */ path = getenv("PATH"); cp = malloc(strlen(path)+1); if (cp == NULL) { fprintf(stderr, "Memory Allocation Error\\n"); return; } strcpy(cp, path); path = cp; while (path) { if ((cp = strchr(path, ':')) != NULL) *cp++ = '\\0'; if (strlen(path) + strlen(pname) + 2 > sizeof(program)) { program[0] = '\\0'; fprintf("String too long error"); return; } strcpy(program, path); strcat(program, "/"); strcat(program, pname); if (access(program, X_OK) == 0) return; path = cp; } program[0] = '\\0'; return; } ------------------------ END ------------------------