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 37RCSID("$Id: replay.c 17047 2006-04-10 17:13:49Z lha $"); 38 39struct krb5_rcache_data { 40 char *name; 41}; 42 43krb5_error_code KRB5_LIB_FUNCTION 44krb5_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 56krb5_error_code KRB5_LIB_FUNCTION 57krb5_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 75krb5_error_code KRB5_LIB_FUNCTION 76krb5_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 100const char* KRB5_LIB_FUNCTION 101krb5_rc_default_name(krb5_context context) 102{ 103 return "FILE:/var/run/default_rcache"; 104} 105 106const char* KRB5_LIB_FUNCTION 107krb5_rc_default_type(krb5_context context) 108{ 109 return "FILE"; 110} 111 112krb5_error_code KRB5_LIB_FUNCTION 113krb5_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 119struct rc_entry{ 120 time_t stamp; 121 unsigned char data[16]; 122}; 123 124krb5_error_code KRB5_LIB_FUNCTION 125krb5_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 145krb5_error_code KRB5_LIB_FUNCTION 146krb5_rc_recover(krb5_context context, 147 krb5_rcache id) 148{ 149 return 0; 150} 151 152krb5_error_code KRB5_LIB_FUNCTION 153krb5_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 167krb5_error_code KRB5_LIB_FUNCTION 168krb5_rc_close(krb5_context context, 169 krb5_rcache id) 170{ 171 free(id->name); 172 free(id); 173 return 0; 174} 175 176static void 177checksum_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 192krb5_error_code KRB5_LIB_FUNCTION 193krb5_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 240krb5_error_code KRB5_LIB_FUNCTION 241krb5_rc_expunge(krb5_context context, 242 krb5_rcache id) 243{ 244 return 0; 245} 246 247krb5_error_code KRB5_LIB_FUNCTION 248krb5_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 265const char* KRB5_LIB_FUNCTION 266krb5_rc_get_name(krb5_context context, 267 krb5_rcache id) 268{ 269 return id->name; 270} 271 272const char* KRB5_LIB_FUNCTION 273krb5_rc_get_type(krb5_context context, 274 krb5_rcache id) 275{ 276 return "FILE"; 277} 278 279krb5_error_code KRB5_LIB_FUNCTION 280krb5_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