PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
chkpass.c
Go to the documentation of this file.
1 /*
2  * PostgreSQL type definitions for chkpass
3  * Written by D'Arcy J.M. Cain
4  * darcy@druid.net
5  * http://www.druid.net/darcy/
6  *
7  * contrib/chkpass/chkpass.c
8  * best viewed with tabs set to 4
9  */
10 
11 #include "postgres.h"
12 
13 #include <time.h>
14 #include <unistd.h>
15 #ifdef HAVE_CRYPT_H
16 #include <crypt.h>
17 #endif
18 
19 #include "fmgr.h"
20 #include "utils/backend_random.h"
21 #include "utils/builtins.h"
22 
24 
25 /*
26  * This type encrypts it's input unless the first character is a colon.
27  * The output is the encrypted form with a leading colon. The output
28  * format is designed to allow dump and reload operations to work as
29  * expected without doing special tricks.
30  */
31 
32 
33 /*
34  * This is the internal storage format for CHKPASSs.
35  * 15 is all I need but add a little buffer
36  */
37 
38 typedef struct chkpass
39 {
40  char password[16];
41 } chkpass;
42 
43 
44 /* This function checks that the password is a good one
45  * It's just a placeholder for now */
46 static int
47 verify_pass(const char *str)
48 {
49  return 0;
50 }
51 
52 /*
53  * CHKPASS reader.
54  */
56 Datum
58 {
59  char *str = PG_GETARG_CSTRING(0);
60  chkpass *result;
61  char mysalt[4];
62  char *crypt_output;
63  static char salt_chars[] =
64  "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
65 
66  /* special case to let us enter encrypted passwords */
67  if (*str == ':')
68  {
69  result = (chkpass *) palloc0(sizeof(chkpass));
70  strlcpy(result->password, str + 1, 13 + 1);
71  PG_RETURN_POINTER(result);
72  }
73 
74  if (verify_pass(str) != 0)
75  ereport(ERROR,
76  (errcode(ERRCODE_DATA_EXCEPTION),
77  errmsg("password \"%s\" is weak", str)));
78 
79  result = (chkpass *) palloc0(sizeof(chkpass));
80 
81  if (!pg_backend_random(mysalt, 2))
82  ereport(ERROR,
83  (errmsg("could not generate random salt")));
84 
85  mysalt[0] = salt_chars[mysalt[0] & 0x3f];
86  mysalt[1] = salt_chars[mysalt[1] & 0x3f];
87  mysalt[2] = 0; /* technically the terminator is not necessary
88  * but I like to play safe */
89 
90  crypt_output = crypt(str, mysalt);
91  if (crypt_output == NULL)
92  ereport(ERROR,
93  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
94  errmsg("crypt() failed")));
95 
96  strlcpy(result->password, crypt_output, sizeof(result->password));
97 
98  PG_RETURN_POINTER(result);
99 }
100 
101 /*
102  * CHKPASS output function.
103  * Just like any string but we know it is max 15 (13 plus colon and terminator.)
104  */
105 
107 Datum
109 {
111  char *result;
112 
113  result = (char *) palloc(16);
114  result[0] = ':';
115  strlcpy(result + 1, password->password, 15);
116 
117  PG_RETURN_CSTRING(result);
118 }
119 
120 
121 /*
122  * special output function that doesn't output the colon
123  */
124 
126 Datum
128 {
130 
132 }
133 
134 
135 /*
136  * Boolean tests
137  */
138 
140 Datum
142 {
144  text *a2 = PG_GETARG_TEXT_PP(1);
145  char str[9];
146  char *crypt_output;
147 
148  text_to_cstring_buffer(a2, str, sizeof(str));
149  crypt_output = crypt(str, a1->password);
150  if (crypt_output == NULL)
151  ereport(ERROR,
152  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
153  errmsg("crypt() failed")));
154 
155  PG_RETURN_BOOL(strcmp(a1->password, crypt_output) == 0);
156 }
157 
159 Datum
161 {
163  text *a2 = PG_GETARG_TEXT_PP(1);
164  char str[9];
165  char *crypt_output;
166 
167  text_to_cstring_buffer(a2, str, sizeof(str));
168  crypt_output = crypt(str, a1->password);
169  if (crypt_output == NULL)
170  ereport(ERROR,
171  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
172  errmsg("crypt() failed")));
173 
174  PG_RETURN_BOOL(strcmp(a1->password, crypt_output) != 0);
175 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:321
static char password[100]
Definition: streamutil.c:42
PG_MODULE_MAGIC
Definition: chkpass.c:23
Datum chkpass_ne(PG_FUNCTION_ARGS)
Definition: chkpass.c:160
Datum chkpass_rout(PG_FUNCTION_ARGS)
Definition: chkpass.c:127
int errcode(int sqlerrcode)
Definition: elog.c:575
return result
Definition: formatting.c:1633
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:241
void text_to_cstring_buffer(const text *src, char *dst, size_t dst_len)
Definition: varlena.c:213
PG_FUNCTION_INFO_V1(chkpass_in)
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:273
struct chkpass chkpass
#define ERROR
Definition: elog.h:43
Datum chkpass_out(PG_FUNCTION_ARGS)
Definition: chkpass.c:108
Datum chkpass_eq(PG_FUNCTION_ARGS)
Definition: chkpass.c:141
bool pg_backend_random(char *dst, int len)
#define ereport(elevel, rest)
Definition: elog.h:122
Datum chkpass_in(PG_FUNCTION_ARGS)
Definition: chkpass.c:57
void * palloc0(Size size)
Definition: mcxt.c:878
char * crypt(const char *key, const char *setting)
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:319
uintptr_t Datum
Definition: postgres.h:372
static FormData_pg_attribute a1
Definition: heap.c:144
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:330
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
text * cstring_to_text(const char *s)
Definition: varlena.c:149
#define NULL
Definition: c.h:229
static int verify_pass(const char *str)
Definition: chkpass.c:47
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:322
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:242
Definition: c.h:439
#define PG_FUNCTION_ARGS
Definition: fmgr.h:158
char password[16]
Definition: chkpass.c:40
static FormData_pg_attribute a2
Definition: heap.c:150