main() { if (getuid() != 0) { #if (defined(AIX) && defined(USE_SETREUID)) /* setreuid is badly broken on AIX 4.1, we avoid it completely */ fprintf(stderr,"avoiding possibly broken setreuid\n"); exit(1); #endif /* if not running as root then at least check to see if we get ENOSYS - this handles Linux 2.0.x with glibc 2.1 */ fprintf(stderr,"not running as root: checking for ENOSYS\n"); exit(have_syscall()); } gain_root_privilege(); gain_root_group_privilege(); set_effective_gid(1); set_effective_uid(1); save_re_uid(); restore_re_uid(); gain_root_privilege(); gain_root_group_privilege(); become_user_permanently(1, 1); setuid(0); if (getuid() == 0) { fprintf(stderr,"uid not set permanently\n"); exit(1); } printf("OK\n"); exit(0); }
/* This is a wrapper around the system() call to allow commands to run correctly as non root from a program which is switching between root and non-root It takes 3 arguments as uid,gid,command and runs command after becoming a non-root user */ int main(int argc,char *argv[]) { uid_t uid; gid_t gid; close_fds(); if (argc != 4) exit(2); uid = (uid_t)atoi(argv[1]); gid = (gid_t)atoi(argv[2]); become_user_permanently( uid, gid); /* paranoia :-) */ if (getuid() != uid) return(3); if (geteuid() != getuid()) return(4); /* this is to make sure that the system() call doesn't run forever */ alarm(30); return(system(argv[3])); }
static int dochild(int master,char *slavedev, char *name, char *passwordprogram, BOOL as_root) { int slave; struct termios stermios; struct passwd *pass = Get_Pwnam(name,True); gid_t gid; uid_t uid; if (pass == NULL) { DEBUG(0,("dochild: user name %s doesn't exist in the UNIX password database.\n", name)); return False; } gid = pass->pw_gid; uid = pass->pw_uid; gain_root_privilege(); /* Start new session - gets rid of controlling terminal. */ if (setsid() < 0) { DEBUG(3,("Weirdness, couldn't let go of controlling terminal\n")); return(False); } /* Open slave pty and acquire as new controlling terminal. */ if ((slave = sys_open(slavedev, O_RDWR, 0)) < 0) { DEBUG(3,("More weirdness, could not open %s\n", slavedev)); return(False); } #ifdef I_PUSH ioctl(slave, I_PUSH, "ptem"); ioctl(slave, I_PUSH, "ldterm"); #elif defined(TIOCSCTTY) if (ioctl(slave,TIOCSCTTY,0) <0) { DEBUG(3,("Error in ioctl call for slave pty\n")); /* return(False); */ } #endif /* Close master. */ close(master); /* Make slave stdin/out/err of child. */ if (dup2(slave, STDIN_FILENO) != STDIN_FILENO) { DEBUG(3,("Could not re-direct stdin\n")); return(False); } if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO) { DEBUG(3,("Could not re-direct stdout\n")); return(False); } if (dup2(slave, STDERR_FILENO) != STDERR_FILENO) { DEBUG(3,("Could not re-direct stderr\n")); return(False); } if (slave > 2) close(slave); /* Set proper terminal attributes - no echo, canonical input processing, no map NL to CR/NL on output. */ if (tcgetattr(0, &stermios) < 0) { DEBUG(3,("could not read default terminal attributes on pty\n")); return(False); } stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); stermios.c_lflag |= ICANON; stermios.c_oflag &= ~(ONLCR); if (tcsetattr(0, TCSANOW, &stermios) < 0) { DEBUG(3,("could not set attributes of pty\n")); return(False); } /* make us completely into the right uid */ if (!as_root) { become_user_permanently(uid, gid); } DEBUG(10, ("Invoking '%s' as password change program.\n", passwordprogram)); /* execl() password-change application */ if (execl("/bin/sh","sh","-c",passwordprogram,NULL) < 0) { DEBUG(3,("Bad status returned from %s\n",passwordprogram)); return(False); } return(True); }
/**************************************************************************** run a command being careful about uid/gid handling and putting the output in outfile (or discard it if outfile is NULL). if shared is True then ensure the file will be writeable by all users but created such that its owned by root. This overcomes a security hole. if shared is not set then open the file with O_EXCL set ****************************************************************************/ int smbrun(char *cmd,char *outfile,BOOL shared) { int fd; pid_t pid; uid_t uid = current_user.uid; gid_t gid = current_user.gid; /* * Lose any kernel oplock capabilities we may have. */ set_process_capability(KERNEL_OPLOCK_CAPABILITY, False); set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY, False); #ifndef HAVE_EXECL int ret; pstring syscmd; char *path = lp_smbrun(); /* in the old method we use system() to execute smbrun which then executes the command (using system() again!). This involves lots of shell launches and is very slow. It also suffers from a potential security hole */ if (!file_exist(path,NULL)) { DEBUG(0,("SMBRUN ERROR: Can't find %s. Installation problem?\n",path)); return(1); } slprintf(syscmd,sizeof(syscmd)-1,"%s %d %d \"(%s 2>&1) > %s\"", path,(int)uid,(int)gid,cmd, outfile?outfile:"/dev/null"); DEBUG(5,("smbrun - running %s ",syscmd)); ret = system(syscmd); DEBUG(5,("gave %d\n",ret)); return(ret); #else /* in this newer method we will exec /bin/sh with the correct arguments, after first setting stdout to point at the file */ /* * We need to temporarily stop CatchChild from eating * SIGCLD signals as it also eats the exit status code. JRA. */ CatchChildLeaveStatus(); if ((pid=fork()) < 0) { DEBUG(0,("smbrun: fork failed with error %s\n", strerror(errno) )); CatchChild(); return errno; } if (pid) { /* * Parent. */ int status=0; pid_t wpid; /* the parent just waits for the child to exit */ while((wpid = sys_waitpid(pid,&status,0)) < 0) { if(errno == EINTR) { errno = 0; continue; } break; } CatchChild(); if (wpid != pid) { DEBUG(2,("waitpid(%d) : %s\n",(int)pid,strerror(errno))); return -1; } #if defined(WIFEXITED) && defined(WEXITSTATUS) if (WIFEXITED(status)) { return WEXITSTATUS(status); } #endif return status; } CatchChild(); /* we are in the child. we exec /bin/sh to do the work for us. we don't directly exec the command we want because it may be a pipeline or anything else the config file specifies */ /* point our stdout at the file we want output to go into */ if (outfile && !setup_stdout_file(outfile,shared)) { exit(80); } /* now completely lose our privileges. This is a fairly paranoid way of doing it, but it does work on all systems that I know of */ become_user_permanently(uid, gid); if (getuid() != uid || geteuid() != uid || getgid() != gid || getegid() != gid) { /* we failed to lose our privileges - do not execute the command */ exit(81); /* we can't print stuff at this stage, instead use exit codes for debugging */ } /* close all other file descriptors, leaving only 0, 1 and 2. 0 and 2 point to /dev/null from the startup code */ for (fd=3;fd<256;fd++) close(fd); execl("/bin/sh","sh","-c",cmd,NULL); /* not reached */ exit(82); #endif return 1; }
/*************************************************************************** handle a http authentication line ***************************************************************************/ static bool cgi_handle_authorization(char *line) { char *p; fstring user, user_pass; struct passwd *pass = NULL; if (!strnequal(line,"Basic ", 6)) { goto err; } line += 6; while (line[0] == ' ') line++; base64_decode_inplace(line); if (!(p=strchr_m(line,':'))) { /* * Always give the same error so a cracker * cannot tell why we fail. */ goto err; } *p = 0; convert_string(CH_UTF8, CH_UNIX, line, -1, user, sizeof(user), True); convert_string(CH_UTF8, CH_UNIX, p+1, -1, user_pass, sizeof(user_pass), True); /* * Try and get the user from the UNIX password file. */ pass = getpwnam_alloc(talloc_autofree_context(), user); /* * Validate the password they have given. */ if NT_STATUS_IS_OK(pass_check(pass, user, user_pass, strlen(user_pass), NULL, False)) { if (pass) { /* * Password was ok. */ if ( initgroups(pass->pw_name, pass->pw_gid) != 0 ) goto err; become_user_permanently(pass->pw_uid, pass->pw_gid); /* Save the users name */ C_user = SMB_STRDUP(user); TALLOC_FREE(pass); return True; } } err: cgi_setup_error("401 Bad Authorization", "WWW-Authenticate: Basic realm=\"SWAT\"\r\n", "username or password incorrect"); TALLOC_FREE(pass); return False; }
static int dochild(int master, const char *slavedev, const struct passwd *pass, const char *passwordprogram, bool as_root) { int slave; struct termios stermios; gid_t gid; uid_t uid; char * const eptrs[1] = { NULL }; if (pass == NULL) { DEBUG(0, ("dochild: user doesn't exist in the UNIX password database.\n")); return False; } gid = pass->pw_gid; uid = pass->pw_uid; gain_root_privilege(); /* Start new session - gets rid of controlling terminal. */ if (setsid() < 0) { DEBUG(3, ("Weirdness, couldn't let go of controlling terminal\n")); return (False); } /* Open slave pty and acquire as new controlling terminal. */ if ((slave = open(slavedev, O_RDWR, 0)) < 0) { DEBUG(3, ("More weirdness, could not open %s\n", slavedev)); return (False); } #if defined(TIOCSCTTY) && !defined(SUNOS5) /* * On patched Solaris 10 TIOCSCTTY is defined but seems not to work, * see the discussion under * https://bugzilla.samba.org/show_bug.cgi?id=5366. */ if (ioctl(slave, TIOCSCTTY, 0) < 0) { DEBUG(3, ("Error in ioctl call for slave pty\n")); /* return(False); */ } #elif defined(I_PUSH) && defined(I_FIND) if (ioctl(slave, I_FIND, "ptem") == 0) { ioctl(slave, I_PUSH, "ptem"); } if (ioctl(slave, I_FIND, "ldterm") == 0) { ioctl(slave, I_PUSH, "ldterm"); } #endif /* Close master. */ close(master); /* Make slave stdin/out/err of child. */ if (dup2(slave, STDIN_FILENO) != STDIN_FILENO) { DEBUG(3, ("Could not re-direct stdin\n")); return (False); } if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO) { DEBUG(3, ("Could not re-direct stdout\n")); return (False); } if (dup2(slave, STDERR_FILENO) != STDERR_FILENO) { DEBUG(3, ("Could not re-direct stderr\n")); return (False); } if (slave > 2) close(slave); /* Set proper terminal attributes - no echo, canonical input processing, no map NL to CR/NL on output. */ if (tcgetattr(0, &stermios) < 0) { DEBUG(3, ("could not read default terminal attributes on pty\n")); return (False); } stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); stermios.c_lflag |= ICANON; #ifdef ONLCR stermios.c_oflag &= ~(ONLCR); #endif if (tcsetattr(0, TCSANOW, &stermios) < 0) { DEBUG(3, ("could not set attributes of pty\n")); return (False); } /* make us completely into the right uid */ if (!as_root) { become_user_permanently(uid, gid); } DEBUG(10, ("Invoking '%s' as password change program.\n", passwordprogram)); /* execl() password-change application */ if (execle("/bin/sh", "sh", "-c", passwordprogram, NULL, eptrs) < 0) { DEBUG(3, ("Bad status returned from %s\n", passwordprogram)); return (False); } return (True); }
int smbrun(char *cmd, int *outfd) { pid_t pid; uid_t uid = current_user.uid; gid_t gid = current_user.gid; /* * Lose any kernel oplock capabilities we may have. */ oplock_set_capability(False, False); /* point our stdout at the file we want output to go into */ if (outfd && ((*outfd = setup_out_fd()) == -1)) { return -1; } /* in this method we will exec /bin/sh with the correct arguments, after first setting stdout to point at the file */ /* * We need to temporarily stop CatchChild from eating * SIGCLD signals as it also eats the exit status code. JRA. */ CatchChildLeaveStatus(); if ((pid=sys_fork()) < 0) { DEBUG(0,("smbrun: fork failed with error %s\n", strerror(errno) )); CatchChild(); if (outfd) { close(*outfd); *outfd = -1; } return errno; } if (pid) { /* * Parent. */ int status=0; pid_t wpid; /* the parent just waits for the child to exit */ while((wpid = sys_waitpid(pid,&status,0)) < 0) { if(errno == EINTR) { errno = 0; continue; } break; } CatchChild(); if (wpid != pid) { DEBUG(2,("waitpid(%d) : %s\n",(int)pid,strerror(errno))); if (outfd) { close(*outfd); *outfd = -1; } return -1; } /* Reset the seek pointer. */ if (outfd) { sys_lseek(*outfd, 0, SEEK_SET); } #if defined(WIFEXITED) && defined(WEXITSTATUS) if (WIFEXITED(status)) { return WEXITSTATUS(status); } #endif return status; } CatchChild(); /* we are in the child. we exec /bin/sh to do the work for us. we don't directly exec the command we want because it may be a pipeline or anything else the config file specifies */ /* point our stdout at the file we want output to go into */ if (outfd) { close(1); if (dup2(*outfd,1) != 1) { DEBUG(2,("Failed to create stdout file descriptor\n")); close(*outfd); exit(80); } } /* now completely lose our privileges. This is a fairly paranoid way of doing it, but it does work on all systems that I know of */ become_user_permanently(uid, gid); if (getuid() != uid || geteuid() != uid || getgid() != gid || getegid() != gid) { /* we failed to lose our privileges - do not execute the command */ exit(81); /* we can't print stuff at this stage, instead use exit codes for debugging */ } #ifndef __INSURE__ /* close all other file descriptors, leaving only 0, 1 and 2. 0 and 2 point to /dev/null from the startup code */ { int fd; for (fd=3;fd<256;fd++) close(fd); } #endif execl("/bin/sh","sh","-c",cmd,NULL); /* not reached */ exit(82); return 1; }
int smbrunsecret(const char *cmd, const char *secret) { OutputDebugString("smbrunsecret is not supported\n"); #ifndef _XBOX pid_t pid; uid_t uid = current_user.ut.uid; gid_t gid = current_user.ut.gid; int ifd[2]; /* * Lose any elevated privileges. */ drop_effective_capability(KERNEL_OPLOCK_CAPABILITY); drop_effective_capability(DMAPI_ACCESS_CAPABILITY); /* build up an input pipe */ if(pipe(ifd)) { return -1; } /* in this method we will exec /bin/sh with the correct arguments, after first setting stdout to point at the file */ /* * We need to temporarily stop CatchChild from eating * SIGCLD signals as it also eats the exit status code. JRA. */ CatchChildLeaveStatus(); if ((pid=sys_fork()) < 0) { DEBUG(0, ("smbrunsecret: fork failed with error %s\n", strerror(errno))); CatchChild(); return errno; } if (pid) { /* * Parent. */ int status = 0; pid_t wpid; size_t towrite; ssize_t wrote; close(ifd[0]); /* send the secret */ towrite = strlen(secret); wrote = write(ifd[1], secret, towrite); if ( wrote != towrite ) { DEBUG(0,("smbrunsecret: wrote %ld of %lu bytes\n",(long)wrote,(unsigned long)towrite)); } fsync(ifd[1]); close(ifd[1]); /* the parent just waits for the child to exit */ while((wpid = sys_waitpid(pid, &status, 0)) < 0) { if(errno == EINTR) { errno = 0; continue; } break; } CatchChild(); if (wpid != pid) { DEBUG(2, ("waitpid(%d) : %s\n", (int)pid, strerror(errno))); return -1; } #if defined(WIFEXITED) && defined(WEXITSTATUS) if (WIFEXITED(status)) { return WEXITSTATUS(status); } #endif return status; } CatchChild(); /* we are in the child. we exec /bin/sh to do the work for us. we don't directly exec the command we want because it may be a pipeline or anything else the config file specifies */ close(ifd[1]); close(0); if (sys_dup2(ifd[0], 0) != 0) { DEBUG(2,("Failed to create stdin file descriptor\n")); close(ifd[0]); exit(80); } /* now completely lose our privileges. This is a fairly paranoid way of doing it, but it does work on all systems that I know of */ become_user_permanently(uid, gid); if (getuid() != uid || geteuid() != uid || getgid() != gid || getegid() != gid) { /* we failed to lose our privileges - do not execute the command */ exit(81); /* we can't print stuff at this stage, instead use exit codes for debugging */ } #ifndef __INSURE__ /* close all other file descriptors, leaving only 0, 1 and 2. 0 and 2 point to /dev/null from the startup code */ { int fd; for (fd = 3; fd < 256; fd++) close(fd); } #endif execl("/bin/sh", "sh", "-c", cmd, NULL); /* not reached */ exit(82); #endif return 1; }