(root)/
Linux-PAM-1.5.3/
modules/
pam_faillock/
main.c
       1  /*
       2   * Copyright (c) 2010 Tomas Mraz <tmraz@redhat.com>
       3   * Copyright (c) 2010 Red Hat, Inc.
       4   *
       5   * Redistribution and use in source and binary forms, with or without
       6   * modification, are permitted provided that the following conditions
       7   * are met:
       8   * 1. Redistributions of source code must retain the above copyright
       9   *    notice, and the entire permission notice in its entirety,
      10   *    including the disclaimer of warranties.
      11   * 2. Redistributions in binary form must reproduce the above copyright
      12   *    notice, this list of conditions and the following disclaimer in the
      13   *    documentation and/or other materials provided with the distribution.
      14   * 3. The name of the author may not be used to endorse or promote
      15   *    products derived from this software without specific prior
      16   *    written permission.
      17   *
      18   * ALTERNATIVELY, this product may be distributed under the terms of
      19   * the GNU Public License, in which case the provisions of the GPL are
      20   * required INSTEAD OF the above restrictions.  (This clause is
      21   * necessary due to a potential bad interaction between the GPL and
      22   * the restrictions contained in a BSD-style copyright.)
      23   *
      24   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
      25   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      26   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
      27   * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
      28   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
      29   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      30   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      31   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
      32   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      33   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
      34   * OF THE POSSIBILITY OF SUCH DAMAGE.
      35   */
      36  
      37  #include "config.h"
      38  
      39  #include <stdio.h>
      40  #include <stdlib.h>
      41  #include <string.h>
      42  #include <dirent.h>
      43  #include <errno.h>
      44  #include <pwd.h>
      45  #include <time.h>
      46  #include <sys/types.h>
      47  #include <unistd.h>
      48  #ifdef HAVE_LIBAUDIT
      49  #include <libaudit.h>
      50  
      51  #define AUDIT_NO_ID     ((unsigned int) -1)
      52  #endif
      53  
      54  #include "pam_inline.h"
      55  #include "faillock.h"
      56  #include "faillock_config.h"
      57  
      58  static int
      59  args_parse(int argc, char **argv, struct options *opts)
      60  {
      61  	int i;
      62  	int rv;
      63  	const char *dir = NULL;
      64  	const char *conf = NULL;
      65  
      66  	memset(opts, 0, sizeof(*opts));
      67  
      68  	opts->progname = argv[0];
      69  
      70  	for (i = 1; i < argc; ++i) {
      71  		if (strcmp(argv[i], "--conf") == 0) {
      72  			++i;
      73  			if (i >= argc || strlen(argv[i]) == 0) {
      74  				fprintf(stderr, "%s: No configuration file supplied.\n",
      75  						argv[0]);
      76  				return -1;
      77  			}
      78  			conf = argv[i];
      79  		}
      80  		else if (strcmp(argv[i], "--dir") == 0) {
      81  			++i;
      82  			if (i >= argc || strlen(argv[i]) == 0) {
      83  				fprintf(stderr, "%s: No records directory supplied.\n",
      84  						argv[0]);
      85  				return -1;
      86  			}
      87  			dir = argv[i];
      88  		}
      89  		else if (strcmp(argv[i], "--user") == 0) {
      90  			++i;
      91  			if (i >= argc || strlen(argv[i]) == 0) {
      92  				fprintf(stderr, "%s: No user name supplied.\n", argv[0]);
      93  				return -1;
      94  			}
      95  			opts->user = argv[i];
      96  		}
      97  		else if (strcmp(argv[i], "--reset") == 0) {
      98  			opts->reset = 1;
      99  		}
     100  		else if (!strcmp(argv[i], "--legacy-output")) {
     101  			opts->legacy_output = 1;
     102  		}
     103  		else {
     104  			fprintf(stderr, "%s: Unknown option: %s\n", argv[0], argv[i]);
     105  			return -1;
     106  		}
     107  	}
     108  
     109  	if ((rv = read_config_file(NULL, opts, conf)) != PAM_SUCCESS) {
     110  		fprintf(stderr, "Configuration file missing or broken");
     111  		return rv;
     112  	}
     113  
     114  	if (dir != NULL) {
     115  		free(opts->dir);
     116  		opts->dir = strdup(dir);
     117  		if (opts->dir == NULL) {
     118  			fprintf(stderr, "Error allocating memory: %m");
     119  			return -1;
     120  		}
     121  	}
     122  
     123  	return 0;
     124  }
     125  
     126  static void
     127  usage(const char *progname)
     128  {
     129  	fprintf(stderr,
     130  		_("Usage: %s [--dir /path/to/tally-directory]"
     131  		  " [--user username] [--reset] [--legacy-output]\n"), progname);
     132  
     133  }
     134  
     135  static int
     136  get_local_time(time_t when, char *timebuf, size_t timebuf_size)
     137  {
     138  	struct tm *tm;
     139  
     140  	tm = localtime(&when);
     141  	if (tm == NULL) {
     142  		return -1;
     143  	}
     144  	strftime(timebuf, timebuf_size, "%Y-%m-%d %H:%M:%S", tm);
     145  	return 0;
     146  }
     147  
     148  static void
     149  print_in_new_format(struct options *opts, const struct tally_data *tallies, const char *user)
     150  {
     151  	uint32_t i;
     152  
     153  	printf("%s:\n", user);
     154  	printf("%-19s %-5s %-48s %-5s\n", "When", "Type", "Source", "Valid");
     155  
     156  	for (i = 0; i < tallies->count; i++) {
     157  		uint16_t status;
     158  		char timebuf[80];
     159  
     160  		if (get_local_time(tallies->records[i].time, timebuf, sizeof(timebuf)) != 0) {
     161  			fprintf(stderr, "%s: Invalid timestamp in the tally record\n",
     162  				opts->progname);
     163  			continue;
     164  		}
     165  
     166  		status = tallies->records[i].status;
     167  
     168  		printf("%-19s %-5s %-52.52s %s\n", timebuf,
     169  			status & TALLY_STATUS_RHOST ? "RHOST" : (status & TALLY_STATUS_TTY ? "TTY" : "SVC"),
     170  			tallies->records[i].source, status & TALLY_STATUS_VALID ? "V":"I");
     171  	}
     172  }
     173  
     174  static void
     175  print_in_legacy_format(struct options *opts, const struct tally_data *tallies, const char *user)
     176  {
     177  	uint32_t tally_count;
     178  	static uint32_t pr_once;
     179  
     180  	if (pr_once == 0) {
     181  		printf(_("Login           Failures    Latest failure         From\n"));
     182  		pr_once = 1;
     183  	}
     184  
     185  	printf("%-15.15s ", user);
     186  
     187  	tally_count = tallies->count;
     188  
     189  	if (tally_count > 0) {
     190  		uint32_t i;
     191  		char timebuf[80];
     192  
     193  		i = tally_count - 1;
     194  
     195  		if (get_local_time(tallies->records[i].time, timebuf, sizeof(timebuf)) != 0) {
     196  			fprintf(stderr, "%s: Invalid timestamp in the tally record\n",
     197  				opts->progname);
     198  			return;
     199  		}
     200  
     201  		printf("%5u %25s    %s\n",
     202  			tally_count, timebuf, tallies->records[i].source);
     203  	}
     204  	else {
     205  		printf("%5u\n", tally_count);
     206  	}
     207  }
     208  
     209  static int
     210  do_user(struct options *opts, const char *user)
     211  {
     212  	int fd;
     213  	int rv;
     214  	struct tally_data tallies;
     215  	struct passwd *pwd;
     216  	const char *dir = get_tally_dir(opts);
     217  
     218  	pwd = getpwnam(user);
     219  	if (pwd == NULL) {
     220  	    fprintf(stderr, "%s: Error no such user: %s\n", opts->progname, user);
     221  	    return 1;
     222  	}
     223  
     224  	fd = open_tally(dir, user, pwd->pw_uid, 1);
     225  
     226  	if (fd == -1) {
     227  		if (errno == ENOENT) {
     228  			return 0;
     229  		}
     230  		else {
     231  			fprintf(stderr, "%s: Error opening the tally file for %s:",
     232  				opts->progname, user);
     233  			perror(NULL);
     234  			return 3;
     235  		}
     236  	}
     237  	if (opts->reset) {
     238  #ifdef HAVE_LIBAUDIT
     239  		int audit_fd;
     240  #endif
     241  
     242  		while ((rv=ftruncate(fd, 0)) == -1 && errno == EINTR);
     243  		if (rv == -1) {
     244  			fprintf(stderr, "%s: Error clearing the tally file for %s:",
     245  				opts->progname, user);
     246  			perror(NULL);
     247  #ifdef HAVE_LIBAUDIT
     248  		}
     249  		if ((audit_fd=audit_open()) >= 0) {
     250  			audit_log_acct_message(audit_fd, AUDIT_USER_MGMT, NULL,
     251  				"faillock-reset", user,
     252  				pwd != NULL ? pwd->pw_uid : AUDIT_NO_ID,
     253  				NULL, NULL, NULL, rv == 0);
     254  			close(audit_fd);
     255  		}
     256  		if (rv == -1) {
     257  #endif
     258  			close(fd);
     259  			return 4;
     260  		}
     261  	}
     262  	else {
     263  		memset(&tallies, 0, sizeof(tallies));
     264  		if (read_tally(fd, &tallies) == -1) {
     265  			fprintf(stderr, "%s: Error reading the tally file for %s:",
     266  				opts->progname, user);
     267  			perror(NULL);
     268  			close(fd);
     269  			return 5;
     270  		}
     271  
     272  		if (opts->legacy_output == 0) {
     273  			print_in_new_format(opts, &tallies, user);
     274  		}
     275  		else {
     276  			print_in_legacy_format(opts, &tallies, user);
     277  		}
     278  
     279  		free(tallies.records);
     280  	}
     281  	close(fd);
     282  	return 0;
     283  }
     284  
     285  static int
     286  do_allusers(struct options *opts)
     287  {
     288  	struct dirent **userlist;
     289  	int rv, i;
     290  	const char *dir = get_tally_dir(opts);
     291  
     292  	rv = scandir(dir, &userlist, NULL, alphasort);
     293  	if (rv < 0) {
     294  		fprintf(stderr, "%s: Error reading tally directory: %m\n", opts->progname);
     295  		return 2;
     296  	}
     297  
     298  	for (i = 0; i < rv; i++) {
     299  		if (userlist[i]->d_name[0] == '.') {
     300  			if ((userlist[i]->d_name[1] == '.' && userlist[i]->d_name[2] == '\0') ||
     301  			    userlist[i]->d_name[1] == '\0')
     302  				continue;
     303  		}
     304  		do_user(opts, userlist[i]->d_name);
     305  		free(userlist[i]);
     306  	}
     307  	free(userlist);
     308  
     309  	return 0;
     310  }
     311  
     312  
     313  /*-----------------------------------------------------------------------*/
     314  int
     315  main (int argc, char *argv[])
     316  {
     317  	struct options opts;
     318  
     319  	if (args_parse(argc, argv, &opts)) {
     320  		usage(argv[0]);
     321  		return 1;
     322  	}
     323  
     324  	if (opts.user == NULL) {
     325  		return do_allusers(&opts);
     326  	}
     327  
     328  	return do_user(&opts, opts.user);
     329  }