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