1 /*
2  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 
8 /*
9  * lib/krb5/rcache/rc_base.c
10  *
11  * This file of the Kerberos V5 software is derived from public-domain code
12  * contributed by Daniel J. Bernstein, <brnstnd@acf10.nyu.edu>.
13  */
14 
15 
16 /*
17  * Base "glue" functions for the replay cache.
18  */
19 
20 #include "rc_base.h"
21 #include "rc_common.h"
22 #include "rc_mem.h"
23 #include "rc_file.h"
24 #include <k5-thread.h>
25 
26 #define FREE_RC(x) ((void) free((char *) (x)))
27 
28 struct krb5_rc_typelist
29  {
30   const krb5_rc_ops *ops;
31   struct krb5_rc_typelist *next;
32  };
33 static struct krb5_rc_typelist rc_mem_type = { &krb5_rc_mem_ops, 0 };
34 static struct krb5_rc_typelist krb5_rc_typelist_dfl =
35 	{ &krb5_rc_file_ops, &rc_mem_type };
36 static struct krb5_rc_typelist *typehead = &krb5_rc_typelist_dfl;
37 static k5_mutex_t rc_typelist_lock = K5_MUTEX_PARTIAL_INITIALIZER;
38 
39 int krb5int_rc_finish_init(void)
40 {
41     return k5_mutex_finish_init(&rc_typelist_lock);
42 }
43 void krb5int_rc_terminate(void)
44 {
45     struct krb5_rc_typelist *t, *t_next;
46     k5_mutex_destroy(&rc_typelist_lock);
47     for (t = typehead; t != &krb5_rc_typelist_dfl; t = t_next) {
48 	t_next = t->next;
49 	free(t);
50     }
51 }
52 
53 /*ARGSUSED*/
54 krb5_error_code krb5_rc_register_type(krb5_context context,
55 				      const krb5_rc_ops *ops)
56 {
57  struct krb5_rc_typelist *t;
58  krb5_error_code err;
59 
60  err = k5_mutex_lock(&rc_typelist_lock);
61  if (err)
62 	return err;
63 
64  for (t = typehead;t && strcmp(t->ops->type,ops->type);t = t->next)
65    ;
66  if (t) {
67    k5_mutex_unlock(&rc_typelist_lock);
68    return KRB5_RC_TYPE_EXISTS;
69  }
70 
71  t = (struct krb5_rc_typelist *) malloc(sizeof(struct krb5_rc_typelist));
72  if (t == NULL) {
73 	k5_mutex_unlock(&rc_typelist_lock);
74 	return KRB5_RC_MALLOC;
75  }
76  t->next = typehead;
77  t->ops = ops;
78  typehead = t;
79 
80  k5_mutex_unlock(&rc_typelist_lock);
81  return 0;
82 }
83 
84 /*ARGSUSED*/
85 krb5_error_code krb5_rc_resolve_type(krb5_context context, krb5_rcache *id,
86 				     char *type)
87 {
88     struct krb5_rc_typelist *t;
89     krb5_error_code err;
90     err = k5_mutex_lock(&rc_typelist_lock);
91     if (err)
92 	return err;
93     for (t = typehead;t && strcmp(t->ops->type,type);t = t->next)
94 	;
95     if (!t) {
96 	k5_mutex_unlock(&rc_typelist_lock);
97 	return KRB5_RC_TYPE_NOTFOUND;
98     }
99     /* allocate *id? nah */
100     (*id)->ops = t->ops;
101     k5_mutex_unlock(&rc_typelist_lock);
102     return k5_mutex_init(&(*id)->lock);
103 }
104 
105 /*ARGSUSED*/
106 char * krb5_rc_get_type(krb5_context context, krb5_rcache id)
107 {
108  return id->ops->type;
109 }
110 
111 char * krb5_rc_default_type(krb5_context context)
112 {
113 	/*
114 	 * Solaris Kerberos/SUNW14resync
115 	 * MIT's is "dfl" but we now have FILE and MEMORY instead.
116 	 * And we only support the KRB5RCNAME env var.
117 	 */
118 	return ("FILE");
119 }
120 
121 /*ARGSUSED*/
122 char * krb5_rc_default_name(krb5_context context)
123 {
124  char *s;
125  if ((s = getenv("KRB5RCNAME")))
126    return s;
127  else
128    return (char *) 0;
129 }
130 
131 krb5_error_code
132 krb5_rc_default(krb5_context context, krb5_rcache *id)
133 {
134     krb5_error_code retval;
135 
136     if (!(*id = (krb5_rcache )malloc(sizeof(**id))))
137 	return KRB5_RC_MALLOC;
138 
139     retval = krb5_rc_resolve_type(context, id, krb5_rc_default_type(context));
140     if (retval != 0) {
141 	k5_mutex_destroy(&(*id)->lock);
142 	FREE_RC(*id);
143 	return (retval);
144     }
145     retval = krb5_rc_resolve(context, *id, krb5_rc_default_name(context));
146     if (retval) {
147         k5_mutex_destroy(&(*id)->lock);
148 	FREE_RC(*id);
149 	return retval;
150     }
151     (*id)->magic = KV5M_RCACHE;
152     return retval;
153 }
154 
155 krb5_error_code krb5_rc_resolve_full(krb5_context context, krb5_rcache *id, char *string_name)
156 {
157     char *type;
158     char *residual;
159     krb5_error_code retval;
160     unsigned int diff;
161 
162     if (!(residual = strchr(string_name,':')))
163 	return KRB5_RC_PARSE;
164 
165     diff = residual - string_name;
166     if (!(type = malloc(diff + 1)))
167 	return KRB5_RC_MALLOC;
168     (void) strncpy(type, string_name, diff);
169     type[residual - string_name] = '\0';
170 
171     if (!(*id = (krb5_rcache) malloc(sizeof(**id)))) {
172 	FREE_RC(type);
173 	return KRB5_RC_MALLOC;
174     }
175 
176     if ((retval = krb5_rc_resolve_type(context, id,type))) {
177 	FREE_RC(type);
178 	k5_mutex_destroy(&(*id)->lock);
179 	FREE_RC(*id);
180 	return retval;
181     }
182     FREE_RC(type);
183     retval = krb5_rc_resolve(context, *id, residual + 1);
184     if (retval) {
185         k5_mutex_destroy(&(*id)->lock);
186 	FREE_RC(*id);
187 	return retval;
188     }
189     (*id)->magic = KV5M_RCACHE;
190     return retval;
191 }
192