(root)/
Linux-PAM-1.5.3/
libpam/
pam_modutil_check_user.c
       1  #include "pam_modutil_private.h"
       2  #include <security/pam_ext.h>
       3  
       4  #include <stdio.h>
       5  #include <string.h>
       6  #include <syslog.h>
       7  
       8  int
       9  pam_modutil_check_user_in_passwd(pam_handle_t *pamh,
      10  				 const char *user_name,
      11  				 const char *file_name)
      12  {
      13  	int rc;
      14  	size_t user_len;
      15  	FILE *fp;
      16  	char line[BUFSIZ];
      17  
      18  	/* Validate the user name.  */
      19  	if ((user_len = strlen(user_name)) == 0) {
      20  		pam_syslog(pamh, LOG_NOTICE, "user name is not valid");
      21  		return PAM_SERVICE_ERR;
      22  	}
      23  
      24  	if (user_len > sizeof(line) - sizeof(":")) {
      25  		pam_syslog(pamh, LOG_NOTICE, "user name is too long");
      26  		return PAM_SERVICE_ERR;
      27  	}
      28  
      29  	if (strchr(user_name, ':') != NULL) {
      30  		/*
      31  		 * "root:x" is not a local user name even if the passwd file
      32  		 * contains a line starting with "root:x:".
      33  		 */
      34  		return PAM_PERM_DENIED;
      35  	}
      36  
      37  	/* Open the passwd file.  */
      38  	if (file_name == NULL) {
      39  		file_name = "/etc/passwd";
      40  	}
      41  	if ((fp = fopen(file_name, "r")) == NULL) {
      42  		pam_syslog(pamh, LOG_ERR, "error opening %s: %m", file_name);
      43  		return PAM_SERVICE_ERR;
      44  	}
      45  
      46  	/*
      47  	 * Scan the file using fgets() instead of fgetpwent_r() because
      48  	 * the latter is not flexible enough in handling long lines
      49  	 * in passwd files.
      50  	 */
      51  	rc = PAM_PERM_DENIED;
      52  	while (fgets(line, sizeof(line), fp) != NULL) {
      53  		size_t line_len;
      54  		const char *str;
      55  
      56  		/*
      57  		 * Does this line start with the user name
      58  		 * followed by a colon?
      59  		 */
      60  		if (strncmp(user_name, line, user_len) == 0 &&
      61  		    line[user_len] == ':') {
      62  			rc = PAM_SUCCESS;
      63  			/*
      64  			 * Continue reading the file to avoid timing attacks.
      65  			 */
      66  		}
      67  		/* Has a newline been read?  */
      68  		line_len = strlen(line);
      69  		if (line_len < sizeof(line) - 1 ||
      70  		    line[line_len - 1] == '\n') {
      71  			/* Yes, continue with the next line.  */
      72  			continue;
      73  		}
      74  
      75  		/* No, read till the end of this line first.  */
      76  		while ((str = fgets(line, sizeof(line), fp)) != NULL) {
      77  			line_len = strlen(line);
      78  			if (line_len == 0 ||
      79  			    line[line_len - 1] == '\n') {
      80  				break;
      81  			}
      82  		}
      83  		if (str == NULL) {
      84  			/* fgets returned NULL, we are done.  */
      85  			break;
      86  		}
      87  		/* Continue with the next line.  */
      88  	}
      89  
      90  	fclose(fp);
      91  	return rc;
      92  }