Header And Logo

PostgreSQL
| The world's most advanced open source database.

chkpass.c

Go to the documentation of this file.
00001 /*
00002  * PostgreSQL type definitions for chkpass
00003  * Written by D'Arcy J.M. Cain
00004  * [email protected]
00005  * http://www.druid.net/darcy/
00006  *
00007  * contrib/chkpass/chkpass.c
00008  * best viewed with tabs set to 4
00009  */
00010 
00011 #include "postgres.h"
00012 
00013 #include <time.h>
00014 #include <unistd.h>
00015 #ifdef HAVE_CRYPT_H
00016 #include <crypt.h>
00017 #endif
00018 
00019 #include "fmgr.h"
00020 #include "utils/builtins.h"
00021 
00022 PG_MODULE_MAGIC;
00023 
00024 /*
00025  * This type encrypts it's input unless the first character is a colon.
00026  * The output is the encrypted form with a leading colon.  The output
00027  * format is designed to allow dump and reload operations to work as
00028  * expected without doing special tricks.
00029  */
00030 
00031 
00032 /*
00033  * This is the internal storage format for CHKPASSs.
00034  * 15 is all I need but add a little buffer
00035  */
00036 
00037 typedef struct chkpass
00038 {
00039     char        password[16];
00040 } chkpass;
00041 
00042 /*
00043  * Various forward declarations:
00044  */
00045 
00046 Datum       chkpass_in(PG_FUNCTION_ARGS);
00047 Datum       chkpass_out(PG_FUNCTION_ARGS);
00048 Datum       chkpass_rout(PG_FUNCTION_ARGS);
00049 
00050 /* Only equal or not equal make sense */
00051 Datum       chkpass_eq(PG_FUNCTION_ARGS);
00052 Datum       chkpass_ne(PG_FUNCTION_ARGS);
00053 
00054 
00055 /* This function checks that the password is a good one
00056  * It's just a placeholder for now */
00057 static int
00058 verify_pass(const char *str)
00059 {
00060     return 0;
00061 }
00062 
00063 /*
00064  * CHKPASS reader.
00065  */
00066 PG_FUNCTION_INFO_V1(chkpass_in);
00067 Datum
00068 chkpass_in(PG_FUNCTION_ARGS)
00069 {
00070     char       *str = PG_GETARG_CSTRING(0);
00071     chkpass    *result;
00072     char        mysalt[4];
00073     static char salt_chars[] =
00074     "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
00075 
00076     /* special case to let us enter encrypted passwords */
00077     if (*str == ':')
00078     {
00079         result = (chkpass *) palloc(sizeof(chkpass));
00080         strlcpy(result->password, str + 1, 13 + 1);
00081         PG_RETURN_POINTER(result);
00082     }
00083 
00084     if (verify_pass(str) != 0)
00085         ereport(ERROR,
00086                 (errcode(ERRCODE_DATA_EXCEPTION),
00087                  errmsg("password \"%s\" is weak", str)));
00088 
00089     result = (chkpass *) palloc(sizeof(chkpass));
00090 
00091     mysalt[0] = salt_chars[random() & 0x3f];
00092     mysalt[1] = salt_chars[random() & 0x3f];
00093     mysalt[2] = 0;              /* technically the terminator is not necessary
00094                                  * but I like to play safe */
00095     strcpy(result->password, crypt(str, mysalt));
00096     PG_RETURN_POINTER(result);
00097 }
00098 
00099 /*
00100  * CHKPASS output function.
00101  * Just like any string but we know it is max 15 (13 plus colon and terminator.)
00102  */
00103 
00104 PG_FUNCTION_INFO_V1(chkpass_out);
00105 Datum
00106 chkpass_out(PG_FUNCTION_ARGS)
00107 {
00108     chkpass    *password = (chkpass *) PG_GETARG_POINTER(0);
00109     char       *result;
00110 
00111     result = (char *) palloc(16);
00112     result[0] = ':';
00113     strcpy(result + 1, password->password);
00114 
00115     PG_RETURN_CSTRING(result);
00116 }
00117 
00118 
00119 /*
00120  * special output function that doesn't output the colon
00121  */
00122 
00123 PG_FUNCTION_INFO_V1(chkpass_rout);
00124 Datum
00125 chkpass_rout(PG_FUNCTION_ARGS)
00126 {
00127     chkpass    *password = (chkpass *) PG_GETARG_POINTER(0);
00128 
00129     PG_RETURN_TEXT_P(cstring_to_text(password->password));
00130 }
00131 
00132 
00133 /*
00134  * Boolean tests
00135  */
00136 
00137 PG_FUNCTION_INFO_V1(chkpass_eq);
00138 Datum
00139 chkpass_eq(PG_FUNCTION_ARGS)
00140 {
00141     chkpass    *a1 = (chkpass *) PG_GETARG_POINTER(0);
00142     text       *a2 = PG_GETARG_TEXT_PP(1);
00143     char        str[9];
00144 
00145     text_to_cstring_buffer(a2, str, sizeof(str));
00146     PG_RETURN_BOOL(strcmp(a1->password, crypt(str, a1->password)) == 0);
00147 }
00148 
00149 PG_FUNCTION_INFO_V1(chkpass_ne);
00150 Datum
00151 chkpass_ne(PG_FUNCTION_ARGS)
00152 {
00153     chkpass    *a1 = (chkpass *) PG_GETARG_POINTER(0);
00154     text       *a2 = PG_GETARG_TEXT_PP(1);
00155     char        str[9];
00156 
00157     text_to_cstring_buffer(a2, str, sizeof(str));
00158     PG_RETURN_BOOL(strcmp(a1->password, crypt(str, a1->password)) != 0);
00159 }