int main(int ac, char **av) { int lc, pid; tst_parse_opts(ac, av, NULL, NULL); setup(); #ifdef UCLINUX maybe_run_child(&dochild, "sdd", filename, &recstart, &reclen); #endif for (lc = 0; TEST_LOOPING(lc); lc++) { sprintf(filename, MOUNT_DIR"%s.%d.%d\n", TCID, getpid(), lc); if (tst_fill_file(filename, 0, 1024, 8)) { tst_brkm(TBROK, cleanup, "Failed to create test file '%s'", filename); } SAFE_CHMOD(cleanup, filename, 02666); reclen = RECLEN; /* * want at least RECLEN bytes BEFORE AND AFTER the * record lock. */ recstart = RECLEN + rand() % (len - 3 * RECLEN); if ((pid = FORK_OR_VFORK()) < 0) tst_brkm(TBROK | TERRNO, cleanup, "fork() failed"); if (pid == 0) { #ifdef UCLINUX if (self_exec(av[0], "sdd", filename, recstart, reclen) < -1) { tst_brkm(TBROK, cleanup, "self_exec() failed"); } #else dochild(); #endif } doparent(); } cleanup(); tst_exit(); }
static BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequence, BOOL as_root) { char *slavedev; int master; pid_t pid, wpid; int wstat; BOOL chstat = False; /* allocate a pseudo-terminal device */ if ((master = findpty (&slavedev)) < 0) { DEBUG(3,("Cannot Allocate pty for password change: %s\n",name)); return(False); } /* * We need to temporarily stop CatchChild from eating * SIGCLD signals as it also eats the exit status code. JRA. */ CatchChildLeaveStatus(); #ifdef __uClinux__ /* Hmmm, need to check this one further... */ DEBUG(0,("%s(%d): vfork()ing\n",__FILE__,__LINE__)); if ((pid = vfork()) < 0) { #else if ((pid = fork()) < 0) { #endif DEBUG(3,("Cannot fork() child for password change: %s\n",name)); close(master); CatchChild(); return(False); } /* we now have a pty */ if (pid > 0){ /* This is the parent process */ if ((chstat = talktochild(master, chatsequence)) == False) { DEBUG(3,("Child failed to change password: %s\n",name)); kill(pid, SIGKILL); /* be sure to end this process */ } while((wpid = sys_waitpid(pid, &wstat, 0)) < 0) { if(errno == EINTR) { errno = 0; continue; } break; } if (wpid < 0) { DEBUG(3,("The process is no longer waiting!\n\n")); close(master); CatchChild(); return(False); } /* * Go back to ignoring children. */ CatchChild(); close(master); if (pid != wpid) { DEBUG(3,("We were waiting for the wrong process ID\n")); return(False); } if (WIFEXITED(wstat) == 0) { DEBUG(3,("The process exited while we were waiting\n")); return(False); } if (WEXITSTATUS(wstat) != 0) { DEBUG(3,("The status of the process exiting was %d\n", wstat)); return(False); } } else { /* CHILD */ /* * Lose any oplock capabilities. */ set_process_capability(KERNEL_OPLOCK_CAPABILITY, False); set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY, False); /* make sure it doesn't freeze */ alarm(20); if (as_root) become_root(False); DEBUG(3,("Dochild for user %s (uid=%d,gid=%d)\n",name,(int)getuid(),(int)getgid())); chstat = dochild(master, slavedev, name, passwordprogram, as_root); /* * The child should never return from dochild() .... */ DEBUG(0,("chat_with_program: Error: dochild() returned %d\n", chstat )); exit(1); } if (chstat) DEBUG(3,("Password change %ssuccessful for user %s\n", (chstat?"":"un"), name)); return (chstat); } BOOL chgpasswd(char *name,char *oldpass,char *newpass, BOOL as_root) { pstring passwordprogram; pstring chatsequence; size_t i; size_t len; strlower(name); DEBUG(3,("Password change for user: %s\n",name)); #if DEBUG_PASSWORD DEBUG(100,("Passwords: old=%s new=%s\n",oldpass,newpass)); #endif /* Take the passed information and test it for minimum criteria */ /* Minimum password length */ if (strlen(newpass) < lp_min_passwd_length()) /* too short, must be at least MINPASSWDLENGTH */ { DEBUG(0,("Password Change: user %s, New password is shorter than minimum password length = %d\n", name, lp_min_passwd_length())); return (False); /* inform the user */ } /* Password is same as old password */ if (strcmp(oldpass,newpass) == 0) /* don't allow same password */ { DEBUG(2,("Password Change: %s, New password is same as old\n",name)); /* log the attempt */ return (False); /* inform the user */ } pstrcpy(passwordprogram,lp_passwd_program()); pstrcpy(chatsequence,lp_passwd_chat()); if (!*chatsequence) { DEBUG(2,("Null chat sequence - no password changing\n")); return(False); } if (!*passwordprogram) { DEBUG(2,("Null password program - no password changing\n")); return(False); } /* * Check the old and new passwords don't contain any control * characters. */ len = strlen(oldpass); for(i = 0; i < len; i++) { if (iscntrl((int)oldpass[i])) { DEBUG(0,("chat_with_program: oldpass contains control characters (disallowed).\n")); return False; } } len = strlen(newpass); for(i = 0; i < len; i++) { if (iscntrl((int)newpass[i])) { DEBUG(0,("chat_with_program: newpass contains control characters (disallowed).\n")); return False; } } pstring_sub(passwordprogram,"%u",name); /* note that we do NOT substitute the %o and %n in the password program as this would open up a security hole where the user could use a new password containing shell escape characters */ pstring_sub(chatsequence,"%u",name); all_string_sub(chatsequence,"%o",oldpass,sizeof(pstring)); all_string_sub(chatsequence,"%n",newpass,sizeof(pstring)); return(chat_with_program(passwordprogram,name,chatsequence, as_root)); }
static BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequence, BOOL as_root) { char *slavedev; int master; pid_t pid, wpid; int wstat; BOOL chstat = False; /* allocate a pseudo-terminal device */ if ((master = findpty (&slavedev)) < 0) { DEBUG(3,("Cannot Allocate pty for password change: %s\n",name)); return(False); } /* * 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(3,("Cannot fork() child for password change: %s\n",name)); close(master); CatchChild(); return(False); } /* we now have a pty */ if (pid > 0){ /* This is the parent process */ if ((chstat = talktochild(master, chatsequence)) == False) { DEBUG(3,("Child failed to change password: %s\n",name)); kill(pid, SIGKILL); /* be sure to end this process */ } while((wpid = sys_waitpid(pid, &wstat, 0)) < 0) { if(errno == EINTR) { errno = 0; continue; } break; } if (wpid < 0) { DEBUG(3,("The process is no longer waiting!\n\n")); close(master); CatchChild(); return(False); } /* * Go back to ignoring children. */ CatchChild(); close(master); if (pid != wpid) { DEBUG(3,("We were waiting for the wrong process ID\n")); return(False); } if (WIFEXITED(wstat) == 0) { DEBUG(3,("The process exited while we were waiting\n")); return(False); } if (WEXITSTATUS(wstat) != 0) { DEBUG(3,("The status of the process exiting was %d\n", wstat)); return(False); } } else { /* CHILD */ /* * Lose any oplock capabilities. */ set_process_capability(KERNEL_OPLOCK_CAPABILITY, False); set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY, False); /* make sure it doesn't freeze */ alarm(20); if (as_root) become_root(False); DEBUG(3,("Dochild for user %s (uid=%d,gid=%d)\n",name,(int)getuid(),(int)getgid())); chstat = dochild(master, slavedev, name, passwordprogram, as_root); /* * The child should never return from dochild() .... */ DEBUG(0,("chat_with_program: Error: dochild() returned %d\n", chstat )); exit(1); } if (chstat) DEBUG(3,("Password change %ssuccessful for user %s\n", (chstat?"":"un"), name)); return (chstat); }
int run_test(int file_flag, int file_mode, int start, int end) { int child_count; int child; int nexited; int status, expect_stat; int i, fail = 0; /* loop through all test cases */ for (test = start; test < end; test++) { /* open a temp file to lock */ fd = open(tmpname, file_flag, file_mode); if (fd < 0) { tst_brkm(TBROK, cleanup, "open failed"); } /* write some dummy data to the file */ (void)write(fd, FILEDATA, 10); /* Initialize first parent lock structure */ thiscase = &testcases[test]; thislock = &thiscase->parent_a; /* set the initial parent lock on the file */ if ((fcntl(fd, F_SETLK, thislock)) < 0) { tst_resm(TFAIL, "First parent lock failed"); tst_resm(TFAIL, "Test case %d, errno = %d", test + 1, errno); unlink(tmpname); return 1; } /* Initialize second parent lock structure */ thislock = &thiscase->parent_b; if ((thislock->type) != IGNORED) { /*SKIPVAL */ /* set the second parent lock */ if ((fcntl(fd, F_SETLK, thislock)) < 0) { tst_resm(TFAIL, "Second parent lock failed"); tst_resm(TFAIL, "Test case %d, errno = %d", test + 1, errno); unlink(tmpname); return 1; } } /* Initialize first child lock structure */ thislock = &thiscase->child_a; /* Initialize child counter and flags */ alarm_flag = parent_flag = 0; child_flag1 = child_flag2 = 0; child_count = 0; /* spawn child processes */ for (i = 0; i < 2; i++) { if (thislock->type != IGNORED) { if ((child = FORK_OR_VFORK()) == 0) { #ifdef UCLINUX if (self_exec(argv0, "ddddd", i, parent, test, thislock, fd) < 0) { perror("self_exec failed"); return 1; } #else dochild(i); #endif } if (child < 0) { perror("Fork failed"); return 1; } child_count++; child_pid[i] = child; flag[i] = thislock->flag; } /* Initialize second child lock structure */ thislock = &thiscase->child_b; } /* parent process */ /* * Wait for children to signal they are ready. Set a timeout * just in case they don't signal at all. */ alarm(TIME_OUT); while (!alarm_flag && (child_flag1 + child_flag2 != child_count)) { pause(); } /* * Turn off alarm and unmask signals */ alarm((unsigned)0); if (child_flag1 + child_flag2 != child_count) { tst_resm(TFAIL, "Test case %d: kids didn't signal", test + 1); fail = 1; } child_flag1 = child_flag2 = alarm_flag = 0; thislock = &thiscase->parent_c; /* set the third parent lock on the file */ if ((fcntl(fd, F_SETLK, thislock)) < 0) { tst_resm(TFAIL, "Third parent lock failed"); tst_resm(TFAIL, "Test case %d, errno = %d", test + 1, errno); unlink(tmpname); return 1; } /* Initialize fourth parent lock structure */ thislock = &thiscase->parent_d; if ((thislock->type) != IGNORED) { /*SKIPVAL */ /* set the fourth parent lock */ if ((fcntl(fd, F_SETLK, thislock)) < 0) { tst_resm(TINFO, "Fourth parent lock failed"); tst_resm(TINFO, "Test case %d, errno = %d", test + 1, errno); unlink(tmpname); return 1; } } /* * Wait for children to exit, or for timeout to occur. * Timeouts are expected for testcases where kids are * 'WILLBLOCK', In that case, send kids a wakeup interrupt * and wait again for them. If a second timeout occurs, then * something is wrong. */ alarm_flag = nexited = 0; while (nexited < child_count) { alarm(TIME_OUT); child = wait(&status); alarm(0); if (child == -1) { if (errno != EINTR || alarm_flag != 1) { /* * Some error other than a timeout, * or else this is the second * timeout. Both cases are errors. */ break; } /* * Expected timeout case. Signal kids then * go back and wait again */ child_sig(SIGUSR1, child_count); continue; } for (i = 0; i < child_count; i++) if (child == child_pid[i]) break; if (i == child_count) { /* * Ignore unexpected kid, it could be a * leftover from a previous iteration that * timed out. */ continue; } /* Found the right kid, check his status */ nexited++; expect_stat = (flag[i] == NOBLOCK) ? 0 : 1; if (!WIFEXITED(status) || WEXITSTATUS(status) != expect_stat) { /* got unexpected exit status from kid */ tst_resm(TFAIL, "Test case %d: child %d %s " "or got bad status (x%x)", test + 1, i, (flag[i] == NOBLOCK) ? "BLOCKED unexpectedly" : "failed to BLOCK", status); fail = 1; } } if (nexited != child_count) { tst_resm(TFAIL, "Test case %d, caught %d expected %d " "children", test + 1, nexited, child_count); child_sig(SIGKILL, nexited); fail = 1; } close(fd); } unlink(tmpname); if (fail) { return 1; } else { return 0; } return 0; }
void dochild_uc() { dochild(kid_uc); }
int main(int ac, char **av) { int fd, i; int tlen = 0; struct sigaction act; int lc; char *msg; struct statvfs fs; /* * parse standard options */ if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL) { tst_resm(TBROK, "OPTION PARSING ERROR - %s", msg); tst_exit(); } #ifdef UCLINUX maybe_run_child(&dochild, "dddd", filename, &recstart, &reclen, &ppid); #endif local_flag = PASSED; tst_tmpdir(); if (statvfs(".", &fs) == -1) { tst_resm(TFAIL | TERRNO, "statvfs failed"); tst_rmdir(); tst_exit(); } if ((fs.f_flag & MS_MANDLOCK) == 0) { tst_resm(TCONF, "The filesystem where /tmp is mounted does" " not support mandatory locks. Cannot run this test."); tst_rmdir(); tst_exit(); } for (lc = 0; TEST_LOOPING(lc); lc++) { setvbuf(stdin, 0, _IOLBF, BUFSIZ); setvbuf(stdout, 0, _IOLBF, BUFSIZ); setvbuf(stderr, 0, _IOLBF, BUFSIZ); ppid = getpid(); srand(ppid); sigemptyset(&set); act.sa_handler = (void (*)())usr1hndlr; act.sa_mask = set; act.sa_flags = 0; if (sigaction(SIGUSR1, &act, 0)) { tst_resm(TBROK, "Sigaction for SIGUSR1 failed"); tst_rmdir(); tst_exit(); } /* end if */ if (sigaddset(&set, SIGUSR1)) { tst_resm(TBROK, "sigaddset for SIGUSR1 failed"); tst_rmdir(); tst_exit(); } if (sigprocmask(SIG_SETMASK, &set, 0)) { tst_resm(TBROK, "sigprocmask for SIGUSR1 failed"); tst_rmdir(); tst_exit(); } for (i = 0; i < iterations; i++) { sprintf(filename, "%s.%d.%d\n", progname, ppid, i); if ((fd = open(filename, O_CREAT | O_RDWR, 02666)) < 0) { tst_resm(TBROK, "parent error opening/creating %s", filename); cleanup(); } /* end if */ if (chown(filename, geteuid(), getegid()) == -1) { tst_resm(TBROK, "parent error chowning %s", filename); cleanup(); } /* end if */ if (chmod(filename, 02666) == -1) { tst_resm(TBROK, "parent error chmoding %s", filename); cleanup(); } /* end if */ do { if (write(fd, buffer, BUFSIZE) < 0) { tst_resm(TBROK, "parent write failed to %s", filename); cleanup(); } tlen += BUFSIZE; } while (tlen < len); close(fd); reclen = RECLEN; /* * want at least RECLEN bytes BEFORE AND AFTER the * record lock. */ recstart = RECLEN + rand() % (len - 3 * RECLEN); if (sync_pipe_create(sync_pipes, PIPE_NAME) == -1) tst_brkm(TBROK, cleanup, "sync_pipe_create failed"); if ((cpid = FORK_OR_VFORK()) < 0) { unlink(filename); tst_resm(TINFO, "System resource may be too low, fork() malloc()" " etc are likely to fail."); tst_resm(TBROK, "Test broken due to inability of fork."); tst_rmdir(); tst_exit(); } if (cpid == 0) { #ifdef UCLINUX if (self_exec (av[0], "dddd", filename, recstart, reclen, ppid) < -1) { unlink(filename); tst_resm(TBROK, "self_exec failed."); tst_rmdir(); tst_exit(); } #else dochild(); #endif /* never returns */ } if (sync_pipe_wait(sync_pipes) == -1) tst_brkm(TBROK, cleanup, "sync_pipe_wait failed"); if (sync_pipe_close(sync_pipes, PIPE_NAME) == -1) tst_brkm(TBROK, cleanup, "sync_pipe_close failed"); doparent(); /* child should already be dead */ unlink(filename); } if (local_flag == PASSED) tst_resm(TPASS, "Test passed."); else tst_resm(TFAIL, "Test failed."); tst_rmdir(); tst_exit(); } /* end for */ tst_exit(); }