Merge from vendor branch GCC:
[dragonfly.git] / crypto / heimdal-0.6.3 / lib / hdb / hdb.c
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 "hdb_locl.h"
35
36 RCSID("$Id: hdb.c,v 1.44 2001/08/09 08:41:48 assar Exp $");
37
38 struct hdb_method {
39     const char *prefix;
40     krb5_error_code (*create)(krb5_context, HDB **, const char *filename);
41 };
42
43 static struct hdb_method methods[] = {
44 #if HAVE_DB1 || HAVE_DB3
45     {"db:",     hdb_db_create},
46 #endif
47 #if HAVE_NDBM
48     {"ndbm:",   hdb_ndbm_create},
49 #endif
50 #ifdef OPENLDAP
51     {"ldap:",   hdb_ldap_create},
52 #endif
53 #if HAVE_DB1 || HAVE_DB3
54     {"",        hdb_db_create},
55 #elif defined(HAVE_NDBM)
56     {"",        hdb_ndbm_create},
57 #elif defined(OPENLDAP)
58     {"",        hdb_ldap_create},
59 #endif
60     {NULL,      NULL}
61 };
62
63 krb5_error_code
64 hdb_next_enctype2key(krb5_context context,
65                      const hdb_entry *e,
66                      krb5_enctype enctype,
67                      Key **key)
68 {
69     Key *k;
70     
71     for (k = *key ? (*key) + 1 : e->keys.val;
72          k < e->keys.val + e->keys.len; 
73          k++)
74         if(k->key.keytype == enctype){
75             *key = k;
76             return 0;
77         }
78     return KRB5_PROG_ETYPE_NOSUPP; /* XXX */
79 }
80
81 krb5_error_code
82 hdb_enctype2key(krb5_context context, 
83                 hdb_entry *e, 
84                 krb5_enctype enctype, 
85                 Key **key)
86 {
87     *key = NULL;
88     return hdb_next_enctype2key(context, e, enctype, key);
89 }
90
91 void
92 hdb_free_key(Key *key)
93 {
94     memset(key->key.keyvalue.data, 
95            0,
96            key->key.keyvalue.length);
97     free_Key(key);
98     free(key);
99 }
100
101
102 krb5_error_code
103 hdb_lock(int fd, int operation)
104 {
105     int i, code = 0;
106
107     for(i = 0; i < 3; i++){
108         code = flock(fd, (operation == HDB_RLOCK ? LOCK_SH : LOCK_EX) | LOCK_NB);
109         if(code == 0 || errno != EWOULDBLOCK)
110             break;
111         sleep(1);
112     }
113     if(code == 0)
114         return 0;
115     if(errno == EWOULDBLOCK)
116         return HDB_ERR_DB_INUSE;
117     return HDB_ERR_CANT_LOCK_DB;
118 }
119
120 krb5_error_code
121 hdb_unlock(int fd)
122 {
123     int code;
124     code = flock(fd, LOCK_UN);
125     if(code)
126         return 4711 /* XXX */;
127     return 0;
128 }
129
130 void
131 hdb_free_entry(krb5_context context, hdb_entry *ent)
132 {
133     int i;
134
135     for(i = 0; i < ent->keys.len; ++i) {
136         Key *k = &ent->keys.val[i];
137
138         memset (k->key.keyvalue.data, 0, k->key.keyvalue.length);
139     }
140     free_hdb_entry(ent);
141 }
142
143 krb5_error_code
144 hdb_foreach(krb5_context context,
145             HDB *db,
146             unsigned flags,
147             hdb_foreach_func_t func,
148             void *data)
149 {
150     krb5_error_code ret;
151     hdb_entry entry;
152     ret = db->firstkey(context, db, flags, &entry);
153     while(ret == 0){
154         ret = (*func)(context, db, &entry, data);
155         hdb_free_entry(context, &entry);
156         if(ret == 0)
157             ret = db->nextkey(context, db, flags, &entry);
158     }
159     if(ret == HDB_ERR_NOENTRY)
160         ret = 0;
161     return ret;
162 }
163
164 krb5_error_code
165 hdb_check_db_format(krb5_context context, HDB *db)
166 {
167     krb5_data tag;
168     krb5_data version;
169     krb5_error_code ret;
170     unsigned ver;
171     int foo;
172
173     tag.data = HDB_DB_FORMAT_ENTRY;
174     tag.length = strlen(tag.data);
175     ret = (*db->_get)(context, db, tag, &version);
176     if(ret)
177         return ret;
178     foo = sscanf(version.data, "%u", &ver);
179     krb5_data_free (&version);
180     if (foo != 1)
181         return HDB_ERR_BADVERSION;
182     if(ver != HDB_DB_FORMAT)
183         return HDB_ERR_BADVERSION;
184     return 0;
185 }
186
187 krb5_error_code
188 hdb_init_db(krb5_context context, HDB *db)
189 {
190     krb5_error_code ret;
191     krb5_data tag;
192     krb5_data version;
193     char ver[32];
194     
195     ret = hdb_check_db_format(context, db);
196     if(ret != HDB_ERR_NOENTRY)
197         return ret;
198     
199     tag.data = HDB_DB_FORMAT_ENTRY;
200     tag.length = strlen(tag.data);
201     snprintf(ver, sizeof(ver), "%u", HDB_DB_FORMAT);
202     version.data = ver;
203     version.length = strlen(version.data) + 1; /* zero terminated */
204     ret = (*db->_put)(context, db, 0, tag, version);
205     return ret;
206 }
207
208 /*
209  * find the relevant method for `filename', returning a pointer to the
210  * rest in `rest'.
211  * return NULL if there's no such method.
212  */
213
214 static const struct hdb_method *
215 find_method (const char *filename, const char **rest)
216 {
217     const struct hdb_method *h;
218
219     for (h = methods; h->prefix != NULL; ++h)
220         if (strncmp (filename, h->prefix, strlen(h->prefix)) == 0) {
221             *rest = filename + strlen(h->prefix);
222             return h;
223         }
224     return NULL;
225 }
226
227 krb5_error_code
228 hdb_create(krb5_context context, HDB **db, const char *filename)
229 {
230     const struct hdb_method *h;
231     const char *residual;
232
233     if(filename == NULL)
234         filename = HDB_DEFAULT_DB;
235     krb5_add_et_list(context, initialize_hdb_error_table_r);
236     h = find_method (filename, &residual);
237     if (h == NULL)
238         krb5_errx(context, 1, "No database support! (hdb_create)");
239     return (*h->create)(context, db, residual);
240 }