All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rlm_cram.c
Go to the documentation of this file.
1 /*
2  * This program is is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or (at
5  * your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: 649ed8daad0cf7d1900109628248ec83e2fb9303 $
19  * @file rlm_cram.c
20  * @brief CRAM mail authentication (APOP, CRAM-MD5)
21  @verbatim
22  Attributes used (Vendor Code/PEN: 11406, you may change it to your own)
23  101 (Sandy-Mail-Authtype), selects CRAM protocol, possible values:
24  2: CRAM-MD5
25  3: APOP
26  8: CRAM-MD4
27  9: CRAM-SHA1
28  102 (Sandy-Mail-Challenge), contains server's challenge (usually
29  text banner)
30  103 (Sandy-Mail-Response), contains client's response, 16 octets
31  for APOP/CRAM-MD5/CRAM-MD4, 20 octets for CRAM-SHA1
32  @endverbatim
33  * @copyright 2001,2006 The FreeRADIUS server project
34  * @copyright 2002 SANDY (http://www.sandy.ru/) under GPLr
35  */
36 RCSID("$Id: 649ed8daad0cf7d1900109628248ec83e2fb9303 $")
37 
38 #include <freeradius-devel/radiusd.h>
39 #include <freeradius-devel/modules.h>
40 
41 #include <freeradius-devel/md5.h>
42 
43 #include <ctype.h>
44 
45 #define VENDORPEC_SM 11406
46 #define SM_AUTHTYPE 101
47 #define SM_CHALLENGE 102
48 #define SM_RESPONSE 103
49 
50 static void calc_apop_digest(uint8_t *buffer, uint8_t const *challenge,
51  size_t challen, char const *password)
52 {
53  FR_MD5_CTX context;
54 
55  fr_md5_init(&context);
56  fr_md5_update(&context, challenge, challen);
57  fr_md5_update(&context, (uint8_t const *) password, strlen(password));
58  fr_md5_final(buffer, &context);
59 }
60 
61 
62 static void calc_md5_digest(uint8_t *buffer, uint8_t const *challenge, size_t challen, char const *password)
63 {
64  uint8_t buf[1024];
65  int i;
66  FR_MD5_CTX context;
67 
68  memset(buf, 0, 1024);
69  memset(buf, 0x36, 64);
70  for(i=0; i<64 && password[i]; i++) buf[i]^=password[i];
71  memcpy(buf+64, challenge, challen);
72  fr_md5_init(&context);
73  fr_md5_update(&context, buf, 64+challen);
74  memset(buf, 0x5c, 64);
75  for(i=0; i<64 && password[i]; i++) buf[i]^=password[i];
76  fr_md5_final(buf+64,&context);
77  fr_md5_init(&context);
78  fr_md5_update(&context,buf,64+16);
79  fr_md5_final(buffer,&context);
80 }
81 
82 static void calc_md4_digest(uint8_t *buffer, uint8_t const *challenge, size_t challen, char const *password)
83 {
84  uint8_t buf[1024];
85  int i;
86  FR_MD4_CTX context;
87 
88  memset(buf, 0, 1024);
89  memset(buf, 0x36, 64);
90  for(i=0; i<64 && password[i]; i++) buf[i]^=password[i];
91  memcpy(buf+64, challenge, challen);
92  fr_md4_init(&context);
93  fr_md4_update(&context,buf,64+challen);
94  memset(buf, 0x5c, 64);
95  for(i=0; i<64 && password[i]; i++) buf[i]^=password[i];
96  fr_md4_final(buf+64,&context);
97  fr_md4_init(&context);
98  fr_md4_update(&context,buf,64+16);
99  fr_md4_final(buffer,&context);
100 }
101 
102 static void calc_sha1_digest(uint8_t *buffer, uint8_t const *challenge,
103  size_t challen, char const *password)
104 {
105  uint8_t buf[1024];
106  int i;
107  fr_sha1_ctx context;
108 
109  memset(buf, 0, 1024);
110  memset(buf, 0x36, 64);
111  for(i=0; i<64 && password[i]; i++) buf[i]^=password[i];
112  memcpy(buf+64, challenge, challen);
113  fr_sha1_init(&context);
114  fr_sha1_update(&context,buf,64+challen);
115  memset(buf, 0x5c, 64);
116  for(i=0; i<64 && password[i]; i++) buf[i]^=password[i];
117  fr_sha1_final(buf+64,&context);
118  fr_sha1_init(&context);
119  fr_sha1_update(&context,buf,64+20);
120  fr_sha1_final(buffer,&context);
121 }
122 
123 
124 static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(UNUSED void * instance, REQUEST *request)
125 {
126  VALUE_PAIR *authtype, *challenge, *response, *password;
127  uint8_t buffer[64];
128 
129  password = fr_pair_find_by_num(request->config, 0, PW_CLEARTEXT_PASSWORD, TAG_ANY);
130  if(!password) {
131  AUTH("rlm_cram: Cleartext-Password is required for authentication");
132  return RLM_MODULE_INVALID;
133  }
134  authtype = fr_pair_find_by_num(request->packet->vps, VENDORPEC_SM, SM_AUTHTYPE, TAG_ANY);
135  if(!authtype) {
136  AUTH("rlm_cram: Required attribute Sandy-Mail-Authtype missed");
137  return RLM_MODULE_INVALID;
138  }
139  challenge = fr_pair_find_by_num(request->packet->vps, VENDORPEC_SM, SM_CHALLENGE, TAG_ANY);
140  if(!challenge) {
141  AUTH("rlm_cram: Required attribute Sandy-Mail-Challenge missed");
142  return RLM_MODULE_INVALID;
143  }
144  response = fr_pair_find_by_num(request->packet->vps, VENDORPEC_SM, SM_RESPONSE, TAG_ANY);
145  if(!response) {
146  AUTH("rlm_cram: Required attribute Sandy-Mail-Response missed");
147  return RLM_MODULE_INVALID;
148  }
149  switch (authtype->vp_integer){
150  case 2: /* CRAM-MD5 */
151  if(challenge->vp_length < 5 || response->vp_length != 16) {
152  AUTH("rlm_cram: invalid MD5 challenge/response length");
153  return RLM_MODULE_INVALID;
154  }
155  calc_md5_digest(buffer, challenge->vp_octets, challenge->vp_length, password->vp_strvalue);
156  if(!memcmp(buffer, response->vp_octets, 16)) return RLM_MODULE_OK;
157  break;
158  case 3: /* APOP */
159  if(challenge->vp_length < 5 || response->vp_length != 16) {
160  AUTH("rlm_cram: invalid APOP challenge/response length");
161  return RLM_MODULE_INVALID;
162  }
163  calc_apop_digest(buffer, challenge->vp_octets, challenge->vp_length, password->vp_strvalue);
164  if(!memcmp(buffer, response->vp_octets, 16)) return RLM_MODULE_OK;
165  break;
166  case 8: /* CRAM-MD4 */
167  if(challenge->vp_length < 5 || response->vp_length != 16) {
168  AUTH("rlm_cram: invalid MD4 challenge/response length");
169  return RLM_MODULE_INVALID;
170  }
171  calc_md4_digest(buffer, challenge->vp_octets, challenge->vp_length, password->vp_strvalue);
172  if(!memcmp(buffer, response->vp_octets, 16)) return RLM_MODULE_OK;
173  break;
174  case 9: /* CRAM-SHA1 */
175  if(challenge->vp_length < 5 || response->vp_length != 20) {
176  AUTH("rlm_cram: invalid MD4 challenge/response length");
177  return RLM_MODULE_INVALID;
178  }
179  calc_sha1_digest(buffer, challenge->vp_octets, challenge->vp_length, password->vp_strvalue);
180  if(!memcmp(buffer, response->vp_octets, 20)) return RLM_MODULE_OK;
181  break;
182  default:
183  AUTH("rlm_cram: unsupported Sandy-Mail-Authtype");
184  return RLM_MODULE_INVALID;
185  }
186  return RLM_MODULE_NOTFOUND;
187 
188 }
189 
190 extern module_t rlm_cram;
191 module_t rlm_cram = {
193  .name = "cram",
194  .type = RLM_TYPE_THREAD_SAFE,
195  .methods = {
197  },
198 };
void fr_sha1_update(fr_sha1_ctx *context, uint8_t const *data, size_t len)
Definition: sha1.c:106
static void calc_md4_digest(uint8_t *buffer, uint8_t const *challenge, size_t challen, char const *password)
Definition: rlm_cram.c:82
static void calc_apop_digest(uint8_t *buffer, uint8_t const *challenge, size_t challen, char const *password)
Definition: rlm_cram.c:50
#define AUTH(fmt,...)
Definition: log.h:139
The module is OK, continue.
Definition: radiusd.h:91
Metadata exported by the module.
Definition: modules.h:134
#define RLM_TYPE_THREAD_SAFE
Module is threadsafe.
Definition: modules.h:75
#define UNUSED
Definition: libradius.h:134
#define RLM_MODULE_INIT
Definition: modules.h:86
static void calc_md5_digest(uint8_t *buffer, uint8_t const *challenge, size_t challen, char const *password)
Definition: rlm_cram.c:62
void fr_md5_init(FR_MD5_CTX *ctx)
Initialise a new MD5 context.
Definition: md5.c:84
#define SM_CHALLENGE
Definition: rlm_cram.c:47
The module considers the request invalid.
Definition: radiusd.h:93
module_t rlm_cram
Definition: rlm_cram.c:191
static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request) CC_HINT(nonnull)
void fr_md4_init(FR_MD4_CTX *ctx)
Initialise a new MD4 context.
Definition: md4.c:115
void fr_sha1_init(fr_sha1_ctx *context)
Definition: sha1.c:94
void fr_md5_update(FR_MD5_CTX *ctx, uint8_t const *in, size_t inlen) CC_BOUNDED(__string__
void fr_md4_update(FR_MD4_CTX *ctx, uint8_t const *in, size_t inlen) CC_BOUNDED(__string__
void void fr_md4_final(uint8_t out[MD4_DIGEST_LENGTH], FR_MD4_CTX *ctx) CC_BOUNDED(__minbytes__
#define SM_RESPONSE
Definition: rlm_cram.c:48
static void calc_sha1_digest(uint8_t *buffer, uint8_t const *challenge, size_t challen, char const *password)
Definition: rlm_cram.c:102
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
void fr_sha1_final(uint8_t digest[20], fr_sha1_ctx *context)
Definition: sha1.c:132
0 methods index for authenticate section.
Definition: modules.h:41
#define VENDORPEC_SM
Definition: rlm_cram.c:45
enum rlm_rcodes rlm_rcode_t
Return codes indicating the result of the module call.
uint64_t magic
Used to validate module struct.
Definition: modules.h:135
#define TAG_ANY
Definition: pair.h:191
#define SM_AUTHTYPE
Definition: rlm_cram.c:46
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
Definition: pair.c:639
void void fr_md5_final(uint8_t out[MD5_DIGEST_LENGTH], FR_MD5_CTX *ctx) CC_BOUNDED(__minbytes__
static rlm_rcode_t CC_HINT(nonnull)
Definition: rlm_cram.c:124
User not found.
Definition: radiusd.h:95
#define RCSID(id)
Definition: build.h:135