Ejemplo n.º 1
0
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));
}
Ejemplo n.º 2
0
static bool chat_with_program(char *passwordprogram, const struct passwd *pass,
			      char *chatsequence, bool as_root)
{
	char *slavedev = NULL;
	int master;
	pid_t pid, wpid;
	int wstat;
	bool chstat = False;
	void (*saved_handler)(int);

	if (pass == NULL) {
		DEBUG(0, ("chat_with_program: user doesn't exist in the UNIX password database.\n"));
		return False;
	}

	/* allocate a pseudo-terminal device */
	if ((master = findpty(&slavedev)) < 0) {
		DEBUG(3, ("chat_with_program: Cannot Allocate pty for password change: %s\n", pass->pw_name));
		return (False);
	}

	/*
	 * We need to temporarily stop CatchChild from eating
	 * SIGCLD signals as it also eats the exit status code. JRA.
	 */

	saved_handler = CatchChildLeaveStatus();

	if ((pid = fork()) < 0) {
		DEBUG(3, ("chat_with_program: Cannot fork() child for password change: %s\n", pass->pw_name));
		SAFE_FREE(slavedev);
		close(master);
		(void)CatchSignal(SIGCLD, saved_handler);
		return (False);
	}

	/* we now have a pty */
	if (pid > 0) {			/* This is the parent process */
		/* Don't need this anymore in parent. */
		SAFE_FREE(slavedev);

		if ((chstat = talktochild(master, chatsequence)) == False) {
			DEBUG(3, ("chat_with_program: Child failed to change password: %s\n", pass->pw_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, ("chat_with_program: The process is no longer waiting!\n\n"));
			close(master);
			(void)CatchSignal(SIGCLD, saved_handler);
			return (False);
		}

		/*
		 * Go back to ignoring children.
		 */
		(void)CatchSignal(SIGCLD, saved_handler);

		close(master);

		if (pid != wpid) {
			DEBUG(3, ("chat_with_program: We were waiting for the wrong process ID\n"));
			return (False);
		}
		if (WIFEXITED(wstat) && (WEXITSTATUS(wstat) != 0)) {
			DEBUG(3, ("chat_with_program: The process exited with status %d \
while we were waiting\n", WEXITSTATUS(wstat)));
			return (False);
		}
Ejemplo n.º 3
0
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);
}
Ejemplo n.º 4
0
int main(int argc, char **argv)
{
	FILE		*fp;
	struct timeval	tv;
	fd_set		fds;
	char		buf[1024];
	char		realcons[1024];
	char		*p;
	char		*logfile;
	char		*pidfile;
	int		rotate;
	int		dontfork;
	int		ptm, pts;
	int		realfd;
	int		n, m, i;
	int		todo;

	fp = NULL;
	logfile = LOGFILE;
	pidfile = NULL;
	rotate = 0;
	dontfork = 0;

	while ((i = getopt(argc, argv, "cdsl:p:rv")) != EOF) switch(i) {
		case 'l':
			logfile = optarg;
			break;
		case 'r':
			rotate = 1;
			break;
		case 'v':
			printf("%s\n", Version);
			exit(0);
			break;
		case 'p':
			pidfile = optarg;
			break;
		case 'c':
			createlogfile = 1;
			break;
		case 'd':
			dontfork = 1;
			break;
		case 's':
			syncalot = 1;
			break;
		default:
			usage();
			break;
	}
	if (optind < argc) usage();

	signal(SIGTERM, handler);
	signal(SIGQUIT, handler);
	signal(SIGINT,  handler);
	signal(SIGTTIN,  SIG_IGN);
	signal(SIGTTOU,  SIG_IGN);
	signal(SIGTSTP,  SIG_IGN);

	/*
	 *	Open console device directly.
	 */
	if (consolename(realcons, sizeof(realcons)) < 0)
		return 1;

	if (strcmp(realcons, "/dev/tty0") == 0)
		strcpy(realcons, "/dev/tty1");
	if (strcmp(realcons, "/dev/vc/0") == 0)
		strcpy(realcons, "/dev/vc/1");

	if ((realfd = open_nb(realcons)) < 0) {
		fprintf(stderr, "bootlogd: %s: %s\n", buf, strerror(errno));
		return 1;
	}

	/*
	 *	Grab a pty, and redirect console messages to it.
	 */
	ptm = -1;
	pts = -1;
	buf[0] = 0;
	if (findpty(&ptm, &pts, buf) < 0) {
		fprintf(stderr,
			"bootlogd: cannot allocate pseudo tty: %s\n",
			strerror(errno));
		return 1;
	}

	(void)ioctl(0, TIOCCONS, NULL);
#if 1
	/* Work around bug in 2.1/2.2 kernels. Fixed in 2.2.13 and 2.3.18 */
	if ((n = open("/dev/tty0", O_RDWR)) >= 0) {
		(void)ioctl(n, TIOCCONS, NULL);
		close(n);
	}
#endif
	if (ioctl(pts, TIOCCONS, NULL) < 0) {
		fprintf(stderr, "bootlogd: ioctl(%s, TIOCCONS): %s\n",
			buf, strerror(errno));
		return 1;
	}

	/*
	 *	Fork and write pidfile if needed.
	 */
	if (!dontfork) {
		pid_t child_pid = fork();
		switch (child_pid) {
		case -1: /* I am parent and the attempt to create a child failed */
			fprintf(stderr, "bootlogd: fork failed: %s\n",
				strerror(errno));
			exit(1);
			break;
		case 0: /* I am the child */
			break;
		default: /* I am parent and got child's pid */
			exit(0);
			break;
		}
		setsid();
	}
	if (pidfile) {
		unlink(pidfile);
		if ((fp = fopen(pidfile, "w")) != NULL) {
			fprintf(fp, "%d\n", (int)getpid());
			fclose(fp);
		}
		fp = NULL;
	}

	/*
	 *	Read the console messages from the pty, and write
	 *	to the real console and the logfile.
	 */
	while (!got_signal) {

		/*
		 *	We timeout after 5 seconds if we still need to
		 *	open the logfile. There might be buffered messages
		 *	we want to write.
		 */
		tv.tv_sec = 0;
		tv.tv_usec = 500000;
		FD_ZERO(&fds);
		FD_SET(ptm, &fds);
		if (select(ptm + 1, &fds, NULL, NULL, &tv) == 1) {
			/*
			 *	See how much space there is left, read.
			 */
			if ((n = read(ptm, inptr, endptr - inptr)) >= 0) {
				/*
				 *	Write data (in chunks if needed)
				 *	to the real output device.
				 */
				m = n;
				p = inptr;
				while (m > 0) {
					i = write(realfd, p, m);
					if (i >= 0) {
						m -= i;
						p += i;
						continue;
					}
					/*
					 *	Handle EIO (somebody hung
					 *	up our filedescriptor)
					 */
					realfd = write_err(pts, realfd,
						realcons, errno);
					if (realfd >= 0) continue;
					got_signal = 1; /* Not really */
					break;
				}

				/*
				 *	Increment buffer position. Handle
				 *	wraps, and also drag output pointer
				 *	along if we cross it.
				 */
				inptr += n;
				if (inptr - n < outptr && inptr > outptr)
					outptr = inptr;
				if (inptr >= endptr)
					inptr = ringbuf;
				if (outptr >= endptr)
					outptr = ringbuf;
			}
		}

		/*
		 *	Perhaps we need to open the logfile.
		 */
		if (fp == NULL && access(logfile, F_OK) == 0) {
			if (rotate) {
				snprintf(buf, sizeof(buf), "%s~", logfile);
				rename(logfile, buf);
			}
			fp = fopen(logfile, "a");
		}
		if (fp == NULL && createlogfile)
			fp = fopen(logfile, "a");

		if (inptr >= outptr)
			todo = inptr - outptr;
		else
			todo = endptr - outptr;
		if (fp && todo)
			writelog(fp, (unsigned char *)outptr, todo);
	}

	if (fp) {
		if (!didnl) fputc('\n', fp);
		fclose(fp);
	}

	close(pts);
	close(ptm);
	close(realfd);

	return 0;
}