crypt.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:7k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * crypt.c
  4.  * Look into pg_shadow and check the encrypted password with
  5.  * the one passed in from the frontend.
  6.  *
  7.  * Modification History
  8.  *
  9.  * Dec 17, 1997 - Todd A. Brandys
  10.  * Orignal Version Completed.
  11.  *
  12.  * $Id: crypt.c,v 1.18 1999/05/27 04:09:45 momjian Exp $
  13.  *
  14.  *-------------------------------------------------------------------------
  15.  */
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <stdlib.h>
  19. #include <unistd.h>
  20. #include "postgres.h"
  21. #include "miscadmin.h"
  22. #include "utils/nabstime.h"
  23. #include "storage/fd.h"
  24. #include "libpq/crypt.h"
  25. #ifdef HAVE_CRYPT_H
  26. #include <crypt.h>
  27. #endif
  28. char   **pwd_cache = NULL;
  29. int pwd_cache_count = 0;
  30. /*-------------------------------------------------------------------------*/
  31. char *
  32. crypt_getpwdfilename()
  33. {
  34. static char *pfnam = NULL;
  35. int bufsize;
  36. bufsize = strlen(DataDir) + strlen(CRYPT_PWD_FILE) + 2;
  37. pfnam = (char *) palloc(bufsize);
  38. snprintf(pfnam, bufsize, "%s/%s", DataDir, CRYPT_PWD_FILE);
  39. return pfnam;
  40. }
  41. /*-------------------------------------------------------------------------*/
  42. char *
  43. crypt_getpwdreloadfilename()
  44. {
  45. static char *rpfnam = NULL;
  46. char    *pwdfilename;
  47. int bufsize;
  48. pwdfilename = crypt_getpwdfilename();
  49. bufsize = strlen(pwdfilename) + strlen(CRYPT_PWD_RELOAD_SUFX) + 1;
  50. rpfnam = (char *) palloc(bufsize);
  51. snprintf(rpfnam, bufsize, "%s%s", pwdfilename, CRYPT_PWD_RELOAD_SUFX);
  52. return rpfnam;
  53. }
  54. /*-------------------------------------------------------------------------*/
  55. static
  56. FILE *
  57. crypt_openpwdfile()
  58. {
  59. char    *filename;
  60. FILE    *pwdfile;
  61. filename = crypt_getpwdfilename();
  62. #ifndef __CYGWIN32__
  63. pwdfile = AllocateFile(filename, "r");
  64. #else
  65. pwdfile = AllocateFile(filename, "rb");
  66. #endif
  67. return pwdfile;
  68. }
  69. /*-------------------------------------------------------------------------*/
  70. static
  71. int
  72. compar_user(const void *user_a, const void *user_b)
  73. {
  74. int min,
  75. value;
  76. char    *login_a;
  77. char    *login_b;
  78. login_a = *((char **) user_a);
  79. login_b = *((char **) user_b);
  80. /*
  81.  * We only really want to compare the user logins which are first. We
  82.  * look for the first SEPSTR char getting the number of chars there
  83.  * are before it. We only need to compare to the min count from the
  84.  * two strings.
  85.  */
  86. min = strcspn(login_a, CRYPT_PWD_FILE_SEPSTR);
  87. value = strcspn(login_b, CRYPT_PWD_FILE_SEPSTR);
  88. if (value < min)
  89. min = value;
  90. /*
  91.  * We add one to min so that the separator character is included in
  92.  * the comparison. Why?  I believe this will prevent logins that are
  93.  * proper prefixes of other logins from being 'masked out'.  Being
  94.  * conservative!
  95.  */
  96. return strncmp(login_a, login_b, min + 1);
  97. }
  98. /*-------------------------------------------------------------------------*/
  99. static
  100. void
  101. crypt_loadpwdfile()
  102. {
  103. char    *filename;
  104. int result;
  105. FILE    *pwd_file;
  106. char buffer[256];
  107. filename = crypt_getpwdreloadfilename();
  108. result = unlink(filename);
  109. /*
  110.  * We want to delete the flag file before reading the contents of the
  111.  * pg_pwd file.  If result == 0 then the unlink of the reload file was
  112.  * successful. This means that a backend performed a COPY of the
  113.  * pg_shadow file to pg_pwd.  Therefore we must now do a reload.
  114.  */
  115. if (!pwd_cache || !result)
  116. {
  117. if (pwd_cache)
  118. { /* free the old data only if this is a
  119.  * reload */
  120. while (pwd_cache_count--)
  121. free((void *) pwd_cache[pwd_cache_count]);
  122. free((void *) pwd_cache);
  123. pwd_cache = NULL;
  124. pwd_cache_count = 0;
  125. }
  126. if (!(pwd_file = crypt_openpwdfile()))
  127. return;
  128. /*
  129.  * Here is where we load the data from pg_pwd.
  130.  */
  131. while (fgets(buffer, 256, pwd_file) != NULL)
  132. {
  133. /*
  134.  * We must remove the return char at the end of the string, as
  135.  * this will affect the correct parsing of the password entry.
  136.  */
  137. if (buffer[(result = strlen(buffer) - 1)] == 'n')
  138. buffer[result] = '';
  139. pwd_cache = (char **) realloc((void *) pwd_cache, sizeof(char *) * (pwd_cache_count + 1));
  140. pwd_cache[pwd_cache_count++] = strdup(buffer);
  141. }
  142. FreeFile(pwd_file);
  143. /*
  144.  * Now sort the entries in the cache for faster searching later.
  145.  */
  146. qsort((void *) pwd_cache, pwd_cache_count, sizeof(char *), compar_user);
  147. }
  148. }
  149. /*-------------------------------------------------------------------------*/
  150. static
  151. void
  152. crypt_parsepwdentry(char *buffer, char **pwd, char **valdate)
  153. {
  154. char    *parse = buffer;
  155. int count,
  156. i;
  157. /*
  158.  * skip to the password field
  159.  */
  160. for (i = 0; i < 6; i++)
  161. parse += (strcspn(parse, CRYPT_PWD_FILE_SEPSTR) + 1);
  162. /*
  163.  * store a copy of user password to return
  164.  */
  165. count = strcspn(parse, CRYPT_PWD_FILE_SEPSTR);
  166. *pwd = (char *) palloc(count + 1);
  167. strncpy(*pwd, parse, count);
  168. (*pwd)[count] = '';
  169. parse += (count + 1);
  170. /*
  171.  * store a copy of date login becomes invalid
  172.  */
  173. count = strcspn(parse, CRYPT_PWD_FILE_SEPSTR);
  174. *valdate = (char *) palloc(count + 1);
  175. strncpy(*valdate, parse, count);
  176. (*valdate)[count] = '';
  177. parse += (count + 1);
  178. }
  179. /*-------------------------------------------------------------------------*/
  180. static
  181. int
  182. crypt_getloginfo(const char *user, char **passwd, char **valuntil)
  183. {
  184. char    *pwd,
  185.    *valdate;
  186. void    *fakeout;
  187. *passwd = NULL;
  188. *valuntil = NULL;
  189. crypt_loadpwdfile();
  190. if (pwd_cache)
  191. {
  192. char   **pwd_entry;
  193. char user_search[NAMEDATALEN + 2];
  194. snprintf(user_search, NAMEDATALEN + 2, "%st", user);
  195. fakeout = (void *) &user_search;
  196. if ((pwd_entry = (char **) bsearch((void *) &fakeout, (void *) pwd_cache, pwd_cache_count, sizeof(char *), compar_user)))
  197. {
  198. crypt_parsepwdentry(*pwd_entry, &pwd, &valdate);
  199. *passwd = pwd;
  200. *valuntil = valdate;
  201. return STATUS_OK;
  202. }
  203. return STATUS_OK;
  204. }
  205. return STATUS_ERROR;
  206. }
  207. /*-------------------------------------------------------------------------*/
  208. int
  209. crypt_verify(Port *port, const char *user, const char *pgpass)
  210. {
  211. char    *passwd,
  212.    *valuntil,
  213.    *crypt_pwd;
  214. int retval = STATUS_ERROR;
  215. AbsoluteTime vuntil,
  216. current;
  217. if (crypt_getloginfo(user, &passwd, &valuntil) == STATUS_ERROR)
  218. return STATUS_ERROR;
  219. if (passwd == NULL || *passwd == '')
  220. {
  221. if (passwd)
  222. pfree((void *) passwd);
  223. if (valuntil)
  224. pfree((void *) valuntil);
  225. return STATUS_ERROR;
  226. }
  227. /*
  228.  * Compare with the encrypted or plain password depending on the
  229.  * authentication method being used for this connection.
  230.  */
  231. crypt_pwd =
  232. (port->auth_method == uaCrypt ? crypt(passwd, port->salt) : passwd);
  233. if (!strcmp(pgpass, crypt_pwd))
  234. {
  235. /*
  236.  * check here to be sure we are not past valuntil
  237.  */
  238. if (!valuntil || strcmp(valuntil, "\N") == 0)
  239. vuntil = INVALID_ABSTIME;
  240. else
  241. vuntil = nabstimein(valuntil);
  242. current = GetCurrentAbsoluteTime();
  243. if (vuntil != INVALID_ABSTIME && vuntil < current)
  244. retval = STATUS_ERROR;
  245. else
  246. retval = STATUS_OK;
  247. }
  248. pfree((void *) passwd);
  249. if (valuntil)
  250. pfree((void *) valuntil);
  251. return retval;
  252. }