1 /*
2 * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2005, 2008, 2009, 2010,
3 * 2011, 2012, 2013, 2014, 2019, 2020
4 * Inferno Nettverk A/S, Norway. 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 * 1. The above copyright notice, this list of conditions and the following
10 * disclaimer must appear in all copies of the software, derivative works
11 * or modified versions, and any portions thereof, aswell as in all
12 * supporting documentation.
13 * 2. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by
16 * Inferno Nettverk A/S, Norway.
17 * 3. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Inferno Nettverk A/S requests users of this software to return to
32 *
33 * Software Distribution Coordinator or sdc@inet.no
34 * Inferno Nettverk A/S
35 * Oslo Research Park
36 * Gaustadall�en 21
37 * NO-0349 Oslo
38 * Norway
39 *
40 * any improvements or extensions that they make and grant Inferno Nettverk A/S
41 * the rights to redistribute these changes.
42 *
43 */
44
45 #include "common.h"
46
47 static const char rcsid[] =
48 "$Id: method_uname.c,v 1.114.4.2.6.6 2020/11/11 17:02:28 karls Exp $";
49
50 static negotiate_result_t
51 recv_unamever(int s, request_t *request, negotiate_state_t *state);
52
53 static negotiate_result_t
54 recv_ulen(int s, request_t *request, negotiate_state_t *state);
55
56 static negotiate_result_t
57 recv_uname(int s, request_t *request, negotiate_state_t *state);
58
59 static negotiate_result_t
60 recv_plen(int s, request_t *request, negotiate_state_t *state);
61
62 static negotiate_result_t
63 recv_passwd(int s, request_t *request, negotiate_state_t *state);
64
65 static int
66 passworddbisunique(void);
67 /*
68 * If it's possible for us to fail username/password authentication
69 * on one rule, and succeed at another, returns false.
70 * Otherwise returns the unique authmethod that would be used.
71 */
72
73
74 negotiate_result_t
method_uname(s,request,state)75 method_uname(s, request, state)
76 int s;
77 request_t *request;
78 negotiate_state_t *state;
79
80 {
81
82 state->rcurrent = recv_unamever;
83 return state->rcurrent(s, request, state);
84 }
85
86 static int
passworddbisunique(void)87 passworddbisunique(void)
88 {
89 const char *function = "passworddbisunique()";
90 int rc;
91
92 if (methodisset(AUTHMETHOD_UNAME, sockscf.smethodv, sockscf.smethodc)) {
93 #if HAVE_PAM
94 if (methodisset(AUTHMETHOD_PAM_USERNAME,
95 sockscf.smethodv,
96 sockscf.smethodc))
97 rc = 0;
98 else
99 #endif /* HAVE_PAM */
100
101 #if HAVE_BSDAUTH
102 if (methodisset(AUTHMETHOD_BSDAUTH, sockscf.smethodv, sockscf.smethodc))
103 rc = 0;
104 else
105 #endif /* HAVE_BSDAUTH */
106
107 #if HAVE_LDAP
108 if (methodisset(AUTHMETHOD_LDAPAUTH, sockscf.smethodv, sockscf.smethodc))
109 rc = 0;
110 else
111 #endif /* HAVE_LDAP */
112 rc = AUTHMETHOD_UNAME;
113 }
114
115 #if HAVE_PAM
116 else if (methodisset(AUTHMETHOD_PAM_USERNAME,
117 sockscf.smethodv,
118 sockscf.smethodc)) {
119 if (*sockscf.state.pamservicename == NUL)
120 rc = 0;
121 else if (methodisset(AUTHMETHOD_UNAME,
122 sockscf.smethodv,
123 sockscf.smethodc))
124 rc = 0;
125 #if HAVE_BSDAUTH
126 else if (methodisset(AUTHMETHOD_BSDAUTH,
127 sockscf.smethodv,
128 sockscf.smethodc))
129 rc = 0;
130 #endif /* HAVE_BSDAUTH */
131 #if HAVE_LDAP
132 else if (methodisset(AUTHMETHOD_LDAPAUTH,
133 sockscf.smethodv,
134 sockscf.smethodc))
135 rc = 0;
136 #endif /* HAVE_LDAP */
137 else
138 rc = AUTHMETHOD_PAM_USERNAME;
139 }
140 #endif /* HAVE_PAM */
141
142 #if HAVE_BSDAUTH
143 else if (methodisset(AUTHMETHOD_BSDAUTH,
144 sockscf.smethodv,
145 sockscf.smethodc)) {
146 if (sockscf.state.bsdauthstylename == NULL)
147 rc = 0;
148 else if (methodisset(AUTHMETHOD_UNAME,
149 sockscf.smethodv,
150 sockscf.smethodc))
151 rc = 0;
152 #if HAVE_PAM
153 else if (methodisset(AUTHMETHOD_PAM_USERNAME,
154 sockscf.smethodv,
155 sockscf.smethodc))
156 rc = 0;
157 #endif /* HAVE_PAM */
158 #if HAVE_LDAP
159 else if (methodisset(AUTHMETHOD_LDAPAUTH,
160 sockscf.smethodv,
161 sockscf.smethodc))
162 rc = 0;
163 #endif /* HAVE_LDAP */
164 else
165 rc = AUTHMETHOD_BSDAUTH;
166 }
167 #endif /* HAVE_BSDAUTH */
168
169 #if HAVE_LDAP
170 else if (methodisset(AUTHMETHOD_LDAPAUTH,
171 sockscf.smethodv,
172 sockscf.smethodc)) {
173 if (sockscf.state.ldapauthentication.ldapurl == NULL)
174 rc = 0;
175 else if (methodisset(AUTHMETHOD_UNAME,
176 sockscf.smethodv,
177 sockscf.smethodc))
178 rc = 0;
179 #if HAVE_PAM
180 else if (methodisset(AUTHMETHOD_PAM_USERNAME,
181 sockscf.smethodv,
182 sockscf.smethodc))
183 rc = 0;
184 #endif /* HAVE_PAM */
185 #if HAVE_BSDAUTH
186 else if (methodisset(AUTHMETHOD_BSDAUTH,
187 sockscf.smethodv,
188 sockscf.smethodc))
189 rc = 0;
190 #endif /* HAVE_BSDAUTH */
191 else
192 rc = AUTHMETHOD_LDAPAUTH;
193 }
194 #endif /* HAVE_LDAP */
195 else {
196 slog(LOG_DEBUG, "%s: no password-based methods configured", function);
197 rc = 0;
198 }
199
200 slog(LOG_DEBUG, "%s: returning %d", function, rc);
201 return rc;
202 }
203
204 static negotiate_result_t
recv_unamever(s,request,state)205 recv_unamever(s, request, state)
206 int s;
207 request_t *request;
208 negotiate_state_t *state;
209 {
210 const char *function = "recv_unamever()";
211
212 INIT(sizeof(request->auth->mdata.uname.version));
213 CHECK(&request->auth->mdata.uname.version, request->auth, NULL);
214
215 switch (request->auth->mdata.uname.version) {
216 case SOCKS_UNAMEVERSION:
217 break;
218
219 default:
220 snprintf(state->emsg, sizeof(state->emsg),
221 "%s: unknown %s version on username packet from client: %d",
222 function,
223 proxyprotocol2string(request->version),
224 request->auth->mdata.uname.version);
225
226 return NEGOTIATE_ERROR;
227 }
228
229 state->rcurrent = recv_ulen;
230 return state->rcurrent(s, request, state);
231 }
232
233 static negotiate_result_t
recv_ulen(s,request,state)234 recv_ulen(s, request, state)
235 int s;
236 request_t *request;
237 negotiate_state_t *state;
238 {
239
240 INIT(sizeof(*request->auth->mdata.uname.name));
241 CHECK(request->auth->mdata.uname.name, request->auth, NULL);
242
243 /* LINTED conversion from 'int' may lose accuracy */
244 OCTETIFY(*request->auth->mdata.uname.name);
245
246 state->rcurrent = recv_uname;
247 return state->rcurrent(s, request, state);
248 }
249
250 static negotiate_result_t
recv_uname(s,request,state)251 recv_uname(s, request, state)
252 int s;
253 request_t *request;
254 negotiate_state_t *state;
255 {
256 /* in the protocol, first byte gives length. */
257 const size_t ulen = (size_t)*request->auth->mdata.uname.name;
258
259 INIT(ulen);
260 CHECK(request->auth->mdata.uname.name + 1, request->auth, NULL);
261
262 /* convert to string. */
263 memmove(request->auth->mdata.uname.name,
264 request->auth->mdata.uname.name + 1,
265 ulen);
266 request->auth->mdata.uname.name[ulen] = NUL;
267
268 state->rcurrent = recv_plen;
269 return state->rcurrent(s, request, state);
270 }
271
272 static negotiate_result_t
recv_plen(s,request,state)273 recv_plen(s, request, state)
274 int s;
275 request_t *request;
276 negotiate_state_t *state;
277 {
278
279 INIT(sizeof(*request->auth->mdata.uname.password));
280 CHECK(request->auth->mdata.uname.password, request->auth, NULL);
281
282 /* LINTED conversion from 'int' may lose accuracy */
283 OCTETIFY(*request->auth->mdata.uname.password);
284
285 state->rcurrent = recv_passwd;
286 return state->rcurrent(s, request, state);
287 }
288
289 static negotiate_result_t
recv_passwd(s,request,state)290 recv_passwd(s, request, state)
291 int s;
292 request_t *request;
293 negotiate_state_t *state;
294 {
295 /* const char *function = "recv_passwd()"; */
296 const size_t plen = (size_t)*request->auth->mdata.uname.password;
297 sendto_info_t sendtoflags;
298 unsigned char response[1 /* version. */ + 1 /* status. */];
299 int isunique;
300
301 INIT(plen);
302 CHECK(request->auth->mdata.uname.password + 1, request->auth, NULL);
303
304 /* convert to C string. */
305 memmove(request->auth->mdata.uname.password,
306 request->auth->mdata.uname.password + 1,
307 plen);
308 request->auth->mdata.uname.password[plen] = NUL;
309
310 /*
311 * Very sadly we can't always do checking of the username/password here
312 * since we don't know what authentication to use yet. It could
313 * be username, but it could also be PAM, or some future method.
314 * It depends on what the socks request is. We therefor would have
315 * liked to give the client success status back no matter what
316 * the username/password is, and later deny the connection if need be
317 * after we have gotten the request.
318 *
319 * That however creates problems with clients that, naturally, cache
320 * the wrong username/password if they get success.
321 * We therefor check if we have a unique passworddb to use, and if so,
322 * check the password here so we can return an immediate error to client.
323 * This we can do because if the passworddb is unique there is
324 * no chance of the result varying based to the client's request.
325 *
326 * If the database is not unique, we go with returning a success at
327 * this point, and deny it later if need be, even though this might
328 * create problems for the clients that cache the result.
329 */
330 response[UNAME_VERSION] = request->auth->mdata.uname.version;
331 switch ((isunique = passworddbisunique())) {
332 case 0:
333 /*
334 * not unique. Return ok now, and check correct db later,
335 * when we know what rules to use and what "correct" is.
336 */
337 response[UNAME_STATUS] = (unsigned char)UNAME_STATUS_ISOK;
338 break;
339
340 #if HAVE_PAM
341 case AUTHMETHOD_PAM_ANY:
342 case AUTHMETHOD_PAM_ADDRESS:
343 case AUTHMETHOD_PAM_USERNAME: {
344 /*
345 * it's a union, make a copy before moving into pam object.
346 */
347 const authmethod_uname_t uname = request->auth->mdata.uname;
348
349 request->auth->method = isunique;
350
351 STRCPY_ASSERTLEN(request->auth->mdata.pam.servicename,
352 sockscf.state.pamservicename);
353
354 STRCPY_ASSERTSIZE(request->auth->mdata.pam.name, uname.name);
355
356 STRCPY_ASSERTSIZE(request->auth->mdata.pam.password, uname.password);
357 break;
358 }
359 #endif /* HAVE_PAM */
360
361 #if HAVE_BSDAUTH
362 case AUTHMETHOD_BSDAUTH: {
363 /*
364 * it's a union, make a copy before moving into bsd object.
365 */
366 const authmethod_uname_t uname = request->auth->mdata.uname;
367
368 request->auth->method = AUTHMETHOD_BSDAUTH;
369 if (sockscf.state.bsdauthstylename != NULL)
370 STRCPY_ASSERTLEN(request->auth->mdata.bsd.style,
371 (const char *)sockscf.state.bsdauthstylename);
372 else
373 request->auth->mdata.bsd.style[0] = NUL;
374
375 STRCPY_ASSERTSIZE(request->auth->mdata.bsd.name, uname.name);
376
377 STRCPY_ASSERTSIZE(request->auth->mdata.bsd.password,
378 uname.password);
379 break;
380 }
381 #endif /* HAVE_BSDAUTH */
382
383 #if HAVE_LDAP
384 case AUTHMETHOD_LDAPAUTH: {
385 /*
386 * it's a union, make a copy before moving into ldap object.
387 */
388 const authmethod_uname_t uname = request->auth->mdata.uname;
389
390 request->auth->method = AUTHMETHOD_LDAPAUTH;
391
392 STRCPY_ASSERTSIZE(request->auth->mdata.ldap.name,
393 uname.name);
394
395 STRCPY_ASSERTSIZE(request->auth->mdata.ldap.password,
396 uname.password);
397
398 /*
399 * Use global LDAP settigs until we know what socks-rule
400 * the request will match.
401 */
402 request->auth->mdata.ldap.ldapauthentication
403 = sockscf.state.ldapauthentication;
404
405 break;
406 }
407 #endif /* HAVE_LDAP */
408
409 case AUTHMETHOD_UNAME:
410 break;
411
412 default:
413 SERRX(passworddbisunique());
414 }
415
416 if (isunique) {
417 struct sockaddr_storage src, dst;
418
419 sockshost2sockaddr(&state->src, &src);
420 sockshost2sockaddr(&state->dst, &dst);
421
422 if (accesscheck(s,
423 request->auth,
424 &src,
425 &dst,
426 state->emsg,
427 sizeof(state->emsg)))
428 response[UNAME_STATUS] = (unsigned char)UNAME_STATUS_ISOK;
429 else
430 response[UNAME_STATUS] = (unsigned char)UNAME_STATUS_ISNOK;
431 }
432
433 bzero(&sendtoflags, sizeof(sendtoflags));
434 sendtoflags.side = INTERNALIF;
435
436 if (socks_sendton(s,
437 response,
438 sizeof(response),
439 0,
440 0,
441 NULL,
442 0,
443 &sendtoflags,
444 request->auth) != sizeof(response))
445 return NEGOTIATE_ERROR;
446
447 if (response[UNAME_STATUS] == (unsigned char)UNAME_STATUS_ISOK) {
448 state->rcurrent = recv_sockspacket;
449
450 /* presumably client is awaiting our response. */
451 return NEGOTIATE_CONTINUE;
452 }
453
454 /* else; failed authentication. */
455 return NEGOTIATE_ERROR;
456 }
457