/* $Id: libauth.c 7500 2006-03-20 01:52:44Z eagle $
**
** Common code for authenticators and resolvers.
**
** Collects common code to read information from nnrpd that should be done
** the same for all authenticators, and common code to get information about
** the incoming connection.
*/
#include "config.h"
#include "clibrary.h"
#include "libinn.h"
#include "libauth.h"
#include "inn/messages.h"
#define NAMESTR "ClientAuthname: "
#define PASSSTR "ClientPassword: "
#define CLIHOST "ClientHost: "
#define CLIIP "ClientIP: "
#define CLIPORT "ClientPort: "
#define LOCIP "LocalIP: "
#define LOCPORT "LocalPort: "
#ifdef HAVE_INET6
# include <netdb.h>
#endif
/* Main loop. If res != NULL, expects to get resolver info from nnrpd, and
writes it into the struct. If auth != NULL, expects to get authentication
info from nnrpd, and writes it into the struct. */
static bool
get_connection_info(FILE *stream, struct res_info *res, struct auth_info *auth)
{
char buff[SMBUF];
size_t length;
char *cip = NULL, *sip = NULL, *cport = NULL, *sport = NULL;
#ifdef HAVE_INET6
struct addrinfo *r, hints;
#else
struct sockaddr_in *loc_sin, *cli_sin;
#endif
/* Zero fields first (anything remaining NULL after is missing data) */
if (res != NULL) {
res->clienthostname = NULL;
res->client = NULL;
res->local = NULL;
}
if (auth != NULL) {
auth->username = NULL;
auth->password = NULL;
}
/* Read input from nnrpd a line at a time, stripping \r\n. */
while (fgets(buff, sizeof(buff), stream) != NULL) {
length = strlen(buff);
if (length == 0 || buff[length - 1] != '\n')
goto error;
buff[length - 1] = '\0';
if (length > 1 && buff[length - 2] == '\r')
buff[length - 2] = '\0';
/* Parse */
if (strncmp(buff, ".", 2) == 0)
break;
else if (auth != NULL && strncmp(buff, NAMESTR, strlen(NAMESTR)) == 0)
auth->username = xstrdup(buff + strlen(NAMESTR));
else if (auth != NULL && strncmp(buff, PASSSTR, strlen(PASSSTR)) == 0)
auth->password = xstrdup(buff + strlen(PASSSTR));
else if (res != NULL && strncmp(buff, CLIHOST, strlen(CLIHOST)) == 0)
res->clienthostname = xstrdup(buff + strlen(CLIHOST));
else if (res != NULL && strncmp(buff, CLIIP, strlen(CLIIP)) == 0)
cip = xstrdup(buff + strlen(CLIIP));
else if (res != NULL && strncmp(buff, CLIPORT, strlen(CLIPORT)) == 0)
cport = xstrdup(buff + strlen(CLIPORT));
else if (res != NULL && strncmp(buff, LOCIP, strlen(LOCIP)) == 0)
sip = xstrdup(buff + strlen(LOCIP));
else if (res != NULL && strncmp(buff, LOCPORT, strlen(LOCPORT)) == 0)
sport = xstrdup(buff + strlen(LOCPORT));
else {
/**** We just ignore excess fields for now ****/
/* warn("libauth: unexpected data from nnrpd: \"%s\"", buff); */
/* goto error; */
}
}
/* If some field is missing, free the rest and error out. */
if (auth != NULL && (auth->username == NULL || auth->password == NULL)) {
warn("libauth: requested authenticator data not sent by nnrpd");
goto error;
}
if (res != NULL && (res->clienthostname == NULL || cip == NULL ||
cport == NULL || sip == NULL || sport == NULL)) {
warn("libauth: requested resolver data not sent by nnrpd");
goto error;
}
/* Generate sockaddrs from IP and port strings */
if (res != NULL) {
#ifdef HAVE_INET6
/* sockaddr_in6 may be overkill for PF_INET case, but oh well */
res->client = xcalloc(1, sizeof(struct sockaddr_in6));
res->local = xcalloc(1, sizeof(struct sockaddr_in6));
memset( &hints, 0, sizeof( hints ) );
hints.ai_flags = AI_NUMERICHOST;
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = strchr( cip, ':' ) != NULL ? PF_INET6 : PF_INET;
if( getaddrinfo( cip, cport, &hints, &r ) != 0)
goto error;
if( r->ai_addrlen > sizeof(struct sockaddr_in6) )
goto error;
memcpy( res->client, r->ai_addr, r->ai_addrlen );
freeaddrinfo( r );
hints.ai_family = strchr( sip, ':' ) != NULL ? PF_INET6 : PF_INET;
if( getaddrinfo( sip, sport, &hints, &r ) != 0)
goto error;
if( r->ai_addrlen > sizeof(struct sockaddr_in6) )
goto error;
memcpy( res->local, r->ai_addr, r->ai_addrlen );
freeaddrinfo( r );
#else
res->client = xcalloc(1, sizeof(struct sockaddr_in));
res->local = xcalloc(1, sizeof(struct sockaddr_in));
cli_sin = (struct sockaddr_in *)(res->client);
loc_sin = (struct sockaddr_in *)(res->local);
cli_sin->sin_family = AF_INET;
if (!inet_aton(cip, &cli_sin->sin_addr))
goto error;
cli_sin->sin_port = htons( atoi(cport) );
loc_sin->sin_family = AF_INET;
if (!inet_aton(sip, &loc_sin->sin_addr))
goto error;
loc_sin->sin_port = htons( atoi(sport) );
# ifdef HAVE_SOCKADDR_LEN
cli_sin->sin_len = sizeof(struct sockaddr_in);
loc_sin->sin_len = sizeof(struct sockaddr_in);
# endif
#endif
free(sip);
free(sport);
free(cip);
free(cport);
}
return true;
error:
if (auth != NULL && auth->username != NULL) free(auth->username);
if (auth != NULL && auth->password != NULL) free(auth->password);
if (res != NULL && res->clienthostname != NULL) free(res->clienthostname);
if (res != NULL && res->client != NULL) free(res->client);
if (res != NULL && res->local != NULL) free(res->local);
if (sip != NULL) free(sip);
if (sport != NULL) free(sport);
if (cip != NULL) free(cip);
if (cport != NULL) free(cport);
return false;
}
/* Wrappers to read information from nnrpd, returning an allocated struct on
success. */
struct res_info *
get_res_info(FILE *stream) {
struct res_info *res = xmalloc(sizeof(struct res_info));
if(get_connection_info(stream, res, NULL))
return res;
free(res);
return NULL;
}
struct auth_info *
get_auth_info(FILE *stream) {
struct auth_info *auth = xmalloc(sizeof(struct auth_info));
if(get_connection_info(stream, NULL, auth))
return auth;
free(auth);
return NULL;
}
void
free_res_info(struct res_info *res) {
if(res == NULL)
return;
if(res->client != NULL) free(res->client);
if(res->local != NULL) free(res->local);
if(res->clienthostname != NULL) free(res->clienthostname);
free(res);
}
void
free_auth_info(struct auth_info *auth) {
if(auth == NULL)
return;
if(auth->username != NULL) free(auth->username);
if(auth->password != NULL) free(auth->password);
free(auth);
}
syntax highlighted by Code2HTML, v. 0.9.1