Esempio n. 1
0
static int
read_field(const pam_handle_t *pamh, int fd, char **buf, int *from, int *state)
{
    char *to;
    char *src;
    int i;
    char c;
    int onspace;

    /* is buf set ? */
    if (! *buf) {
	*buf = (char *) calloc(1, PAM_TIME_BUFLEN+1);
	if (! *buf) {
	    pam_syslog(pamh, LOG_ERR, "out of memory");
	    D(("no memory"));
	    *state = STATE_EOF;
	    return -1;
	}
	*from = 0;
        *state = STATE_NL;
	fd = open(PAM_TIME_CONF, O_RDONLY);
	if (fd < 0) {
	    pam_syslog(pamh, LOG_ERR, "error opening %s: %m", PAM_TIME_CONF);
	    _pam_drop(*buf);
	    *state = STATE_EOF;
	    return -1;
	}
    }


    if (*from > 0)
	to = shift_buf(*buf, *from);
    else
	to = *buf;

    while (fd != -1 && to - *buf < PAM_TIME_BUFLEN) {
	i = pam_modutil_read(fd, to, PAM_TIME_BUFLEN - (to - *buf));
	if (i < 0) {
	    pam_syslog(pamh, LOG_ERR, "error reading %s: %m", PAM_TIME_CONF);
	    close(fd);
	    memset(*buf, 0, PAM_TIME_BUFLEN);
	    _pam_drop(*buf);
	    *state = STATE_EOF;
	    return -1;
	} else if (!i) {
	    close(fd);
	    fd = -1;          /* end of file reached */
	}

	to += i;
    }

    if (to == *buf) {
	/* nothing previously in buf, nothing read */
	_pam_drop(*buf);
	*state = STATE_EOF;
	return -1;
    }

    memset(to, '\0', PAM_TIME_BUFLEN - (to - *buf));

    to = *buf;
    onspace = 1; /* delete any leading spaces */

    for (src = to; (c=*src) != '\0'; ++src) {
	if (*state == STATE_COMMENT && c != '\n') {
		continue;
	}

	switch (c) {
	    case '\n':
		*state = STATE_NL;
                *to = '\0';
		*from = (src - *buf) + 1;
		trim_spaces(*buf, to);
		return fd;

	    case '\t':
            case ' ':
		if (!onspace) {
		    onspace = 1;
		    *to++ = ' ';
		}
		break;

            case '!':
		onspace = 1; /* ignore following spaces */
		*to++ = '!';
		break;

	    case '#':
		*state = STATE_COMMENT;
		break;

	    case FIELD_SEPARATOR:
		*state = STATE_FIELD;
                *to = '\0';
		*from = (src - *buf) + 1;
		trim_spaces(*buf, to);
		return fd;

	    case '\\':
		if (src[1] == '\n') {
		    ++src; /* skip it */
		    break;
		}
	    default:
		*to++ = c;
		onspace = 0;
	}
	if (src > to)
	    *src = '\0'; /* clearing */
    }

    if (*state != STATE_COMMENT) {
	*state = STATE_COMMENT;
	pam_syslog(pamh, LOG_ERR, "field too long - ignored");
	**buf = '\0';
    } else {
	*to = '\0';
	trim_spaces(*buf, to);
    }

    *from = 0;
    return fd;
}
Esempio n. 2
0
static int
pam_echo (pam_handle_t *pamh, int flags, int argc, const char **argv)
{
  int fd;
  int orig_argc = argc;
  const char **orig_argv = argv;
  const char *file = NULL;
  int retval;

  if (flags & PAM_SILENT)
    return PAM_IGNORE;

  for (; argc-- > 0; ++argv)
    {
      if (!strncmp (*argv, "file=", 5))
	file = (5 + *argv);
    }

  /* No file= option, use argument for output.  */
  if (file == NULL || file[0] == '\0')
    {
      char msg[PAM_MAX_MSG_SIZE];
      const char *p;
      int i;
      size_t len;

      for (i = 0, len = 0; i < orig_argc && len < sizeof (msg) - 1; ++i)
	{
	  if (i > 0)
	    msg[len++] = ' ';
	  for (p = orig_argv[i]; *p != '\0' && len < sizeof(msg) - 1; ++p)
	    msg[len++] = *p;
	}
      msg[len] = '\0';

      retval = replace_and_print (pamh, msg);
    }
  else if ((fd = open (file, O_RDONLY, 0)) >= 0)
    {
      char *mtmp = NULL;
      struct stat st;

      /* load file into message buffer. */
      if ((fstat (fd, &st) < 0) || !st.st_size)
	{
	  close (fd);
	  return PAM_IGNORE;
	}

      mtmp = malloc (st.st_size + 1);
      if (!mtmp)
	{
	  close (fd);
	  return PAM_BUF_ERR;
	}

      if (pam_modutil_read (fd, mtmp, st.st_size) == -1)
	{
	  pam_syslog (pamh, LOG_ERR, "Error while reading %s: %m", file);
	  free (mtmp);
	  close (fd);
	  return PAM_IGNORE;
	}

      if (mtmp[st.st_size - 1] == '\n')
	mtmp[st.st_size - 1] = '\0';
      else
	mtmp[st.st_size] = '\0';

      close (fd);
      retval = replace_and_print (pamh, mtmp);
      free (mtmp);
    }
  else
    {
       pam_syslog (pamh, LOG_ERR, "Cannot open %s: %m", file);
       retval = PAM_IGNORE;
    }
  return retval;
}
Esempio n. 3
0
static int
last_login_read(pam_handle_t *pamh, int announce, int last_fd, uid_t uid, time_t *lltime)
{
    struct flock last_lock;
    struct lastlog last_login;
    int retval = PAM_SUCCESS;
    char the_time[256];
    char *date = NULL;
    char *host = NULL;
    char *line = NULL;

    memset(&last_lock, 0, sizeof(last_lock));
    last_lock.l_type = F_RDLCK;
    last_lock.l_whence = SEEK_SET;
    last_lock.l_start = sizeof(last_login) * (off_t) uid;
    last_lock.l_len = sizeof(last_login);

    if (fcntl(last_fd, F_SETLK, &last_lock) < 0) {
        D(("locking %s failed..(waiting a little)", _PATH_LASTLOG));
	pam_syslog(pamh, LOG_WARNING,
		   "file %s is locked/read", _PATH_LASTLOG);
	sleep(LASTLOG_IGNORE_LOCK_TIME);
    }

    if (pam_modutil_read(last_fd, (char *) &last_login,
			 sizeof(last_login)) != sizeof(last_login)) {
        memset(&last_login, 0, sizeof(last_login));
    }

    last_lock.l_type = F_UNLCK;
    (void) fcntl(last_fd, F_SETLK, &last_lock);        /* unlock */

    *lltime = last_login.ll_time;
    if (!last_login.ll_time) {
        if (announce & LASTLOG_DEBUG) {
	    pam_syslog(pamh, LOG_DEBUG,
		       "first login for user with uid %lu",
		       (unsigned long int)uid);
	}
    }

    if (!(announce & LASTLOG_QUIET)) {

	if (last_login.ll_time) {

	    /* we want the date? */
	    if (announce & LASTLOG_DATE) {
	        struct tm *tm, tm_buf;
		time_t ll_time;

		ll_time = last_login.ll_time;
		tm = localtime_r (&ll_time, &tm_buf);
		strftime (the_time, sizeof (the_time),
	        /* TRANSLATORS: "strftime options for date of last login" */
			  _(" %a %b %e %H:%M:%S %Z %Y"), tm);

		date = the_time;
	    }

	    /* we want & have the host? */
	    if ((announce & LASTLOG_HOST)
		&& (last_login.ll_host[0] != '\0')) {
		/* TRANSLATORS: " from <host>" */
		if (asprintf(&host, _(" from %.*s"), UT_HOSTSIZE,
			     last_login.ll_host) < 0) {
		    pam_syslog(pamh, LOG_ERR, "out of memory");
		    retval = PAM_BUF_ERR;
		    goto cleanup;
		}
	    }

	    /* we want and have the terminal? */
	    if ((announce & LASTLOG_LINE)
		&& (last_login.ll_line[0] != '\0')) {
		/* TRANSLATORS: " on <terminal>" */
		if (asprintf(&line, _(" on %.*s"), UT_LINESIZE,
			     last_login.ll_line) < 0) {
		    pam_syslog(pamh, LOG_ERR, "out of memory");
		    retval = PAM_BUF_ERR;
		    goto cleanup;
		}
	    }

	    if (date != NULL || host != NULL || line != NULL)
		    /* TRANSLATORS: "Last login: <date> from <host> on <terminal>" */
		    retval = pam_info(pamh, _("Last login:%s%s%s"),
			      date ? date : "",
			      host ? host : "",
			      line ? line : "");
	} else if (announce & LASTLOG_NEVER) {
		D(("this is the first time this user has logged in"));
		retval = pam_info(pamh, "%s", _("Welcome to your new account!"));
	}
    }

    /* cleanup */
 cleanup:
    memset(&last_login, 0, sizeof(last_login));
    _pam_overwrite(date);
    _pam_overwrite(host);
    _pam_drop(host);
    _pam_overwrite(line);
    _pam_drop(line);

    return retval;
}
Esempio n. 4
0
static int
last_login_failed(pam_handle_t *pamh, int announce, const char *user, time_t lltime)
{
    int retval;
    int fd;
    struct utmp ut;
    struct utmp utuser;
    int failed = 0;
    char the_time[256];
    char *date = NULL;
    char *host = NULL;
    char *line = NULL;

    if (strlen(user) > UT_NAMESIZE) {
	pam_syslog(pamh, LOG_WARNING, "username too long, output might be inaccurate");
    }

    /* obtain the failed login attempt records from btmp */
    fd = open(_PATH_BTMP, O_RDONLY);
    if (fd < 0) {
        int save_errno = errno;
	pam_syslog(pamh, LOG_ERR, "unable to open %s: %m", _PATH_BTMP);
	D(("unable to open %s file", _PATH_BTMP));
        if (save_errno == ENOENT)
	  return PAM_SUCCESS;
	else
	  return PAM_SERVICE_ERR;
    }

    while ((retval=pam_modutil_read(fd, (void *)&ut,
			 sizeof(ut))) == sizeof(ut)) {
	if (ut.ut_tv.tv_sec >= lltime && strncmp(ut.ut_user, user, UT_NAMESIZE) == 0) {
	    memcpy(&utuser, &ut, sizeof(utuser));
	    failed++;
	}
    }

    if (failed) {
	/* we want the date? */
	if (announce & LASTLOG_DATE) {
	    struct tm *tm, tm_buf;
	    time_t lf_time;

	    lf_time = utuser.ut_tv.tv_sec;
	    tm = localtime_r (&lf_time, &tm_buf);
	    strftime (the_time, sizeof (the_time),
	        /* TRANSLATORS: "strftime options for date of last login" */
		_(" %a %b %e %H:%M:%S %Z %Y"), tm);

	    date = the_time;
	}

	/* we want & have the host? */
	if ((announce & LASTLOG_HOST)
		&& (utuser.ut_host[0] != '\0')) {
	    /* TRANSLATORS: " from <host>" */
	    if (asprintf(&host, _(" from %.*s"), UT_HOSTSIZE,
		    utuser.ut_host) < 0) {
		pam_syslog(pamh, LOG_ERR, "out of memory");
		retval = PAM_BUF_ERR;
		goto cleanup;
	    }
	}

	/* we want and have the terminal? */
	if ((announce & LASTLOG_LINE)
		&& (utuser.ut_line[0] != '\0')) {
	    /* TRANSLATORS: " on <terminal>" */
	    if (asprintf(&line, _(" on %.*s"), UT_LINESIZE,
			utuser.ut_line) < 0) {
		pam_syslog(pamh, LOG_ERR, "out of memory");
		retval = PAM_BUF_ERR;
		goto cleanup;
	    }
	}

	if (line != NULL || date != NULL || host != NULL) {
	    /* TRANSLATORS: "Last failed login: <date> from <host> on <terminal>" */
	    pam_info(pamh, _("Last failed login:%s%s%s"),
			      date ? date : "",
			      host ? host : "",
			      line ? line : "");
	}

	_pam_drop(line);
#if defined HAVE_DNGETTEXT && defined ENABLE_NLS
        retval = asprintf (&line, dngettext(PACKAGE,
		"There was %d failed login attempt since the last successful login.",
		"There were %d failed login attempts since the last successful login.",
		failed),
	    failed);
#else
	if (failed == 1)
	    retval = asprintf(&line,
		_("There was %d failed login attempt since the last successful login."),
		failed);
	else
	    retval = asprintf(&line,
		/* TRANSLATORS: only used if dngettext is not supported */
		_("There were %d failed login attempts since the last successful login."),
		failed);
#endif
	if (retval >= 0)
		retval = pam_info(pamh, "%s", line);
	else {
		retval = PAM_BUF_ERR;
		line = NULL;
	}
    }

cleanup:
    free(host);
    free(line);
    close(fd);
    D(("all done with btmp"));

    return retval;
}
Esempio n. 5
0
/* Do the actual work of creating a home dir */
static int
create_homedir(const struct passwd *pwd,
	       const char *source, const char *dest)
{
   char remark[BUFSIZ];
   DIR *d;
   struct dirent *dent;
   int retval = PAM_SESSION_ERR;

   /* Create the new directory */
   if (rec_mkdir(dest, 0755) != 0)
   {
      pam_syslog(NULL, LOG_ERR, "unable to create directory %s: %m", dest);
      return PAM_PERM_DENIED;
   }

   /* See if we need to copy the skel dir over. */
   if ((source == NULL) || (strlen(source) == 0))
   {
      retval = PAM_SUCCESS;
      goto go_out;
   }

   /* Scan the directory */
   d = opendir(source);
   if (d == NULL)
   {
      pam_syslog(NULL, LOG_DEBUG, "unable to read directory %s: %m", source);
      retval = PAM_PERM_DENIED;
      goto go_out;
   }

   for (dent = readdir(d); dent != NULL; dent = readdir(d))
   {
      int srcfd;
      int destfd;
      int res;
      struct stat st;
#ifndef PATH_MAX
      char *newsource = NULL, *newdest = NULL;
      /* track length of buffers */
      int nslen = 0, ndlen = 0;
      int slen = strlen(source), dlen = strlen(dest);
#else
      char newsource[PATH_MAX], newdest[PATH_MAX];
#endif

      /* Skip some files.. */
      if (strcmp(dent->d_name,".") == 0 ||
	  strcmp(dent->d_name,"..") == 0)
	 continue;

      /* Determine what kind of file it is. */
#ifndef PATH_MAX
      nslen = slen + strlen(dent->d_name) + 2;

      if (nslen <= 0)
	{
	  retval = PAM_BUF_ERR;
	  goto go_out;
	}

      if ((newsource = malloc(nslen)) == NULL)
	{
	  retval = PAM_BUF_ERR;
	  goto go_out;
	}

      sprintf(newsource, "%s/%s", source, dent->d_name);
#else
      snprintf(newsource, sizeof(newsource), "%s/%s", source, dent->d_name);
#endif

      if (lstat(newsource, &st) != 0)
#ifndef PATH_MAX
      {
	      free(newsource);
	      newsource = NULL;
         continue;
      }
#else
      continue;
#endif


      /* We'll need the new file's name. */
#ifndef PATH_MAX
      ndlen = dlen + strlen(dent->d_name)+2;

      if (ndlen <= 0)
	{
	  retval = PAM_BUF_ERR;
	  goto go_out;
	}

      if ((newdest = malloc(ndlen)) == NULL)
	{
	  free (newsource);
	  retval = PAM_BUF_ERR;
	  goto go_out;
	}

      sprintf (newdest, "%s/%s", dest, dent->d_name);
#else
      snprintf (newdest, sizeof (newdest), "%s/%s", dest, dent->d_name);
#endif

      /* If it's a directory, recurse. */
      if (S_ISDIR(st.st_mode))
      {
         retval = create_homedir(pwd, newsource, newdest);

#ifndef PATH_MAX
	 free(newsource); newsource = NULL;
	 free(newdest); newdest = NULL;
#endif

         if (retval != PAM_SUCCESS)
	   {
	     closedir(d);
	     goto go_out;
	   }
         continue;
      }

      /* If it's a symlink, create a new link. */
      if (S_ISLNK(st.st_mode))
      {
	 int pointedlen = 0;
#ifndef PATH_MAX
	 char *pointed = NULL;
           {
		   int size = 100;

		   while (1) {
			   pointed = malloc(size);
			   if (pointed == NULL) {
				   free(newsource);
				   free(newdest);
				   return PAM_BUF_ERR;
			   }
			   pointedlen = readlink(newsource, pointed, size);
			   if (pointedlen < 0) break;
			   if (pointedlen < size) break;
			   free(pointed);
			   size *= 2;
		   }
	   }
	   if (pointedlen < 0)
		   free(pointed);
	   else
		   pointed[pointedlen] = 0;
#else
         char pointed[PATH_MAX];
         memset(pointed, 0, sizeof(pointed));

         pointedlen = readlink(newsource, pointed, sizeof(pointed) - 1);
#endif

	 if (pointedlen >= 0) {
            if(symlink(pointed, newdest) == 0)
            {
               if (lchown(newdest, pwd->pw_uid, pwd->pw_gid) != 0)
               {
                   pam_syslog(NULL, LOG_DEBUG,
			      "unable to change perms on link %s: %m", newdest);
                   closedir(d);
#ifndef PATH_MAX
		   free(pointed);
		   free(newsource);
		   free(newdest);
#endif
                   return PAM_PERM_DENIED;
               }
            }
#ifndef PATH_MAX
	    free(pointed);
#endif
         }
#ifndef PATH_MAX
	 free(newsource); newsource = NULL;
	 free(newdest); newdest = NULL;
#endif
         continue;
      }

      /* If it's not a regular file, it's probably not a good idea to create
       * the new device node, FIFO, or whatever it is. */
      if (!S_ISREG(st.st_mode))
      {
#ifndef PATH_MAX
	 free(newsource); newsource = NULL;
	 free(newdest); newdest = NULL;
#endif
         continue;
      }

      /* Open the source file */
      if ((srcfd = open(newsource, O_RDONLY)) < 0 || fstat(srcfd, &st) != 0)
      {
         pam_syslog(NULL, LOG_DEBUG,
		    "unable to open src file %s: %m", newsource);
         closedir(d);

#ifndef PATH_MAX
	 free(newsource); newsource = NULL;
	 free(newdest); newdest = NULL;
#endif

	 return PAM_PERM_DENIED;
      }
      if (stat(newsource, &st) != 0)
	{
	  pam_syslog(NULL, LOG_DEBUG, "unable to stat src file %s: %m",
		     newsource);
	  close(srcfd);
	  closedir(d);

#ifndef PATH_MAX
	  free(newsource); newsource = NULL;
	  free(newdest); newdest = NULL;
#endif

	  return PAM_PERM_DENIED;
	}

      /* Open the dest file */
      if ((destfd = open(newdest, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0)
      {
         pam_syslog(NULL, LOG_DEBUG,
		    "unable to open dest file %s: %m", newdest);
	 close(srcfd);
	 closedir(d);

#ifndef PATH_MAX
	 free(newsource); newsource = NULL;
	 free(newdest); newdest = NULL;
#endif
	 return PAM_PERM_DENIED;
      }

      /* Set the proper ownership and permissions for the module. We make
       	 the file a+w and then mask it with the set mask. This preseves
       	 execute bits */
      if (fchmod(destfd, (st.st_mode | 0222) & (~u_mask)) != 0 ||
	  fchown(destfd, pwd->pw_uid, pwd->pw_gid) != 0)
      {
         pam_syslog(NULL, LOG_DEBUG,
		    "unable to change perms on copy %s: %m", newdest);
         close(srcfd);
         close(destfd);
         closedir(d);

#ifndef PATH_MAX
	 free(newsource); newsource = NULL;
	 free(newdest); newdest = NULL;
#endif

	 return PAM_PERM_DENIED;
      }

      /* Copy the file */
      do
      {
	 res = pam_modutil_read(srcfd, remark, sizeof(remark));

	 if (res == 0)
	     continue;

	 if (res > 0) {
	     if (pam_modutil_write(destfd, remark, res) == res)
		continue;
	 }

	 /* If we get here, pam_modutil_read returned a -1 or
	    pam_modutil_write returned something unexpected. */
	 pam_syslog(NULL, LOG_DEBUG, "unable to perform IO: %m");
	 close(srcfd);
	 close(destfd);
	 closedir(d);

#ifndef PATH_MAX
	 free(newsource); newsource = NULL;
	 free(newdest); newdest = NULL;
#endif

	 return PAM_PERM_DENIED;
      }
      while (res != 0);
      close(srcfd);
      close(destfd);

#ifndef PATH_MAX
      free(newsource); newsource = NULL;
      free(newdest); newdest = NULL;
#endif

   }
   closedir(d);

   retval = PAM_SUCCESS;

 go_out:

   if (chmod(dest, 0777 & (~u_mask)) != 0 ||
       chown(dest, pwd->pw_uid, pwd->pw_gid) != 0)
   {
      pam_syslog(NULL, LOG_DEBUG,
		 "unable to change perms on directory %s: %m", dest);
      return PAM_PERM_DENIED;
   }

   return retval;
}