(root)/
Linux-PAM-1.5.3/
modules/
pam_faillock/
faillock.c
       1  /*
       2   * Copyright (c) 2010 Tomas Mraz <tmraz@redhat.com>
       3   * Copyright (c) 2010, 2016, 2017 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  #include <string.h>
      39  #include <stdlib.h>
      40  #include <unistd.h>
      41  #include <errno.h>
      42  #include <sys/types.h>
      43  #include <sys/stat.h>
      44  #include <sys/file.h>
      45  #include <sys/stat.h>
      46  #include <fcntl.h>
      47  #include <security/pam_modutil.h>
      48  
      49  #include "faillock.h"
      50  
      51  #define ignore_return(x) if (1==((int)x)) {;}
      52  
      53  int
      54  open_tally (const char *dir, const char *user, uid_t uid, int create)
      55  {
      56  	char *path;
      57  	int flags = O_RDWR;
      58  	int fd;
      59  
      60  	if (dir == NULL || strstr(user, "../") != NULL)
      61  	/* just a defensive programming as the user must be a
      62  	 * valid user on the system anyway
      63  	 */
      64  		return -1;
      65  	path = malloc(strlen(dir) + strlen(user) + 2);
      66  	if (path == NULL)
      67  		return -1;
      68  
      69  	strcpy(path, dir);
      70  	if (*dir && dir[strlen(dir) - 1] != '/') {
      71  		strcat(path, "/");
      72  	}
      73  	strcat(path, user);
      74  
      75  	if (create) {
      76  		flags |= O_CREAT;
      77  		if (access(dir, F_OK) != 0) {
      78  			mkdir(dir, 0755);
      79  		}
      80  	}
      81  
      82  	fd = open(path, flags, 0660);
      83  
      84  	free(path);
      85  
      86  	if (fd != -1) {
      87  		struct stat st;
      88  
      89  		while (flock(fd, LOCK_EX) == -1 && errno == EINTR);
      90  		if (fstat(fd, &st) == 0) {
      91  			if (st.st_uid != uid) {
      92  				ignore_return(fchown(fd, uid, -1));
      93  			}
      94  
      95  			/*
      96  			 * If umask is set to 022, as will probably in most systems, then the
      97  			 * group will not be able to write to the file. So, change the file
      98  			 * permissions just in case.
      99  			 * Note: owners of this file are user:root, so if the permissions are
     100  			 * not changed the root process writing to this file will require
     101  			 * CAP_DAC_OVERRIDE.
     102  			 */
     103  			if (!(st.st_mode & S_IWGRP)) {
     104  				ignore_return(fchmod(fd, 0660));
     105  			}
     106  		}
     107  	}
     108  
     109  	return fd;
     110  }
     111  
     112  #define CHUNK_SIZE (64 * sizeof(struct tally))
     113  #define MAX_RECORDS 1024
     114  
     115  int
     116  read_tally(int fd, struct tally_data *tallies)
     117  {
     118  	void *data = NULL, *newdata;
     119  	unsigned int count = 0;
     120  	ssize_t chunk = 0;
     121  
     122  	do {
     123  		newdata = realloc(data, count * sizeof(struct tally) + CHUNK_SIZE);
     124  		if (newdata == NULL) {
     125  			free(data);
     126  			return -1;
     127  		}
     128  
     129  		data = newdata;
     130  
     131  		chunk = pam_modutil_read(fd, (char *)data + count * sizeof(struct tally), CHUNK_SIZE);
     132  		if (chunk < 0) {
     133  			free(data);
     134  			return -1;
     135  		}
     136  
     137  		count += chunk/sizeof(struct tally);
     138  
     139  		if (count >= MAX_RECORDS)
     140  			break;
     141  	}
     142  	while (chunk == CHUNK_SIZE);
     143  
     144  	tallies->records = data;
     145  	tallies->count = count;
     146  
     147  	return 0;
     148  }
     149  
     150  int
     151  update_tally(int fd, struct tally_data *tallies)
     152  {
     153  	void *data = tallies->records;
     154  	unsigned int count = tallies->count;
     155  	ssize_t chunk;
     156  
     157  	if (tallies->count > MAX_RECORDS) {
     158  		data = tallies->records + (count - MAX_RECORDS);
     159  		count = MAX_RECORDS;
     160  	}
     161  
     162  	if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
     163  		return -1;
     164  	}
     165  
     166  	chunk = pam_modutil_write(fd, data, count * sizeof(struct tally));
     167  
     168  	if (chunk != (ssize_t)(count * sizeof(struct tally))) {
     169  		return -1;
     170  	}
     171  
     172  	if (ftruncate(fd, count * sizeof(struct tally)) == -1)
     173  		return -1;
     174  
     175  	return 0;
     176  }