crypt.c 4.22 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*-------------------------------------------------------------------------
 *
 * crypt.c--
 *        Look into pg_user and check the encrypted password with the one
 *        passed in from the frontend.
 *
 *
 *-------------------------------------------------------------------------
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif

19 20 21 22 23
#include "postgres.h"
#include "libpq/crypt.h"
#include "utils/nabstime.h"
#include "utils/palloc.h"
#include "storage/fd.h"
24 25 26 27 28 29

char* crypt_getpwdfilename() {

  static char*     filename = NULL;

  if (!filename) {
30
    char*     env = NULL;
31 32

    env = getenv("PGDATA");
33 34 35 36
    if(env == NULL) {
      elog(FATAL, "crypt.c: PGDATA is not defined");
      exit(-1);
    }
37
    filename = (char*)palloc(strlen(env) + strlen(CRYPT_PWD_FILE) + 2);
38 39 40 41 42 43 44 45 46 47 48 49 50 51
    sprintf(filename, "%s/%s", env, CRYPT_PWD_FILE);
  }

  return filename;
}

/*-------------------------------------------------------------------------*/

static
FILE* crypt_openpwdfile() {

  char*     filename;

  filename = crypt_getpwdfilename();
52
  return (AllocateFile(filename, "r"));
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
}

/*-------------------------------------------------------------------------*/

static
void crypt_parsepwdfile(FILE* datafile, char** login, char** pwd, char** valdate) {

  char     buffer[256];
  char*    parse;
  int      count,
           i;

  fgets(buffer, 256, datafile);
  parse = buffer;

  /* store a copy of user login to return
   */
  count = strcspn(parse, "#");
71
  *login = (char*)palloc(count + 1);
72 73 74 75 76 77 78 79 80 81 82 83
  strncpy(*login, parse, count);
  (*login)[count] = '\0';
  parse += (count + 1);

  /* skip to the password field
   */
  for (i = 0; i < 5; i++)
    parse += (strcspn(parse, "#") + 1);

  /* store a copy of user password to return
   */
  count = strcspn(parse, "#");
84
  *pwd = (char*)palloc(count + 1);
85 86 87 88 89 90 91
  strncpy(*pwd, parse, count);
  (*pwd)[count] = '\0';
  parse += (count + 1);

  /* store a copy of date login becomes invalid
   */
  count = strcspn(parse, "#");
92
  *valdate = (char*)palloc(count + 1);
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
  strncpy(*valdate, parse, count);
  (*valdate)[count] = '\0';
  parse += (count + 1);
}

/*-------------------------------------------------------------------------*/

static
void crypt_getloginfo(const char* user, char** passwd, char** valuntil) {

  FILE*     datafile;
  char*     login;
  char*     pwd;
  char*     valdate;

  *passwd = NULL;
  *valuntil = NULL;

  if (!(datafile = crypt_openpwdfile()))
    return;

  while (!feof(datafile)) {
    crypt_parsepwdfile(datafile, &login, &pwd, &valdate);
    if (!strcmp(login, user)) {
117
      pfree((void*)login);
118 119 120 121 122
      *passwd = pwd;
      *valuntil = valdate;
      fclose(datafile);
      return;
    }
123 124 125
    pfree((void*)login);
    pfree((void*)pwd);
    pfree((void*)valdate);
126 127 128 129 130 131 132 133 134 135 136 137 138 139
  }
  fclose(datafile);
}

/*-------------------------------------------------------------------------*/

MsgType crypt_salt(const char* user) {

  char*     passwd;
  char*     valuntil;

  crypt_getloginfo(user, &passwd, &valuntil);

  if (passwd == NULL || *passwd == '\0') {
140 141
    if (passwd) pfree((void*)passwd);
    if (valuntil) pfree((void*)valuntil);
142 143 144
    return STARTUP_UNSALT_MSG;
  }

145 146
  pfree((void*)passwd);
  if (valuntil) pfree((void*)valuntil);
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
  return STARTUP_SALT_MSG;
}

/*-------------------------------------------------------------------------*/

int crypt_verify(Port* port, const char* user, const char* pgpass) {

  char*            passwd;
  char*            valuntil;
  char*            crypt_pwd;
  int              retval = STATUS_ERROR;
  AbsoluteTime     vuntil,
                   current;

  crypt_getloginfo(user, &passwd, &valuntil);

  if (passwd == NULL || *passwd == '\0') {
164 165
    if (passwd) pfree((void*)passwd);
    if (valuntil) pfree((void*)valuntil);
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
    return STATUS_ERROR;
  }

  crypt_pwd = crypt(passwd, port->salt);
  if (!strcmp(pgpass, crypt_pwd)) {
    /* check here to be sure we are not past valuntil
     */
    if (!valuntil)
      vuntil = INVALID_ABSTIME;
    else
      vuntil = nabstimein(valuntil);
    current = GetCurrentAbsoluteTime();
    if (vuntil != INVALID_ABSTIME && vuntil < current)
      retval = STATUS_ERROR;
    else
      retval = STATUS_OK;
  }

184 185
  pfree((void*)passwd);
  if (valuntil) pfree((void*)valuntil);
186 187 188
  
  return retval;
}