1 /*
2  * Copyright 2007 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 
34 static struct krb5_rc_typelist rc_none_type = { &krb5_rc_none_ops, 0 };
35 static struct krb5_rc_typelist rc_mem_type =
36 	{ &krb5_rc_mem_ops, &rc_none_type };
37 static struct krb5_rc_typelist krb5_rc_typelist_dfl =
38 	{ &krb5_rc_file_ops, &rc_mem_type };
39 static struct krb5_rc_typelist *typehead = &krb5_rc_typelist_dfl;
40 static k5_mutex_t rc_typelist_lock = K5_MUTEX_PARTIAL_INITIALIZER;
41 
42 int krb5int_rc_finish_init(void)
43 {
44     int retval;
45 
46     retval = k5_mutex_finish_init(&grcache.lock);
47     if (retval)
48 	return (retval);
49 
50     return k5_mutex_finish_init(&rc_typelist_lock);
51 }
52 void krb5int_rc_terminate(void)
53 {
54     struct krb5_rc_typelist *t, *t_next;
55     struct mem_data *tgr = (struct mem_data *)grcache.data;
56     struct authlist *q, *qt;
57     int i;
58 
59     k5_mutex_destroy(&grcache.lock);
60 
61     if (tgr != NULL) {
62     	if (tgr->name)
63 		free(tgr->name);
64     	for (i = 0; i < tgr->hsize; i++)
65 		for (q = tgr->h[i]; q; q = qt) {
66 			qt = q->nh;
67 			free(q->rep.server);
68 			free(q->rep.client);
69 			free(q);
70 		}
71     	if (tgr->h)
72 		free(tgr->h);
73     	free(tgr);
74     }
75 
76     k5_mutex_destroy(&rc_typelist_lock);
77     for (t = typehead; t != &krb5_rc_typelist_dfl; t = t_next) {
78 	t_next = t->next;
79 	free(t);
80     }
81 }
82 
83 /*ARGSUSED*/
84 krb5_error_code krb5_rc_register_type(krb5_context context,
85 				      const krb5_rc_ops *ops)
86 {
87  struct krb5_rc_typelist *t;
88  krb5_error_code err;
89 
90  err = k5_mutex_lock(&rc_typelist_lock);
91  if (err)
92 	return err;
93 
94  for (t = typehead;t && strcmp(t->ops->type,ops->type);t = t->next)
95    ;
96  if (t) {
97    k5_mutex_unlock(&rc_typelist_lock);
98    return KRB5_RC_TYPE_EXISTS;
99  }
100 
101  t = (struct krb5_rc_typelist *) malloc(sizeof(struct krb5_rc_typelist));
102  if (t == NULL) {
103 	k5_mutex_unlock(&rc_typelist_lock);
104 	return KRB5_RC_MALLOC;
105  }
106  t->next = typehead;
107  t->ops = ops;
108  typehead = t;
109 
110  k5_mutex_unlock(&rc_typelist_lock);
111  return 0;
112 }
113 
114 /*ARGSUSED*/
115 krb5_error_code krb5_rc_resolve_type(krb5_context context, krb5_rcache *id,
116 				     char *type)
117 {
118     struct krb5_rc_typelist *t;
119     krb5_error_code err;
120     err = k5_mutex_lock(&rc_typelist_lock);
121     if (err)
122 	return err;
123     for (t = typehead;t && strcmp(t->ops->type,type);t = t->next)
124 	;
125     if (!t) {
126 	k5_mutex_unlock(&rc_typelist_lock);
127 	return KRB5_RC_TYPE_NOTFOUND;
128     }
129     /* allocate *id? nah */
130     (*id)->ops = t->ops;
131     k5_mutex_unlock(&rc_typelist_lock);
132     return k5_mutex_init(&(*id)->lock);
133 }
134 
135 /*ARGSUSED*/
136 char * krb5_rc_get_type(krb5_context context, krb5_rcache id)
137 {
138  return id->ops->type;
139 }
140 
141 char * krb5_rc_default_type(krb5_context context)
142 {
143 	/*
144 	 * Solaris Kerberos/SUNW14resync
145 	 * MIT's is "dfl" but we now have FILE and MEMORY instead.
146 	 * And we only support the KRB5RCNAME env var.
147 	 */
148 	return ("FILE");
149 }
150 
151 /*ARGSUSED*/
152 char * krb5_rc_default_name(krb5_context context)
153 {
154  char *s;
155  if ((s = getenv("KRB5RCNAME")))
156    return s;
157  else
158    return (char *) 0;
159 }
160 
161 krb5_error_code
162 krb5_rc_default(krb5_context context, krb5_rcache *id)
163 {
164     krb5_error_code retval;
165 
166     if (!(*id = (krb5_rcache )malloc(sizeof(**id))))
167 	return KRB5_RC_MALLOC;
168 
169     retval = krb5_rc_resolve_type(context, id, krb5_rc_default_type(context));
170     if (retval != 0) {
171 	/*
172 	 * k5_mutex_destroy() is not called here, because the mutex had
173 	 * not been successfully initialized by krb5_rc_resolve_type().
174 	 */
175 	FREE_RC(*id);
176 	return (retval);
177     }
178     retval = krb5_rc_resolve(context, *id, krb5_rc_default_name(context));
179     if (retval) {
180         k5_mutex_destroy(&(*id)->lock);
181 	FREE_RC(*id);
182 	return retval;
183     }
184     (*id)->magic = KV5M_RCACHE;
185     return retval;
186 }
187 
188 krb5_error_code krb5_rc_resolve_full(krb5_context context, krb5_rcache *id, char *string_name)
189 {
190     char *type;
191     char *residual;
192     krb5_error_code retval;
193     unsigned int diff;
194 
195     if (!(residual = strchr(string_name,':')))
196 	return KRB5_RC_PARSE;
197 
198     diff = residual - string_name;
199     if (!(type = malloc(diff + 1)))
200 	return KRB5_RC_MALLOC;
201     (void) strncpy(type, string_name, diff);
202     type[residual - string_name] = '\0';
203 
204     if (!(*id = (krb5_rcache) malloc(sizeof(**id)))) {
205 	FREE_RC(type);
206 	return KRB5_RC_MALLOC;
207     }
208 
209     retval = krb5_rc_resolve_type(context, id, type);
210     if (retval != 0) {
211 	/*
212 	 * k5_mutex_destroy() is not called here, because the mutex had
213 	 * not been successfully initialized by krb5_rc_resolve_type().
214 	 */
215 	FREE_RC(type);
216 	FREE_RC(*id);
217 	return retval;
218     }
219     FREE_RC(type);
220     retval = krb5_rc_resolve(context, *id, residual + 1);
221     if (retval) {
222         k5_mutex_destroy(&(*id)->lock);
223 	FREE_RC(*id);
224 	return retval;
225     }
226     (*id)->magic = KV5M_RCACHE;
227     return retval;
228 }
229