LCOV - differential code coverage report
Current view: top level - contrib/passwordcheck - passwordcheck.c (source / functions) Coverage Total Hit UIC GIC CBC EUB ECB
Current: Differential Code Coverage HEAD vs 15 Lines: 96.3 % 27 26 1 20 6 1 20
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 3 3 2 1 2
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (240..) days: 96.3 % 27 26 1 20 6 1 20
Legend: Lines: hit not hit Function coverage date bins:
(240..) days: 60.0 % 5 3 2 1 2

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * passwordcheck.c
                                  4                 :  *
                                  5                 :  *
                                  6                 :  * Copyright (c) 2009-2023, PostgreSQL Global Development Group
                                  7                 :  *
                                  8                 :  * Author: Laurenz Albe <laurenz.albe@wien.gv.at>
                                  9                 :  *
                                 10                 :  * IDENTIFICATION
                                 11                 :  *    contrib/passwordcheck/passwordcheck.c
                                 12                 :  *
                                 13                 :  *-------------------------------------------------------------------------
                                 14                 :  */
                                 15                 : #include "postgres.h"
                                 16                 : 
                                 17                 : #include <ctype.h>
                                 18                 : 
                                 19                 : #ifdef USE_CRACKLIB
                                 20                 : #include <crack.h>
                                 21                 : #endif
                                 22                 : 
                                 23                 : #include "commands/user.h"
                                 24                 : #include "fmgr.h"
                                 25                 : #include "libpq/crypt.h"
                                 26                 : 
 4890 tgl                        27 CBC           1 : PG_MODULE_MAGIC;
                                 28                 : 
                                 29                 : /* Saved hook value in case of unload */
                                 30                 : static check_password_hook_type prev_check_password_hook = NULL;
                                 31                 : 
                                 32                 : /* passwords shorter than this will be rejected */
                                 33                 : #define MIN_PWD_LENGTH 8
                                 34                 : 
                                 35                 : /*
                                 36                 :  * check_password
                                 37                 :  *
                                 38                 :  * performs checks on an encrypted or unencrypted password
                                 39                 :  * ereport's if not acceptable
                                 40                 :  *
                                 41                 :  * username: name of role being created or changed
                                 42                 :  * password: new password (possibly already encrypted)
                                 43                 :  * password_type: PASSWORD_TYPE_* code, to indicate if the password is
                                 44                 :  *          in plaintext or encrypted form.
                                 45                 :  * validuntil_time: password expiration time, as a timestamptz Datum
                                 46                 :  * validuntil_null: true if password expiration time is NULL
                                 47                 :  *
                                 48                 :  * This sample implementation doesn't pay any attention to the password
                                 49                 :  * expiration time, but you might wish to insist that it be non-null and
                                 50                 :  * not too far in the future.
 4890 tgl                        51 ECB             :  */
                                 52                 : static void
 4890 tgl                        53 GIC           6 : check_password(const char *username,
                                 54                 :                const char *shadow_pass,
                                 55                 :                PasswordType password_type,
                                 56                 :                Datum validuntil_time,
 4890 tgl                        57 ECB             :                bool validuntil_null)
 4890 tgl                        58 EUB             : {
 1347 michael                    59 GIC           6 :     if (prev_check_password_hook)
 1347 michael                    60 UIC           0 :         prev_check_password_hook(username, shadow_pass,
                                 61                 :                                  password_type, validuntil_time,
 1347 michael                    62 ECB             :                                  validuntil_null);
                                 63                 : 
 2258 heikki.linnakangas         64 GIC           6 :     if (password_type != PASSWORD_TYPE_PLAINTEXT)
                                 65                 :     {
                                 66                 :         /*
                                 67                 :          * Unfortunately we cannot perform exhaustive checks on encrypted
                                 68                 :          * passwords - we are restricted to guessing. (Alternatively, we could
                                 69                 :          * insist on the password being presented non-encrypted, but that has
                                 70                 :          * its own security disadvantages.)
                                 71                 :          *
 2258 heikki.linnakangas         72 ECB             :          * We only check for username = password.
                                 73                 :          */
  453 michael                    74 CBC           2 :         const char *logdetail = NULL;
 2258 heikki.linnakangas         75 ECB             : 
 2258 heikki.linnakangas         76 GIC           2 :         if (plain_crypt_verify(username, shadow_pass, username, &logdetail) == STATUS_OK)
                                 77               1 :             ereport(ERROR,
                                 78                 :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                 79                 :                      errmsg("password must not equal user name")));
                                 80                 :     }
                                 81                 :     else
                                 82                 :     {
                                 83                 :         /*
 2258 heikki.linnakangas         84 ECB             :          * For unencrypted passwords we can perform better checks
                                 85                 :          */
 2258 heikki.linnakangas         86 GIC           4 :         const char *password = shadow_pass;
                                 87               4 :         int         pwdlen = strlen(password);
                                 88                 :         int         i;
                                 89                 :         bool        pwd_has_letter,
                                 90                 :                     pwd_has_nonletter;
                                 91                 : #ifdef USE_CRACKLIB
                                 92                 :         const char *reason;
                                 93                 : #endif
 2258 heikki.linnakangas         94 ECB             : 
                                 95                 :         /* enforce minimum length */
 2258 heikki.linnakangas         96 GIC           4 :         if (pwdlen < MIN_PWD_LENGTH)
                                 97               1 :             ereport(ERROR,
                                 98                 :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                 99                 :                      errmsg("password is too short")));
 2258 heikki.linnakangas        100 ECB             : 
                                101                 :         /* check if the password contains the username */
 2258 heikki.linnakangas        102 GIC           3 :         if (strstr(password, username))
                                103               1 :             ereport(ERROR,
                                104                 :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                105                 :                      errmsg("password must not contain user name")));
 2258 heikki.linnakangas        106 ECB             : 
                                107                 :         /* check if the password contains both letters and non-letters */
 2258 heikki.linnakangas        108 CBC           2 :         pwd_has_letter = false;
 2258 heikki.linnakangas        109 GIC           2 :         pwd_has_nonletter = false;
                                110              43 :         for (i = 0; i < pwdlen; i++)
                                111                 :         {
                                112                 :             /*
                                113                 :              * isalpha() does not work for multibyte encodings but let's
 2258 heikki.linnakangas        114 ECB             :              * consider non-ASCII characters non-letters
 4890 tgl                       115                 :              */
 2258 heikki.linnakangas        116 GIC          41 :             if (isalpha((unsigned char) password[i]))
 2258 heikki.linnakangas        117 CBC          38 :                 pwd_has_letter = true;
                                118                 :             else
                                119               3 :                 pwd_has_nonletter = true;
 2258 heikki.linnakangas        120 ECB             :         }
 2258 heikki.linnakangas        121 GIC           2 :         if (!pwd_has_letter || !pwd_has_nonletter)
                                122               1 :             ereport(ERROR,
                                123                 :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                124                 :                      errmsg("password must contain both letters and nonletters")));
                                125                 : 
                                126                 : #ifdef USE_CRACKLIB
                                127                 :         /* call cracklib to check password */
                                128                 :         if ((reason = FascistCheck(password, CRACKLIB_DICTPATH)))
                                129                 :             ereport(ERROR,
                                130                 :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                131                 :                      errmsg("password is easily cracked"),
                                132                 :                      errdetail_log("cracklib diagnostic: %s", reason)));
                                133                 : #endif
                                134                 :     }
 4890 tgl                       135 ECB             : 
                                136                 :     /* all checks passed, password is ok */
 4890 tgl                       137 GIC           2 : }
                                138                 : 
                                139                 : /*
                                140                 :  * Module initialization function
 4890 tgl                       141 ECB             :  */
                                142                 : void
 4890 tgl                       143 GIC           1 : _PG_init(void)
 4890 tgl                       144 ECB             : {
                                145                 :     /* activate password checks when the module is loaded */
 1347 michael                   146 CBC           1 :     prev_check_password_hook = check_password_hook;
 4890 tgl                       147 GIC           1 :     check_password_hook = check_password;
                                148               1 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a