Changeset View
Changeset View
Standalone View
Standalone View
lib/libcrypt/crypt.c
Show All 28 Lines | |||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/types.h> | #include <sys/types.h> | ||||
#include <libutil.h> | #include <libutil.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <stdio.h> | |||||
delphij: Is this needed? | |||||
ali_mashtizadeh.comAuthorUnsubmitted Done Inline ActionsI'll remove this ali_mashtizadeh.com: I'll remove this | |||||
#include <unistd.h> | #include <unistd.h> | ||||
#include "crypt.h" | #include "crypt.h" | ||||
#define CRYPT_MAGIC_MAX_LEN 64 | |||||
/* | /* | ||||
* List of supported crypt(3) formats. | * List of supported crypt(3) formats. | ||||
* | * | ||||
* The default algorithm is the last entry in the list (second-to-last | * The default algorithm is the last entry in the list (second-to-last | ||||
* array element since the last is a sentinel). The reason for placing | * array element since the last is a sentinel). The reason for placing | ||||
* the default last rather than first is that DES needs to be at the | * the default last rather than first is that DES needs to be at the | ||||
* bottom for the algorithm guessing logic in crypt(3) to work correctly, | * bottom for the algorithm guessing logic in crypt(3) to work correctly, | ||||
* and it needs to be the default for backward compatibility. | * and it needs to be the default for backward compatibility. | ||||
*/ | */ | ||||
static const struct crypt_format { | static const struct crypt_format { | ||||
const char *name; | const char *name; | ||||
int (*func)(const char *, const char *, char *); | int (*func)(const char *, const char *, char *); | ||||
const char *magic; | const char *magic; | ||||
} crypt_formats[] = { | } crypt_formats[] = { | ||||
{ "md5", crypt_md5, "$1$" }, | { "md5", crypt_md5, "$1$" }, | ||||
#ifdef HAS_BLOWFISH | #ifdef HAS_BLOWFISH | ||||
{ "blf", crypt_blowfish, "$2" }, | { "blf", crypt_blowfish, "$2" }, | ||||
#endif | #endif | ||||
{ "nth", crypt_nthash, "$3$" }, | { "nth", crypt_nthash, "$3$" }, | ||||
{ "sha256", crypt_sha256, "$5$" }, | { "sha256", crypt_sha256, "$5$" }, | ||||
{ "sha512", crypt_sha512, "$6$" }, | { "sha512", crypt_sha512, "$6$" }, | ||||
#ifdef HAS_DES | #ifdef HAS_DES | ||||
{ "des", crypt_des, "_" }, | { "des", crypt_des, "_" }, | ||||
#endif | #endif | ||||
/* sentinel */ | /* sentinel */ | ||||
{ NULL, NULL, NULL } | { NULL, NULL, NULL } | ||||
}; | }; | ||||
static const struct crypt_format *crypt_format = | static char crypt_default_magic[CRYPT_MAGIC_MAX_LEN] = ""; | ||||
static const struct crypt_format *crypt_default_format = | |||||
Not Done Inline ActionsWhat's the reasoning behind using Blowfish? (It's author, Bruce Schneier have advised to migrate to Twofish in ~2007 by the way) delphij: What's the reasoning behind using Blowfish? (It's author, Bruce Schneier have advised to… | |||||
&crypt_formats[(sizeof crypt_formats / sizeof *crypt_formats) - 2]; | &crypt_formats[(sizeof crypt_formats / sizeof *crypt_formats) - 2]; | ||||
#define DES_SALT_ALPHABET \ | #define DES_SALT_ALPHABET \ | ||||
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" | "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" | ||||
/* | /* | ||||
* Returns the name of the currently selected format. | * Returns the name of the currently selected format. | ||||
Not Done Inline Actionsstyle: avoid hardcoding. delphij: style: avoid hardcoding. | |||||
*/ | */ | ||||
const char * | const char * | ||||
crypt_get_format(void) | crypt_get_format(void) | ||||
{ | { | ||||
return (crypt_default_format->name); | |||||
delphijUnsubmitted Not Done Inline ActionsPlease keep the blank line per style(9). delphij: Please keep the blank line per style(9). | |||||
ali_mashtizadeh.comAuthorUnsubmitted Done Inline ActionsWill do ali_mashtizadeh.com: Will do | |||||
return (crypt_format->name); | |||||
} | } | ||||
/* | /* | ||||
* Selects the format to use for subsequent crypt(3) invocations. | * Selects the format to use for subsequent crypt(3) invocations. | ||||
*/ | */ | ||||
int | int | ||||
crypt_set_format(const char *format) | crypt_set_format(const char *format) | ||||
{ | { | ||||
const struct crypt_format *cf; | const struct crypt_format *cf; | ||||
for (cf = crypt_formats; cf->name != NULL; ++cf) { | for (cf = crypt_formats; cf->name != NULL; ++cf) { | ||||
if (format[0] == '$') { | |||||
if (strncmp(cf->magic, format, strlen(cf->magic)) == 0) { | |||||
strlcpy(crypt_default_magic, format, sizeof(crypt_default_magic)); | |||||
crypt_default_format = cf; | |||||
return (1); | |||||
} | |||||
} else { | |||||
if (strcasecmp(cf->name, format) == 0) { | if (strcasecmp(cf->name, format) == 0) { | ||||
crypt_format = cf; | crypt_default_magic[0] = '\0'; | ||||
Done Inline ActionsI realized this line shouldn't exist because the formats of the magic. I'll revert the diff to: ali_mashtizadeh.com: I realized this line shouldn't exist because the formats of the magic. I'll revert the diff to… | |||||
crypt_default_format = cf; | |||||
return (1); | return (1); | ||||
} | } | ||||
} | } | ||||
} | |||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Hash the given password with the given salt. If the salt begins with a | * Hash the given password with the given salt. If the salt begins with a | ||||
* magic string (e.g. "$6$" for sha512), the corresponding format is used; | * magic string (e.g. "$6$" for sha512), the corresponding format is used; | ||||
* otherwise, the currently selected format is used. | * otherwise, the currently selected format is used. | ||||
*/ | */ | ||||
char * | char * | ||||
crypt_r(const char *passwd, const char *salt, struct crypt_data *data) | crypt_r(const char *passwd, const char *salt, struct crypt_data *data) | ||||
{ | { | ||||
const struct crypt_format *cf; | const struct crypt_format *cf; | ||||
int (*func)(const char *, const char *, char *); | int (*func)(const char *, const char *, char *); | ||||
#ifdef HAS_DES | #ifdef HAS_DES | ||||
int len; | int len; | ||||
#endif | #endif | ||||
char nsalt[CRYPT_MAGIC_MAX_LEN+CRYPT_SALT_MAX_LEN]; | |||||
strlcpy(nsalt, salt, sizeof(nsalt)); | |||||
Not Done Inline ActionsAvoid strn*, use strl* instead. delphij: Avoid strn*, use strl* instead. | |||||
for (cf = crypt_formats; cf->name != NULL; ++cf) | for (cf = crypt_formats; cf->name != NULL; ++cf) | ||||
if (cf->magic != NULL && strstr(salt, cf->magic) == salt) { | if (cf->magic != NULL && strstr(salt, cf->magic) == salt) { | ||||
func = cf->func; | func = cf->func; | ||||
goto match; | goto match; | ||||
} | } | ||||
#ifdef HAS_DES | #ifdef HAS_DES | ||||
len = strlen(salt); | len = strlen(salt); | ||||
if ((len == 13 || len == 2) && strspn(salt, DES_SALT_ALPHABET) == len) { | if ((len == 13 || len == 2) && strspn(salt, DES_SALT_ALPHABET) == len) { | ||||
func = crypt_des; | func = crypt_des; | ||||
goto match; | goto match; | ||||
} | } | ||||
#endif | #endif | ||||
func = crypt_format->func; | /* | ||||
* New passwords come with an unprefixed salt, which we will prepend | |||||
* with the default magic (if available). Otherwise we fallback to the | |||||
* default function. | |||||
*/ | |||||
if (strcmp(crypt_default_magic, "") != 0) { | |||||
delphijUnsubmitted Not Done Inline ActionsPreviously the switch was performed by modifying a pointer, which is typically atomic, and now it's being compared against a string. This made crypt_r no longer thread safe and we can't do this. delphij: Previously the switch was performed by modifying a pointer, which is typically atomic, and now… | |||||
strlcpy(nsalt, crypt_default_magic, sizeof(nsalt)); | |||||
strlcat(nsalt, salt, sizeof(nsalt)); | |||||
} | |||||
func = crypt_default_format->func; | |||||
match: | match: | ||||
if (func(passwd, salt, data->__buf) != 0) | if (func(passwd, nsalt, data->__buf) != 0) | ||||
return (NULL); | return (NULL); | ||||
return (data->__buf); | return (data->__buf); | ||||
} | } | ||||
char * | char * | ||||
crypt(const char *passwd, const char *salt) | crypt(const char *passwd, const char *salt) | ||||
{ | { | ||||
static struct crypt_data data; | static struct crypt_data data; | ||||
return (crypt_r(passwd, salt, &data)); | return (crypt_r(passwd, salt, &data)); | ||||
} | } |
Is this needed?