chiark / gitweb /
xfoo => mfoo, rename
[innduct.git] / authprogs / ident.c
1 /*  $Id: ident.c 6135 2003-01-19 01:15:40Z rra $
2 **
3 **  Ident authenticator.
4 */
5
6 #include "config.h"
7 #include "clibrary.h"
8 #include <errno.h>
9 #include <netdb.h>
10 #include <signal.h>
11 #include <syslog.h>
12
13 #include "inn/messages.h"
14 #include "libinn.h"
15
16 #include "libauth.h"
17
18 #define IDENT_PORT 113
19
20 static void out(int sig UNUSED) {
21     exit(1);
22 }
23
24 int main(int argc, char *argv[])
25 {
26     struct servent *s;
27     char buf[2048];
28     struct res_info *res;
29     struct sockaddr_in *lsin, *csin;
30 #ifdef HAVE_INET6
31     struct sockaddr_storage *lss;
32     struct sockaddr_in6 *lsin6, *csin6;
33 #endif
34     int sock;
35     int opt;
36     int truncate_domain = 0;
37     char *iter;
38     char *p;
39     unsigned int got;
40     int lport, cport, identport;
41     char *endstr;
42
43     message_program_name = "ident";
44
45     xsignal_norestart(SIGALRM,out);
46     alarm(15);
47
48     s = getservbyname("ident", "tcp");
49     if (!s)
50         identport = IDENT_PORT;
51     else
52         identport = ntohs(s->s_port);
53
54     while ((opt = getopt(argc, argv, "p:t")) != -1) {
55         switch (opt) {
56           case 'p':
57             for (iter = optarg; *iter; iter++)
58                 if (*iter < '0' || *iter > '9')
59                     break;
60             if (*iter) {
61                 /* not entirely numeric */
62                 s = getservbyname(optarg, "tcp");
63                 if (s == NULL)
64                     die("cannot getsrvbyname(%s, tcp)", optarg);
65                 identport = s->s_port;
66             } else
67                 identport = atoi(optarg);
68             break;
69         case 't':
70             truncate_domain = 1;
71             break;
72         }
73     }
74
75     /* read the connection info from stdin */
76     res = get_res_info(stdin);
77     if (res == NULL)
78         die("did not get client information from nnrpd");
79
80 #ifdef HAVE_INET6
81     lss = (struct sockaddr_storage *)(res->local);
82     lsin6 = (struct sockaddr_in6 *)(res->local);
83     csin6 = (struct sockaddr_in6 *)(res->client);
84     if( lss->ss_family == AF_INET6 )
85     {
86         lport = ntohs( lsin6->sin6_port );
87         lsin6->sin6_port = 0;
88         cport = ntohs( csin6->sin6_port );
89         csin6->sin6_port = htons( identport );
90         sock = socket(PF_INET6, SOCK_STREAM, 0);
91     } else
92 #endif
93     {
94         lsin = (struct sockaddr_in *)(res->local);
95         lport = htons( lsin->sin_port );
96         lsin->sin_port = 0;
97         csin = (struct sockaddr_in *)(res->client);
98         cport = htons( csin->sin_port );
99         csin->sin_port = htons( identport );
100         sock = socket(PF_INET, SOCK_STREAM, 0);
101     }
102     if (sock < 0)
103         sysdie("cannot create socket");
104     if (bind(sock, res->local, SA_LEN(res->local)) < 0)
105         sysdie("cannot bind socket");
106     if (connect(sock, res->client, SA_LEN(res->local)) < 0) {
107         if (errno != ECONNREFUSED)
108             sysdie("cannot connect to ident server");
109         else
110             sysdie("client host does not accept ident connections");
111     }
112     free_res_info(res);
113
114     /* send the request out */
115     snprintf(buf, sizeof(buf), "%d , %d\r\n", cport, lport);
116     opt = xwrite(sock, buf, strlen(buf));
117     if (opt < 0)
118         sysdie("cannot write to ident server");
119
120     /* get the answer back */
121     got = 0;
122     do {
123         opt = read(sock, buf+got, sizeof(buf)-got);
124         if (opt < 0)
125             sysdie("cannot read from ident server");
126         else if (!opt)
127             die("end of file from ident server before response");
128         while (opt--)
129             if (buf[got] != '\n')
130                 got++;
131     } while (buf[got] != '\n');
132     buf[got] = '\0';
133     if (buf[got-1] == '\r')
134         buf[got-1] = '\0';
135
136     /* buf now contains the entire ident response. */
137     if (!(iter = strchr(buf, ':')))
138         /* malformed response */
139         die("malformed response \"%s\" from ident server", buf);
140     iter++;
141
142     while (*iter && ISWHITE(*iter))
143         iter++;
144     endstr = iter;
145     while (*endstr && *endstr != ':' && !ISWHITE(*endstr))
146         endstr++;
147     if (!*endstr)
148         /* malformed response */
149         die("malformed response \"%s\" from ident server", buf);
150     if (*endstr != ':') {
151         *endstr++ = '\0';
152         while (*endstr != ':')
153             endstr++;
154     }
155
156     *endstr = '\0';
157
158     if (strcmp(iter, "ERROR") == 0)
159         die("ident server reported an error");
160     else if (strcmp(iter, "USERID") != 0)
161         die("ident server returned \"%s\", not USERID", iter);
162
163     /* skip the operating system */
164     if (!(iter = strchr(endstr+1, ':')))
165         exit(1);
166
167     /* everything else is username */
168     iter++;
169     while (*iter && ISWHITE(*iter))
170         iter++;
171     if (!*iter || *iter == '[')
172         /* null, or encrypted response */
173         die("ident response is null or encrypted");
174     if ((truncate_domain == 1) && ((p = strchr(iter, '@')) != NULL))
175         *p = '\0';
176     printf("User:%s\n", iter);
177
178     exit(0);
179 }