123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- /*
- * Written by Solar Designer and placed in the public domain.
- * See crypt_blowfish.c for more information.
- */
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #ifndef __set_errno
- #define __set_errno(val) errno = (val)
- #endif
- #ifdef TEST
- #include <stdio.h>
- #include <unistd.h>
- #include <signal.h>
- #include <time.h>
- #include <sys/time.h>
- #include <sys/times.h>
- #ifdef TEST_THREADS
- #include <pthread.h>
- #endif
- #endif
- #include <ruby.h>
- #include <util.h>
- #define CRYPT_OUTPUT_SIZE (7 + 22 + 31 + 1)
- #define CRYPT_GENSALT_OUTPUT_SIZE (7 + 22 + 1)
- #if defined(__GLIBC__) && defined(_LIBC)
- #define __SKIP_GNU
- #endif
- #include "ow-crypt.h"
- extern char *_crypt_blowfish_rn(__CONST char *key, __CONST char *setting,
- char *output, int size);
- extern char *_crypt_gensalt_blowfish_rn(unsigned long count,
- __CONST char *input, int size, char *output, int output_size);
- extern unsigned char _crypt_itoa64[];
- extern char *_crypt_gensalt_traditional_rn(unsigned long count,
- __CONST char *input, int size, char *output, int output_size);
- extern char *_crypt_gensalt_extended_rn(unsigned long count,
- __CONST char *input, int size, char *output, int output_size);
- extern char *_crypt_gensalt_md5_rn(unsigned long count,
- __CONST char *input, int size, char *output, int output_size);
- #if defined(__GLIBC__) && defined(_LIBC)
- /* crypt.h from glibc-crypt-2.1 will define struct crypt_data for us */
- #include "crypt.h"
- extern char *__md5_crypt_r(const char *key, const char *salt,
- char *buffer, int buflen);
- /* crypt-entry.c needs to be patched to define __des_crypt_r rather than
- * __crypt_r, and not define crypt_r and crypt at all */
- extern char *__des_crypt_r(const char *key, const char *salt,
- struct crypt_data *data);
- extern struct crypt_data _ufc_foobar;
- #endif
- static int _crypt_data_alloc(void **data, int *size, int need)
- {
- void *updated;
- if (*data && *size >= need) return 0;
- updated = realloc(*data, need);
- if (!updated) {
- #ifndef __GLIBC__
- /* realloc(3) on glibc sets errno, so we don't need to bother */
- __set_errno(ENOMEM);
- #endif
- return -1;
- }
- #if defined(__GLIBC__) && defined(_LIBC)
- if (need >= sizeof(struct crypt_data))
- ((struct crypt_data *)updated)->initialized = 0;
- #endif
- *data = updated;
- *size = need;
- return 0;
- }
- static char *_crypt_retval_magic(char *retval, __CONST char *setting,
- char *output)
- {
- if (retval) return retval;
- output[0] = '*';
- output[1] = '0';
- output[2] = '\0';
- if (setting[0] == '*' && setting[1] == '0')
- output[1] = '1';
- return output;
- }
- #if defined(__GLIBC__) && defined(_LIBC)
- /*
- * Applications may re-use the same instance of struct crypt_data without
- * resetting the initialized field in order to let crypt_r() skip some of
- * its initialization code. Thus, it is important that our multiple hashing
- * algorithms either don't conflict with each other in their use of the
- * data area or reset the initialized field themselves whenever required.
- * Currently, the hashing algorithms simply have no conflicts: the first
- * field of struct crypt_data is the 128-byte large DES key schedule which
- * __des_crypt_r() calculates each time it is called while the two other
- * hashing algorithms use less than 128 bytes of the data area.
- */
- char *__crypt_rn(__const char *key, __const char *setting,
- void *data, int size)
- {
- if (setting[0] == '$' && setting[1] == '2')
- return _crypt_blowfish_rn(key, setting, (char *)data, size);
- if (setting[0] == '$' && setting[1] == '1')
- return __md5_crypt_r(key, setting, (char *)data, size);
- if (setting[0] == '$' || setting[0] == '_') {
- __set_errno(EINVAL);
- return NULL;
- }
- if (size >= sizeof(struct crypt_data))
- return __des_crypt_r(key, setting, (struct crypt_data *)data);
- __set_errno(ERANGE);
- return NULL;
- }
- char *__crypt_ra(__const char *key, __const char *setting,
- void **data, int *size)
- {
- if (setting[0] == '$' && setting[1] == '2') {
- if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE))
- return NULL;
- return _crypt_blowfish_rn(key, setting, (char *)*data, *size);
- }
- if (setting[0] == '$' && setting[1] == '1') {
- if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE))
- return NULL;
- return __md5_crypt_r(key, setting, (char *)*data, *size);
- }
- if (setting[0] == '$' || setting[0] == '_') {
- __set_errno(EINVAL);
- return NULL;
- }
- if (_crypt_data_alloc(data, size, sizeof(struct crypt_data)))
- return NULL;
- return __des_crypt_r(key, setting, (struct crypt_data *)*data);
- }
- char *__crypt_r(__const char *key, __const char *setting,
- struct crypt_data *data)
- {
- return _crypt_retval_magic(
- __crypt_rn(key, setting, data, sizeof(*data)),
- setting, (char *)data);
- }
- char *__crypt(__const char *key, __const char *setting)
- {
- return _crypt_retval_magic(
- __crypt_rn(key, setting, &_ufc_foobar, sizeof(_ufc_foobar)),
- setting, (char *)&_ufc_foobar);
- }
- #else
- char *crypt_rn(__CONST char *key, __CONST char *setting, void *data, int size)
- {
- return _crypt_blowfish_rn(key, setting, (char *)data, size);
- }
- char *crypt_ra(__CONST char *key, __CONST char *setting,
- void **data, int *size)
- {
- if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE))
- return NULL;
- return _crypt_blowfish_rn(key, setting, (char *)*data, *size);
- }
- char *crypt_r(__CONST char *key, __CONST char *setting, void *data)
- {
- return _crypt_retval_magic(
- crypt_rn(key, setting, data, CRYPT_OUTPUT_SIZE),
- setting, (char *)data);
- }
- #define __crypt_gensalt_rn crypt_gensalt_rn
- #define __crypt_gensalt_ra crypt_gensalt_ra
- #define __crypt_gensalt crypt_gensalt
- #endif
- char *__crypt_gensalt_rn(__CONST char *prefix, unsigned long count,
- __CONST char *input, int size, char *output, int output_size)
- {
- char *(*use)(unsigned long count,
- __CONST char *input, int size, char *output, int output_size);
- /* This may be supported on some platforms in the future */
- if (!input) {
- __set_errno(EINVAL);
- return NULL;
- }
- if (!strncmp(prefix, "$2a$", 4))
- use = _crypt_gensalt_blowfish_rn;
- else
- if (!strncmp(prefix, "$1$", 3))
- use = _crypt_gensalt_md5_rn;
- else
- if (prefix[0] == '_')
- use = _crypt_gensalt_extended_rn;
- else
- if (!prefix[0] ||
- (prefix[0] && prefix[1] &&
- memchr(_crypt_itoa64, prefix[0], 64) &&
- memchr(_crypt_itoa64, prefix[1], 64)))
- use = _crypt_gensalt_traditional_rn;
- else {
- __set_errno(EINVAL);
- return NULL;
- }
- return use(count, input, size, output, output_size);
- }
- char *__crypt_gensalt_ra(__CONST char *prefix, unsigned long count,
- __CONST char *input, int size)
- {
- char output[CRYPT_GENSALT_OUTPUT_SIZE];
- char *retval;
- retval = __crypt_gensalt_rn(prefix, count,
- input, size, output, sizeof(output));
- if (retval) {
- retval = ruby_strdup(retval);
- #ifndef __GLIBC__
- /* strdup(3) on glibc sets errno, so we don't need to bother */
- if (!retval)
- __set_errno(ENOMEM);
- #endif
- }
- return retval;
- }
- char *__crypt_gensalt(__CONST char *prefix, unsigned long count,
- __CONST char *input, int size)
- {
- static char output[CRYPT_GENSALT_OUTPUT_SIZE];
- return __crypt_gensalt_rn(prefix, count,
- input, size, output, sizeof(output));
- }
|