1 /*
2    ident.c
3 
4    This file is part of GNU Anubis.
5    Copyright (C) 2001-2014 The Anubis Team.
6 
7    GNU Anubis is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by the
9    Free Software Foundation; either version 3 of the License, or (at your
10    option) any later version.
11 
12    GNU Anubis is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License along
18    with GNU Anubis.  If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include "headers.h"
22 #include "extern.h"
23 
24 /***********************
25  IDENT protocol support
26 ************************/
27 
28 #define USERNAME_C "USERID :"
29 
30 /* If the reply matches sscanf expression
31 
32       "%*[^:]: USERID :%*[^:]:%s"
33 
34    and the length of "%s" part does not exceed size-1 bytes,
35    copies this part to USERNAME and returns 0. Otherwise,
36    returns 1 */
37 
38 static int
ident_extract_username(char * reply,char ** pusername)39 ident_extract_username (char *reply, char **pusername)
40 {
41   char *p;
42 
43   p = strchr (reply, ':');
44   if (!p)
45     return 1;
46   if (p[1] != ' ' || strncmp (p + 2, USERNAME_C, sizeof (USERNAME_C) - 1))
47     return 1;
48   p += 2 + sizeof (USERNAME_C) - 1;
49   p = strchr (p, ':');
50   if (!p)
51     return 1;
52   do
53     p++;
54   while (*p == ' ');
55   assign_string (pusername, p);
56   return 0;
57 }
58 
59 /* If the reply matches sscanf expression
60 
61       "%*[^ ] %*[^ ] %*[^ ] %*[^ ] %*[^ ] %s"
62 
63    and the length of "%s" part does not exceed size-1 bytes,
64    copies this part to USERNAME and returns 0. Otherwise,
65    returns 1 */
66 
67 static int
crypt_extract_username(char * reply,char ** pusername)68 crypt_extract_username (char *reply, char **pusername)
69 {
70   int i;
71   char *p = reply;
72 #define skip_word(c) while (*c && (*c) != ' ') c++
73 
74   /* Skip five words */
75   for (i = 0; i < 5; i++)
76     {
77       skip_word (p);
78       if (!*p++)
79 	return 1;
80     }
81 
82   assign_string (pusername, p);
83   return 0;
84 }
85 
86 int
auth_ident(struct sockaddr_in * addr,char ** user)87 auth_ident (struct sockaddr_in *addr, char **user)
88 {
89   struct servent *sp;
90   struct sockaddr_in ident;
91   char *buf = NULL;
92   char inetd_buf[LINEBUFFER];
93   size_t size = 0;
94   int sd = 0;
95   int rc;
96   NET_STREAM str;
97   size_t nbytes;
98 
99   if ((sd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
100     {
101       anubis_error (0, errno, _("IDENT: socket() failed"));
102       return 0;
103     }
104   memcpy (&ident, addr, sizeof (ident));
105   sp = getservbyname ("auth", "tcp");
106   if (sp)
107     ident.sin_port = sp->s_port;
108   else
109     ident.sin_port = htons (113);	/* default IDENT port number */
110 
111   if (connect (sd, (struct sockaddr *) &ident, sizeof (ident)) < 0)
112     {
113       anubis_error (0, errno, _("IDENT: connect() failed"));
114       close_socket (sd);
115       return 0;
116     }
117   net_create_stream (&str, sd);
118 
119   info (VERBOSE, _("IDENT: connected to %s:%u"),
120 	inet_ntoa (ident.sin_addr), ntohs (ident.sin_port));
121 
122   snprintf (inetd_buf, sizeof inetd_buf,
123 	    "%u , %u" CRLF, ntohs (addr->sin_port), session.anubis_port);
124 
125   if ((rc = stream_write (str, inetd_buf, strlen (inetd_buf), &nbytes)))
126     {
127       anubis_error (0, 0,
128 		    _("IDENT: stream_write() failed: %s."),
129 		    stream_strerror (str, rc));
130       net_close_stream (&str);
131       return 0;
132     }
133   if (recvline (CLIENT, str, &buf, &size) == 0)
134     {
135       anubis_error (0, 0,
136 		    _("IDENT: recvline() failed: %s."),
137 		    stream_strerror (str, rc));
138       net_close_stream (&str);
139       return 0;
140     }
141   net_close_stream (&str);
142 
143   remcrlf (buf);
144   if (ident_extract_username (buf, user))
145     {
146       info (VERBOSE, _("IDENT: incorrect data."));
147       free (buf);
148       return 0;
149     }
150   free (buf);
151 
152   /******************************
153    IDENTD DES decryption support
154   *******************************/
155 
156   if (strstr (*user, "[") && strstr (*user, "]"))
157     {
158       int rs = 0;
159       info (VERBOSE, _("IDENT: data probably encrypted with DES..."));
160       external_program (&rs, IDECRYPT_PATH, *user, buf, LINEBUFFER);
161       if (rs == -1)
162 	return 0;
163 
164       remcrlf (buf);
165       if (crypt_extract_username (buf, user))
166 	{
167 	  info (VERBOSE, _("IDENT: incorrect data (DES deciphered)."));
168 	  return 0;
169 	}
170       else
171 	{			/* UID deciphered */
172 	  if (ntohl (ident.sin_addr.s_addr) == INADDR_LOOPBACK)
173 	    {
174 	      struct passwd *pwd;
175 	      int uid = atoi (*user);
176 	      pwd = getpwuid (uid);
177 	      if (pwd != 0)
178 		assign_string (user, pwd->pw_name);
179 	      else
180 		return 0;
181 	    }
182 	}
183     }
184 
185   info (VERBOSE, _("IDENT: resolved remote user to %s."), *user);
186   return 1;			/* success */
187 }
188 
189 /* EOF */
190