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