1 /* $Id: saslc.c,v 1.2 2011/01/29 23:35:31 agc Exp $ */
2 
3 /* Copyright (c) 2010 The NetBSD Foundation, Inc.
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to The NetBSD Foundation
7  * by Mateusz Kocielski.
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  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *        This product includes software developed by the NetBSD
20  *        Foundation, Inc. and its contributors.
21  * 4. Neither the name of The NetBSD Foundation nor the names of its
22  *    contributors may be used to endorse or promote products derived
23  *    from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
26  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE ARE DISCLAIMED.      IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 #include <saslc.h>
39 #include <ctype.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <stdbool.h>
43 #include <assert.h>
44 #include "dict.h"
45 #include "parser.h"
46 #include "saslc_private.h"
47 #include "mech.h"
48 #include "error.h"
49 
50 /* local headers */
51 
52 static bool saslc__valid_appname(const char *);
53 
54 /**
55  * @brief checks if application name is valid
56  * @param appname application name
57  * @return true if application name is valid, false otherwise
58  */
59 
60 static bool
61 saslc__valid_appname(const char *appname)
62 {
63         const char *p;
64 
65         for (p = appname; *p; p++)
66                 if (!isalnum((unsigned char)*p))
67                         return false;
68 
69         return true;
70 }
71 
72 
73 /**
74  * @brief allocates new saslc context
75  * @return saslc context
76  */
77 
78 saslc_t *
79 saslc_alloc(void)
80 {
81         return calloc(1, sizeof(saslc_t));
82 }
83 
84 /**
85  * @brief initializes sasl context, basing on application name function
86  * parses configuration files, sets up default peroperties and creates
87  * mechanisms list for the context.
88  * @param ctx sasl context
89  * @param appname application name, NULL could be used for generic aplication
90  * @return 0 on success, -1 otherwise.
91  */
92 
93 int
94 saslc_init(saslc_t *ctx, const char *appname)
95 {
96         memset(ctx, 0, sizeof(*ctx));
97 
98         LIST_INIT(&ctx->sessions);
99 
100         ctx->prop = saslc__dict_create();
101 
102         if (ctx->prop == NULL)
103                 return -1;
104 
105         /* appname */
106         if (appname != NULL) {
107                 /* check if appname is valid */
108                 if (saslc__valid_appname(appname) == false) {
109                         saslc__error_set(ERR(ctx), ERROR_BADARG,
110                             "application name is not permited");
111                         goto error;
112                 }
113 
114                 ctx->appname = strdup(appname);
115                 if (ctx->appname == NULL) {
116                         saslc__error_set_errno(ERR(ctx), ERROR_NOMEM);
117                         goto error;
118                 }
119         } else
120                 ctx->appname = NULL;
121 
122         /* mechanisms list */
123         if (saslc__mech_list_create(ctx) == -1)
124                 goto error;
125 
126         /* parse configuration files */
127         if (saslc__parser_config(ctx) == -1)
128                 /* errno is set up by parser */
129                 goto error;
130 
131         return 0;
132 
133 error:
134         if (ctx->appname != NULL)
135                 free((void *)ctx->appname);
136         if (ctx->prop != NULL)
137                 saslc__dict_destroy(ctx->prop);
138 
139         ctx->appname = NULL;
140         ctx->prop = NULL;
141 
142         return -1;
143 }
144 
145 /**
146  * @brief gets string message of last error.
147  * @param ctx context
148  * @return error string
149  */
150 
151 const char *
152 saslc_strerror(saslc_t *ctx)
153 {
154         return saslc__error_get_strerror(ERR(ctx));
155 }
156 
157 /**
158  * @brief destroys and deallocate resources used by the context.
159  * @param ctx context
160  * @param destroy_sessions indicates if all existing sessions assigned to
161  * the context (if any) should be destroyed
162  * @return 0 on success, -1 on failure
163  */
164 
165 int
166 saslc_end(saslc_t *ctx, bool destroy_sessions)
167 {
168         /* check if there're any assigned sessions */
169         if (!LIST_EMPTY(&ctx->sessions) && destroy_sessions == false) {
170                 saslc__error_set(ERR(ctx), ERROR_GENERAL,
171                     "context has got assigned active sessions");
172                 return -1;
173         }
174 
175         /* destroy all assigned sessions (note that if any nodes are assigned,
176          * then destroy_sessions == true) */
177         assert(LIST_EMPTY(&ctx->sessions) || destroy_sessions == true);
178         while (!LIST_EMPTY(&ctx->sessions))
179                 saslc_sess_end(LIST_FIRST(&ctx->sessions));
180 
181         /* mechanism list */
182         if (!LIST_EMPTY(&ctx->mechanisms))
183                 saslc__mech_list_destroy(&ctx->mechanisms);
184 
185         /* properties */
186         if (ctx->prop != NULL)
187                 saslc__dict_destroy(ctx->prop);
188 
189         /* application name */
190         free(ctx->appname);
191 
192         /* free context */
193         free(ctx);
194 
195         return 0;
196 }
197