1 /* 2 * Copyright (c) 1997-2001 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "krb5_locl.h" 35 #include <vis.h> 36 37 RCSID("$Id: replay.c 17047 2006-04-10 17:13:49Z lha $"); 38 39 struct krb5_rcache_data { 40 char *name; 41 }; 42 43 krb5_error_code KRB5_LIB_FUNCTION 44 krb5_rc_resolve(krb5_context context, 45 krb5_rcache id, 46 const char *name) 47 { 48 id->name = strdup(name); 49 if(id->name == NULL) { 50 krb5_set_error_string (context, "malloc: out of memory"); 51 return KRB5_RC_MALLOC; 52 } 53 return 0; 54 } 55 56 krb5_error_code KRB5_LIB_FUNCTION 57 krb5_rc_resolve_type(krb5_context context, 58 krb5_rcache *id, 59 const char *type) 60 { 61 *id = NULL; 62 if(strcmp(type, "FILE")) { 63 krb5_set_error_string (context, "replay cache type %s not supported", 64 type); 65 return KRB5_RC_TYPE_NOTFOUND; 66 } 67 *id = calloc(1, sizeof(**id)); 68 if(*id == NULL) { 69 krb5_set_error_string (context, "malloc: out of memory"); 70 return KRB5_RC_MALLOC; 71 } 72 return 0; 73 } 74 75 krb5_error_code KRB5_LIB_FUNCTION 76 krb5_rc_resolve_full(krb5_context context, 77 krb5_rcache *id, 78 const char *string_name) 79 { 80 krb5_error_code ret; 81 82 *id = NULL; 83 84 if(strncmp(string_name, "FILE:", 5)) { 85 krb5_set_error_string (context, "replay cache type %s not supported", 86 string_name); 87 return KRB5_RC_TYPE_NOTFOUND; 88 } 89 ret = krb5_rc_resolve_type(context, id, "FILE"); 90 if(ret) 91 return ret; 92 ret = krb5_rc_resolve(context, *id, string_name + 5); 93 if (ret) { 94 krb5_rc_close(context, *id); 95 *id = NULL; 96 } 97 return ret; 98 } 99 100 const char* KRB5_LIB_FUNCTION 101 krb5_rc_default_name(krb5_context context) 102 { 103 return "FILE:/var/run/default_rcache"; 104 } 105 106 const char* KRB5_LIB_FUNCTION 107 krb5_rc_default_type(krb5_context context) 108 { 109 return "FILE"; 110 } 111 112 krb5_error_code KRB5_LIB_FUNCTION 113 krb5_rc_default(krb5_context context, 114 krb5_rcache *id) 115 { 116 return krb5_rc_resolve_full(context, id, krb5_rc_default_name(context)); 117 } 118 119 struct rc_entry{ 120 time_t stamp; 121 unsigned char data[16]; 122 }; 123 124 krb5_error_code KRB5_LIB_FUNCTION 125 krb5_rc_initialize(krb5_context context, 126 krb5_rcache id, 127 krb5_deltat auth_lifespan) 128 { 129 FILE *f = fopen(id->name, "w"); 130 struct rc_entry tmp; 131 int ret; 132 133 if(f == NULL) { 134 ret = errno; 135 krb5_set_error_string (context, "open(%s): %s", id->name, 136 strerror(ret)); 137 return ret; 138 } 139 tmp.stamp = auth_lifespan; 140 fwrite(&tmp, 1, sizeof(tmp), f); 141 fclose(f); 142 return 0; 143 } 144 145 krb5_error_code KRB5_LIB_FUNCTION 146 krb5_rc_recover(krb5_context context, 147 krb5_rcache id) 148 { 149 return 0; 150 } 151 152 krb5_error_code KRB5_LIB_FUNCTION 153 krb5_rc_destroy(krb5_context context, 154 krb5_rcache id) 155 { 156 int ret; 157 158 if(remove(id->name) < 0) { 159 ret = errno; 160 krb5_set_error_string (context, "remove(%s): %s", id->name, 161 strerror(ret)); 162 return ret; 163 } 164 return krb5_rc_close(context, id); 165 } 166 167 krb5_error_code KRB5_LIB_FUNCTION 168 krb5_rc_close(krb5_context context, 169 krb5_rcache id) 170 { 171 free(id->name); 172 free(id); 173 return 0; 174 } 175 176 static void 177 checksum_authenticator(Authenticator *auth, void *data) 178 { 179 MD5_CTX md5; 180 int i; 181 182 MD5_Init (&md5); 183 MD5_Update (&md5, auth->crealm, strlen(auth->crealm)); 184 for(i = 0; i < auth->cname.name_string.len; i++) 185 MD5_Update(&md5, auth->cname.name_string.val[i], 186 strlen(auth->cname.name_string.val[i])); 187 MD5_Update (&md5, &auth->ctime, sizeof(auth->ctime)); 188 MD5_Update (&md5, &auth->cusec, sizeof(auth->cusec)); 189 MD5_Final (data, &md5); 190 } 191 192 krb5_error_code KRB5_LIB_FUNCTION 193 krb5_rc_store(krb5_context context, 194 krb5_rcache id, 195 krb5_donot_replay *rep) 196 { 197 struct rc_entry ent, tmp; 198 time_t t; 199 FILE *f; 200 int ret; 201 202 ent.stamp = time(NULL); 203 checksum_authenticator(rep, ent.data); 204 f = fopen(id->name, "r"); 205 if(f == NULL) { 206 ret = errno; 207 krb5_set_error_string (context, "open(%s): %s", id->name, 208 strerror(ret)); 209 return ret; 210 } 211 fread(&tmp, sizeof(ent), 1, f); 212 t = ent.stamp - tmp.stamp; 213 while(fread(&tmp, sizeof(ent), 1, f)){ 214 if(tmp.stamp < t) 215 continue; 216 if(memcmp(tmp.data, ent.data, sizeof(ent.data)) == 0){ 217 fclose(f); 218 krb5_clear_error_string (context); 219 return KRB5_RC_REPLAY; 220 } 221 } 222 if(ferror(f)){ 223 ret = errno; 224 fclose(f); 225 krb5_set_error_string (context, "%s: %s", id->name, strerror(ret)); 226 return ret; 227 } 228 fclose(f); 229 f = fopen(id->name, "a"); 230 if(f == NULL) { 231 krb5_set_error_string (context, "open(%s): %s", id->name, 232 strerror(errno)); 233 return KRB5_RC_IO_UNKNOWN; 234 } 235 fwrite(&ent, 1, sizeof(ent), f); 236 fclose(f); 237 return 0; 238 } 239 240 krb5_error_code KRB5_LIB_FUNCTION 241 krb5_rc_expunge(krb5_context context, 242 krb5_rcache id) 243 { 244 return 0; 245 } 246 247 krb5_error_code KRB5_LIB_FUNCTION 248 krb5_rc_get_lifespan(krb5_context context, 249 krb5_rcache id, 250 krb5_deltat *auth_lifespan) 251 { 252 FILE *f = fopen(id->name, "r"); 253 int r; 254 struct rc_entry ent; 255 r = fread(&ent, sizeof(ent), 1, f); 256 fclose(f); 257 if(r){ 258 *auth_lifespan = ent.stamp; 259 return 0; 260 } 261 krb5_clear_error_string (context); 262 return KRB5_RC_IO_UNKNOWN; 263 } 264 265 const char* KRB5_LIB_FUNCTION 266 krb5_rc_get_name(krb5_context context, 267 krb5_rcache id) 268 { 269 return id->name; 270 } 271 272 const char* KRB5_LIB_FUNCTION 273 krb5_rc_get_type(krb5_context context, 274 krb5_rcache id) 275 { 276 return "FILE"; 277 } 278 279 krb5_error_code KRB5_LIB_FUNCTION 280 krb5_get_server_rcache(krb5_context context, 281 const krb5_data *piece, 282 krb5_rcache *id) 283 { 284 krb5_rcache rcache; 285 krb5_error_code ret; 286 287 char *tmp = malloc(4 * piece->length + 1); 288 char *name; 289 290 if(tmp == NULL) { 291 krb5_set_error_string (context, "malloc: out of memory"); 292 return ENOMEM; 293 } 294 strvisx(tmp, piece->data, piece->length, VIS_WHITE | VIS_OCTAL); 295 #ifdef HAVE_GETEUID 296 asprintf(&name, "FILE:rc_%s_%u", tmp, (unsigned)geteuid()); 297 #else 298 asprintf(&name, "FILE:rc_%s", tmp); 299 #endif 300 free(tmp); 301 if(name == NULL) { 302 krb5_set_error_string (context, "malloc: out of memory"); 303 return ENOMEM; 304 } 305 306 ret = krb5_rc_resolve_full(context, &rcache, name); 307 free(name); 308 if(ret) 309 return ret; 310 *id = rcache; 311 return ret; 312 } 313