(root)/
Linux-PAM-1.5.3/
libpam/
pam_modutil_getspnam.c
       1  /*
       2   * $Id$
       3   *
       4   * This function provides a thread safer version of getspnam() for use
       5   * with PAM modules that care about this sort of thing.
       6   *
       7   * XXX - or at least it should provide a thread-safe alternative.
       8   */
       9  
      10  #include "pam_modutil_private.h"
      11  
      12  #include <errno.h>
      13  #include <limits.h>
      14  #include <shadow.h>
      15  #include <stdio.h>
      16  #include <stdlib.h>
      17  
      18  static int intlen(int number)
      19  {
      20      int len = 2;
      21      while (number != 0) {
      22          number /= 10;
      23  	len++;
      24      }
      25      return len;
      26  }
      27  
      28  struct spwd *
      29  pam_modutil_getspnam(pam_handle_t *pamh, const char *user)
      30  {
      31  #ifdef HAVE_GETSPNAM_R
      32  
      33      void *buffer=NULL;
      34      size_t length = PWD_INITIAL_LENGTH;
      35  
      36      do {
      37  	int status;
      38  	void *new_buffer;
      39  	struct spwd *result = NULL;
      40  
      41  	new_buffer = realloc(buffer, sizeof(struct spwd) + length);
      42  	if (new_buffer == NULL) {
      43  
      44  	    D(("out of memory"));
      45  
      46  	    /* no memory for the user - so delete the memory */
      47  	    if (buffer) {
      48  		free(buffer);
      49  	    }
      50  	    return NULL;
      51  	}
      52  	buffer = new_buffer;
      53  
      54  	/* make the re-entrant call to get the spwd structure */
      55          errno = 0;
      56  	status = getspnam_r(user, buffer,
      57  			    sizeof(struct spwd) + (char *) buffer,
      58  			    length, &result);
      59  	if (!status && (result == buffer)) {
      60  	    char *data_name;
      61  	    const void *ignore;
      62  	    int i;
      63  
      64  	    data_name = malloc(strlen("_pammodutil_getspnam") + 1 +
      65  			       strlen(user) + 1 + intlen(INT_MAX) + 1);
      66  	    if ((pamh != NULL) && (data_name == NULL)) {
      67  	        D(("was unable to register the data item [%s]",
      68  	           pam_strerror(pamh, status)));
      69  		free(buffer);
      70  		return NULL;
      71  	    }
      72  
      73  	    if (pamh != NULL) {
      74  	        for (i = 0; i < INT_MAX; i++) {
      75  	            sprintf(data_name, "_pammodutil_getspnam_%s_%d", user, i);
      76  		    status = PAM_NO_MODULE_DATA;
      77  	            if (pam_get_data(pamh, data_name, &ignore) != PAM_SUCCESS) {
      78  		        status = pam_set_data(pamh, data_name,
      79  					      result, pam_modutil_cleanup);
      80  		    }
      81  		    if (status == PAM_SUCCESS) {
      82  		        break;
      83  		    }
      84  		}
      85  	    } else {
      86  	        status = PAM_SUCCESS;
      87  	    }
      88  
      89  	    free(data_name);
      90  
      91  	    if (status == PAM_SUCCESS) {
      92  		D(("success"));
      93  		return result;
      94  	    }
      95  
      96  	    D(("was unable to register the data item [%s]",
      97  	       pam_strerror(pamh, status)));
      98  
      99  	    free(buffer);
     100  	    return NULL;
     101  
     102  	} else if (errno != ERANGE && errno != EINTR) {
     103                  /* no sense in repeating the call */
     104                  break;
     105          }
     106  
     107  	length <<= PWD_LENGTH_SHIFT;
     108  
     109      } while (length < PWD_ABSURD_PWD_LENGTH);
     110  
     111      D(("spwd structure took %u bytes or so of memory",
     112         length+sizeof(struct spwd)));
     113  
     114      free(buffer);
     115      return NULL;
     116  
     117  #else /* ie. ifndef HAVE_GETSPNAM_R */
     118  
     119      /*
     120       * Sorry, there does not appear to be a reentrant version of
     121       * getspnam(). So, we use the standard libc function.
     122       */
     123  
     124      return getspnam(user);
     125  
     126  #endif /* def HAVE_GETSPNAM_R */
     127  }