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