GSS_S_PROMPTING_NEEDED is a bit
[cyrus-sasl.git] / plugins / sasldb.c
1 /* SASL server API implementation
2  * Rob Siemborski
3  * Tim Martin
4  * $Id: sasldb.c,v 1.11 2006/04/03 10:58:19 mel Exp $
5  */
6 /* 
7  * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer. 
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in
18  *    the documentation and/or other materials provided with the
19  *    distribution.
20  *
21  * 3. The name "Carnegie Mellon University" must not be used to
22  *    endorse or promote products derived from this software without
23  *    prior written permission. For permission or any other legal
24  *    details, please contact  
25  *      Office of Technology Transfer
26  *      Carnegie Mellon University
27  *      5000 Forbes Avenue
28  *      Pittsburgh, PA  15213-3890
29  *      (412) 268-4387, fax: (412) 268-7395
30  *      tech-transfer@andrew.cmu.edu
31  *
32  * 4. Redistributions of any form whatsoever must retain the following
33  *    acknowledgment:
34  *    "This product includes software developed by Computing Services
35  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
36  *
37  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
38  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
39  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
40  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
41  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
42  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
43  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
44  */
45
46 #include <config.h>
47
48 /* sasldb stuff */
49
50 #include <stdio.h>
51
52 #include "sasl.h"
53 #include "saslutil.h"
54 #include "saslplug.h"
55 #include "../sasldb/sasldb.h"
56
57 #include "plugin_common.h"
58
59 static void sasldb_auxprop_lookup(void *glob_context __attribute__((unused)),
60                                   sasl_server_params_t *sparams,
61                                   unsigned flags,
62                                   const char *user,
63                                   unsigned ulen) 
64 {
65     char *userid = NULL;
66     char *realm = NULL;
67     const char *user_realm = NULL;
68     int ret;
69     const struct propval *to_fetch, *cur;
70     char value[8192];
71     size_t value_len;
72     char *user_buf;
73     
74     if(!sparams || !user) return;
75
76     user_buf = sparams->utils->malloc(ulen + 1);
77     if(!user_buf) {
78         goto done;
79     }
80
81     memcpy(user_buf, user, ulen);
82     user_buf[ulen] = '\0';
83
84     if(sparams->user_realm) {
85         user_realm = sparams->user_realm;
86     } else {
87         user_realm = sparams->serverFQDN;
88     }
89
90     ret = _plug_parseuser(sparams->utils, &userid, &realm, user_realm,
91                           sparams->serverFQDN, user_buf);
92     if(ret != SASL_OK) goto done;
93
94     to_fetch = sparams->utils->prop_get(sparams->propctx);
95     if(!to_fetch) goto done;
96
97     for(cur = to_fetch; cur->name; cur++) {
98         const char *realname = cur->name;
99         
100         /* Only look up properties that apply to this lookup! */
101         if(cur->name[0] == '*' && (flags & SASL_AUXPROP_AUTHZID)) continue;
102         if(!(flags & SASL_AUXPROP_AUTHZID)) {
103             if(cur->name[0] != '*') continue;
104             else realname = cur->name + 1;
105         }
106         
107         /* If it's there already, we want to see if it needs to be
108          * overridden */
109         if(cur->values && !(flags & SASL_AUXPROP_OVERRIDE))
110             continue;
111         else if(cur->values)
112             sparams->utils->prop_erase(sparams->propctx, cur->name);
113             
114         ret = _sasldb_getdata(sparams->utils,
115                               sparams->utils->conn, userid, realm,
116                               realname, value, sizeof(value), &value_len);
117         if(ret != SASL_OK) {
118             /* We didn't find it, leave it as not found */
119             continue;
120         }
121
122         sparams->utils->prop_set(sparams->propctx, cur->name,
123                                  value, (unsigned) value_len);
124     }
125
126  done:
127     if (userid) sparams->utils->free(userid);
128     if (realm)  sparams->utils->free(realm);
129     if (user_buf) sparams->utils->free(user_buf);
130 }
131
132 static int sasldb_auxprop_store(void *glob_context __attribute__((unused)),
133                                 sasl_server_params_t *sparams,
134                                 struct propctx *ctx,
135                                 const char *user,
136                                 unsigned ulen) 
137 {
138     char *userid = NULL;
139     char *realm = NULL;
140     const char *user_realm = NULL;
141     int ret = SASL_FAIL;
142     int tmp_res;
143     const struct propval *to_store, *cur;
144     char *user_buf;
145
146     /* just checking if we are enabled */
147     if(!ctx) return SASL_OK;
148     
149     if(!sparams || !user) return SASL_BADPARAM;
150
151     user_buf = sparams->utils->malloc(ulen + 1);
152     if(!user_buf) {
153         ret = SASL_NOMEM;
154         goto done;
155     }
156
157     memcpy(user_buf, user, ulen);
158     user_buf[ulen] = '\0';
159
160     if(sparams->user_realm) {
161         user_realm = sparams->user_realm;
162     } else {
163         user_realm = sparams->serverFQDN;
164     }
165
166     ret = _plug_parseuser(sparams->utils, &userid, &realm, user_realm,
167                           sparams->serverFQDN, user_buf);
168     if(ret != SASL_OK) goto done;
169
170     to_store = sparams->utils->prop_get(ctx);
171     if(!to_store) {
172         ret = SASL_BADPARAM;
173         goto done;
174     }
175
176     /* All iterations return SASL_NOUSER                   ==> ret = SASL_NOUSER
177        Some iterations return SASL_OK and some SASL_NOUSER ==> ret = SASL_OK
178        At least one iteration returns any other error      ==> ret = the error */
179     ret = SASL_NOUSER;
180     for(cur = to_store; cur->name; cur++) {
181         /* We only support one value at a time right now. */
182         tmp_res = _sasldb_putdata(sparams->utils, sparams->utils->conn,
183                               userid, realm, cur->name,
184                               cur->values && cur->values[0] ?
185                               cur->values[0] : NULL,
186                               cur->values && cur->values[0] ?
187                               strlen(cur->values[0]) : 0);
188         /* SASL_NOUSER is returned when _sasldb_putdata fails to delete
189            a non-existent entry, which should not be treated as an error */
190         if ((tmp_res != SASL_NOUSER) &&
191             (ret == SASL_NOUSER || ret == SASL_OK)) {
192             ret = tmp_res;
193         }
194
195         /* Abort the loop if an error has occurred */
196         if (ret != SASL_NOUSER && ret != SASL_OK) {
197             break;
198         }
199     }
200
201  done:
202     if (userid) sparams->utils->free(userid);
203     if (realm)  sparams->utils->free(realm);
204     if (user_buf) sparams->utils->free(user_buf);
205
206     return ret;
207 }
208
209 static sasl_auxprop_plug_t sasldb_auxprop_plugin = {
210     0,                          /* Features */
211     0,                          /* spare */
212     NULL,                       /* glob_context */
213     sasldb_auxprop_free,        /* auxprop_free */
214     sasldb_auxprop_lookup,      /* auxprop_lookup */
215     "sasldb",                   /* name */
216     sasldb_auxprop_store        /* auxprop_store */
217 };
218
219 int sasldb_auxprop_plug_init(const sasl_utils_t *utils,
220                              int max_version,
221                              int *out_version,
222                              sasl_auxprop_plug_t **plug,
223                              const char *plugname __attribute__((unused))) 
224 {
225     if(!out_version || !plug) return SASL_BADPARAM;
226
227     /* Do we have database support? */
228     /* Note that we can use a NULL sasl_conn_t because our
229      * sasl_utils_t is "blessed" with the global callbacks */
230     if(_sasl_check_db(utils, NULL) != SASL_OK)
231         return SASL_NOMECH;
232
233     if(max_version < SASL_AUXPROP_PLUG_VERSION) return SASL_BADVERS;
234     
235     *out_version = SASL_AUXPROP_PLUG_VERSION;
236
237     *plug = &sasldb_auxprop_plugin;
238
239     return SASL_OK;
240 }