1 | /* |
---|
2 | * security.c -- Security handler |
---|
3 | * |
---|
4 | * Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved. |
---|
5 | * |
---|
6 | * See the file "license.txt" for usage and redistribution license requirements |
---|
7 | * |
---|
8 | * $Id$ |
---|
9 | */ |
---|
10 | |
---|
11 | /******************************** Description *********************************/ |
---|
12 | |
---|
13 | /* |
---|
14 | * This module provides a basic security policy. |
---|
15 | */ |
---|
16 | |
---|
17 | /********************************* Includes ***********************************/ |
---|
18 | |
---|
19 | #include "wsIntrn.h" |
---|
20 | #include "um.h" |
---|
21 | #ifdef DIGEST_ACCESS_SUPPORT |
---|
22 | #include "websda.h" |
---|
23 | #endif |
---|
24 | |
---|
25 | /********************************** Defines ***********************************/ |
---|
26 | /* |
---|
27 | * The following #defines change the behaviour of security in the absence |
---|
28 | * of User Management. |
---|
29 | * Note that use of User management functions require prior calling of |
---|
30 | * umInit() to behave correctly |
---|
31 | */ |
---|
32 | |
---|
33 | #ifndef USER_MANAGEMENT_SUPPORT |
---|
34 | #define umGetAccessMethodForURL(url) AM_FULL |
---|
35 | #define umUserExists(userid) 0 |
---|
36 | #define umUserCanAccessURL(userid, url) 1 |
---|
37 | #define umGetUserPassword(userid) websGetPassword() |
---|
38 | #define umGetAccessLimitSecure(accessLimit) 0 |
---|
39 | #define umGetAccessLimit(url) NULL |
---|
40 | #endif |
---|
41 | |
---|
42 | /******************************** Local Data **********************************/ |
---|
43 | |
---|
44 | static char_t websPassword[WEBS_MAX_PASS]; /* Access password (decoded) */ |
---|
45 | #ifdef _DEBUG |
---|
46 | static int debugSecurity = 1; |
---|
47 | #else |
---|
48 | static int debugSecurity = 0; |
---|
49 | #endif |
---|
50 | |
---|
51 | /*********************************** Code *************************************/ |
---|
52 | /* |
---|
53 | * Determine if this request should be honored |
---|
54 | */ |
---|
55 | |
---|
56 | int websSecurityHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg, |
---|
57 | char_t *url, char_t *path, char_t *query) |
---|
58 | { |
---|
59 | char_t *type, *userid, *password, *accessLimit; |
---|
60 | int flags, nRet; |
---|
61 | accessMeth_t am; |
---|
62 | |
---|
63 | a_assert(websValid(wp)); |
---|
64 | a_assert(url && *url); |
---|
65 | a_assert(path && *path); |
---|
66 | /* |
---|
67 | * Get the critical request details |
---|
68 | */ |
---|
69 | type = websGetRequestType(wp); |
---|
70 | password = websGetRequestPassword(wp); |
---|
71 | userid = websGetRequestUserName(wp); |
---|
72 | flags = websGetRequestFlags(wp); |
---|
73 | /* |
---|
74 | * Get the access limit for the URL. Exit if none found. |
---|
75 | */ |
---|
76 | accessLimit = umGetAccessLimit(path); |
---|
77 | if (accessLimit == NULL) { |
---|
78 | return 0; |
---|
79 | } |
---|
80 | |
---|
81 | /* |
---|
82 | * Check to see if URL must be encrypted |
---|
83 | */ |
---|
84 | #ifdef WEBS_SSL_SUPPORT |
---|
85 | nRet = umGetAccessLimitSecure(accessLimit); |
---|
86 | if (nRet && ((flags & WEBS_SECURE) == 0)) { |
---|
87 | websStats.access++; |
---|
88 | websError(wp, 405, T("Access Denied\nSecure access is required.")); |
---|
89 | trace(3, T("SEC: Non-secure access attempted on <%s>\n"), path); |
---|
90 | /* bugfix 5/24/02 -- we were leaking the memory pointed to by |
---|
91 | * 'accessLimit'. Thanks to Simon Byholm. |
---|
92 | */ |
---|
93 | bfree(B_L, accessLimit); |
---|
94 | return 1; |
---|
95 | } |
---|
96 | #endif |
---|
97 | |
---|
98 | /* |
---|
99 | * Get the access limit for the URL |
---|
100 | */ |
---|
101 | am = umGetAccessMethodForURL(accessLimit); |
---|
102 | |
---|
103 | nRet = 0; |
---|
104 | if ((flags & WEBS_LOCAL_REQUEST) && (debugSecurity == 0)) { |
---|
105 | /* |
---|
106 | * Local access is always allowed (defeat when debugging) |
---|
107 | */ |
---|
108 | } else if (am == AM_NONE) { |
---|
109 | /* |
---|
110 | * URL is supposed to be hidden! Make like it wasn't found. |
---|
111 | */ |
---|
112 | websStats.access++; |
---|
113 | websError(wp, 400, T("Page Not Found")); |
---|
114 | nRet = 1; |
---|
115 | } else if (userid && *userid) { |
---|
116 | if (!umUserExists(userid)) { |
---|
117 | websStats.access++; |
---|
118 | websError(wp, 401, T("Access Denied\nUnknown User")); |
---|
119 | trace(3, T("SEC: Unknown user <%s> attempted to access <%s>\n"), |
---|
120 | userid, path); |
---|
121 | nRet = 1; |
---|
122 | } else if (!umUserCanAccessURL(userid, accessLimit)) { |
---|
123 | websStats.access++; |
---|
124 | websError(wp, 403, T("Access Denied\nProhibited User")); |
---|
125 | nRet = 1; |
---|
126 | } else if (password && * password) { |
---|
127 | char_t * userpass = umGetUserPassword(userid); |
---|
128 | if (userpass) { |
---|
129 | if (gstrcmp(password, userpass) != 0) { |
---|
130 | websStats.access++; |
---|
131 | websError(wp, 401, T("Access Denied\nWrong Password")); |
---|
132 | trace(3, T("SEC: Password fail for user <%s>") |
---|
133 | T("attempt to access <%s>\n"), userid, path); |
---|
134 | nRet = 1; |
---|
135 | } else { |
---|
136 | /* |
---|
137 | * User and password check out. |
---|
138 | */ |
---|
139 | } |
---|
140 | |
---|
141 | bfree (B_L, userpass); |
---|
142 | } |
---|
143 | #ifdef DIGEST_ACCESS_SUPPORT |
---|
144 | } else if (flags & WEBS_AUTH_DIGEST) { |
---|
145 | |
---|
146 | char_t *digestCalc; |
---|
147 | |
---|
148 | /* |
---|
149 | * Check digest for equivalence |
---|
150 | */ |
---|
151 | wp->password = umGetUserPassword(userid); |
---|
152 | |
---|
153 | a_assert(wp->digest); |
---|
154 | a_assert(wp->nonce); |
---|
155 | a_assert(wp->password); |
---|
156 | |
---|
157 | digestCalc = websCalcDigest(wp); |
---|
158 | a_assert(digestCalc); |
---|
159 | |
---|
160 | if (gstrcmp(wp->digest, digestCalc) != 0) { |
---|
161 | websStats.access++; |
---|
162 | websError(wp, 405, T("Access Denied\nWrong Password")); |
---|
163 | nRet = 1; |
---|
164 | } |
---|
165 | |
---|
166 | bfree (B_L, digestCalc); |
---|
167 | #endif |
---|
168 | } else { |
---|
169 | /* |
---|
170 | * No password has been specified |
---|
171 | */ |
---|
172 | #ifdef DIGEST_ACCESS_SUPPORT |
---|
173 | if (am == AM_DIGEST) { |
---|
174 | wp->flags |= WEBS_AUTH_DIGEST; |
---|
175 | } |
---|
176 | #endif |
---|
177 | websStats.errors++; |
---|
178 | websError(wp, 401, |
---|
179 | T("Access to this document requires a password")); |
---|
180 | nRet = 1; |
---|
181 | } |
---|
182 | } else if (am != AM_FULL) { |
---|
183 | /* |
---|
184 | * This will cause the browser to display a password / username |
---|
185 | * dialog |
---|
186 | */ |
---|
187 | #ifdef DIGEST_ACCESS_SUPPORT |
---|
188 | if (am == AM_DIGEST) { |
---|
189 | wp->flags |= WEBS_AUTH_DIGEST; |
---|
190 | } |
---|
191 | #endif |
---|
192 | websStats.errors++; |
---|
193 | websError(wp, 401, T("Access to this document requires a User ID")); |
---|
194 | nRet = 1; |
---|
195 | } |
---|
196 | |
---|
197 | bfree(B_L, accessLimit); |
---|
198 | |
---|
199 | return nRet; |
---|
200 | } |
---|
201 | |
---|
202 | /******************************************************************************/ |
---|
203 | /* |
---|
204 | * Delete the default security handler |
---|
205 | */ |
---|
206 | |
---|
207 | void websSecurityDelete() |
---|
208 | { |
---|
209 | websUrlHandlerDelete(websSecurityHandler); |
---|
210 | } |
---|
211 | |
---|
212 | /******************************************************************************/ |
---|
213 | /* |
---|
214 | * Store the new password, expect a decoded password. Store in websPassword in |
---|
215 | * the decoded form. |
---|
216 | */ |
---|
217 | |
---|
218 | void websSetPassword(char_t *password) |
---|
219 | { |
---|
220 | a_assert(password); |
---|
221 | |
---|
222 | gstrncpy(websPassword, password, TSZ(websPassword)); |
---|
223 | } |
---|
224 | |
---|
225 | /******************************************************************************/ |
---|
226 | /* |
---|
227 | * Get password, return the decoded form |
---|
228 | */ |
---|
229 | |
---|
230 | char_t *websGetPassword() |
---|
231 | { |
---|
232 | return bstrdup(B_L, websPassword); |
---|
233 | } |
---|
234 | |
---|
235 | /******************************************************************************/ |
---|