chiark / gitweb /
rename backlog_nextscan_periods to until_backlog_nextscan
[innduct.git] / authprogs / libauth.c
1 /*  $Id: libauth.c 7500 2006-03-20 01:52:44Z eagle $
2 **
3 **  Common code for authenticators and resolvers.
4 **
5 **  Collects common code to read information from nnrpd that should be done
6 **  the same for all authenticators, and common code to get information about
7 **  the incoming connection.
8 */
9
10 #include "config.h"
11 #include "clibrary.h"
12 #include "libinn.h"
13
14 #include "libauth.h"
15 #include "inn/messages.h"
16
17 #define NAMESTR "ClientAuthname: "
18 #define PASSSTR "ClientPassword: "
19
20 #define CLIHOST "ClientHost: "
21 #define CLIIP "ClientIP: "
22 #define CLIPORT "ClientPort: "
23 #define LOCIP "LocalIP: "
24 #define LOCPORT "LocalPort: "
25
26 #ifdef HAVE_INET6
27 # include <netdb.h>
28 #endif
29
30 /* Main loop.  If res != NULL, expects to get resolver info from nnrpd, and
31    writes it into the struct.  If auth != NULL, expects to get authentication
32    info from nnrpd, and writes it into the struct. */
33
34 static bool
35 get_connection_info(FILE *stream, struct res_info *res, struct auth_info *auth)
36 {
37     char buff[SMBUF];
38     size_t length;
39     char *cip = NULL, *sip = NULL, *cport = NULL, *sport = NULL;
40 #ifdef HAVE_INET6
41     struct addrinfo *r, hints;
42 #else
43     struct sockaddr_in *loc_sin, *cli_sin;
44 #endif
45
46     /* Zero fields first (anything remaining NULL after is missing data) */
47     if (res != NULL) {
48         res->clienthostname = NULL;
49         res->client = NULL;
50         res->local = NULL;
51     }
52     if (auth != NULL) {
53         auth->username = NULL;
54         auth->password = NULL;
55     }
56
57     /* Read input from nnrpd a line at a time, stripping \r\n. */
58     while (fgets(buff, sizeof(buff), stream) != NULL) {
59         length = strlen(buff);
60         if (length == 0 || buff[length - 1] != '\n')
61             goto error;
62         buff[length - 1] = '\0';
63         if (length > 1 && buff[length - 2] == '\r')
64             buff[length - 2] = '\0';
65
66         /* Parse */
67         if (strncmp(buff, ".", 2) == 0)
68             break;
69         else if (auth != NULL && strncmp(buff, NAMESTR, strlen(NAMESTR)) == 0)
70             auth->username = xstrdup(buff + strlen(NAMESTR));
71         else if (auth != NULL && strncmp(buff, PASSSTR, strlen(PASSSTR)) == 0)
72             auth->password = xstrdup(buff + strlen(PASSSTR));
73         else if (res != NULL && strncmp(buff, CLIHOST, strlen(CLIHOST)) == 0)
74             res->clienthostname = xstrdup(buff + strlen(CLIHOST));
75         else if (res != NULL && strncmp(buff, CLIIP, strlen(CLIIP)) == 0)
76             cip = xstrdup(buff + strlen(CLIIP));
77         else if (res != NULL && strncmp(buff, CLIPORT, strlen(CLIPORT)) == 0)
78             cport = xstrdup(buff + strlen(CLIPORT));
79         else if (res != NULL && strncmp(buff, LOCIP, strlen(LOCIP)) == 0)
80             sip = xstrdup(buff + strlen(LOCIP));
81         else if (res != NULL && strncmp(buff, LOCPORT, strlen(LOCPORT)) == 0)
82             sport = xstrdup(buff + strlen(LOCPORT));
83         else {
84             /**** We just ignore excess fields for now ****/
85
86             /* warn("libauth: unexpected data from nnrpd: \"%s\"", buff); */
87             /* goto error; */
88         }
89     }
90
91     /* If some field is missing, free the rest and error out. */
92     if (auth != NULL && (auth->username == NULL || auth->password == NULL)) {
93         warn("libauth: requested authenticator data not sent by nnrpd");
94         goto error;
95     }
96     if (res != NULL && (res->clienthostname == NULL || cip == NULL ||
97                 cport == NULL || sip == NULL || sport == NULL)) {
98         warn("libauth: requested resolver data not sent by nnrpd");
99         goto error;
100     }
101
102     /* Generate sockaddrs from IP and port strings */
103     if (res != NULL) {
104 #ifdef HAVE_INET6
105         /* sockaddr_in6 may be overkill for PF_INET case, but oh well */
106         res->client = xcalloc(1, sizeof(struct sockaddr_in6));
107         res->local = xcalloc(1, sizeof(struct sockaddr_in6));
108
109         memset( &hints, 0, sizeof( hints ) );
110         hints.ai_flags = AI_NUMERICHOST;
111         hints.ai_socktype = SOCK_STREAM;
112
113         hints.ai_family = strchr( cip, ':' ) != NULL ? PF_INET6 : PF_INET;
114         if( getaddrinfo( cip, cport, &hints, &r ) != 0)
115             goto error;
116         if( r->ai_addrlen > sizeof(struct sockaddr_in6) )
117             goto error;
118         memcpy( res->client, r->ai_addr, r->ai_addrlen );
119         freeaddrinfo( r );
120
121         hints.ai_family = strchr( sip, ':' ) != NULL ? PF_INET6 : PF_INET;
122         if( getaddrinfo( sip, sport, &hints, &r ) != 0)
123             goto error;
124         if( r->ai_addrlen > sizeof(struct sockaddr_in6) )
125             goto error;
126         memcpy( res->local, r->ai_addr, r->ai_addrlen );
127         freeaddrinfo( r );
128 #else
129         res->client = xcalloc(1, sizeof(struct sockaddr_in));
130         res->local = xcalloc(1, sizeof(struct sockaddr_in));
131
132         cli_sin = (struct sockaddr_in *)(res->client);
133         loc_sin = (struct sockaddr_in *)(res->local);
134         cli_sin->sin_family = AF_INET;
135         if (!inet_aton(cip, &cli_sin->sin_addr))
136             goto error;
137         cli_sin->sin_port = htons( atoi(cport) );
138
139         loc_sin->sin_family = AF_INET;
140         if (!inet_aton(sip, &loc_sin->sin_addr))
141             goto error;
142         loc_sin->sin_port = htons( atoi(sport) );
143
144 # ifdef HAVE_SOCKADDR_LEN
145         cli_sin->sin_len = sizeof(struct sockaddr_in);
146         loc_sin->sin_len = sizeof(struct sockaddr_in);
147 # endif
148 #endif
149
150         free(sip);
151         free(sport);
152         free(cip);
153         free(cport);
154     }
155
156     return true;
157
158 error:
159     if (auth != NULL && auth->username != NULL)     free(auth->username);
160     if (auth != NULL && auth->password != NULL)     free(auth->password);
161     if (res != NULL && res->clienthostname != NULL) free(res->clienthostname);
162     if (res != NULL && res->client != NULL)         free(res->client);
163     if (res != NULL && res->local != NULL)          free(res->local);
164     if (sip != NULL)                                free(sip);
165     if (sport != NULL)                              free(sport);
166     if (cip != NULL)                                free(cip);
167     if (cport != NULL)                              free(cport);
168     return false;
169 }
170
171
172 /* Wrappers to read information from nnrpd, returning an allocated struct on
173    success. */
174
175 struct res_info *
176 get_res_info(FILE *stream) {
177     struct res_info *res = xmalloc(sizeof(struct res_info));
178
179     if(get_connection_info(stream, res, NULL))
180         return res;
181
182     free(res);
183     return NULL;
184 }
185
186
187 struct auth_info *
188 get_auth_info(FILE *stream) {
189     struct auth_info *auth = xmalloc(sizeof(struct auth_info));
190
191     if(get_connection_info(stream, NULL, auth))
192         return auth;
193
194     free(auth);
195     return NULL;
196 }
197
198 void
199 free_res_info(struct res_info *res) {
200     if(res == NULL)
201         return;
202     if(res->client != NULL)             free(res->client);
203     if(res->local != NULL)              free(res->local);
204     if(res->clienthostname != NULL)     free(res->clienthostname);
205     free(res);
206 }
207
208 void
209 free_auth_info(struct auth_info *auth) {
210     if(auth == NULL)
211         return;
212     if(auth->username != NULL)          free(auth->username);
213     if(auth->password != NULL)          free(auth->password);
214     free(auth);
215 }
216