From: mdw Date: Mon, 4 Oct 1999 21:41:58 +0000 (+0000) Subject: Added ident client from `fw'. X-Git-Tag: 2.0.4~235 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/mLib/commitdiff_plain/7bd2091eeaab7a8e5b1bc57ae6bd71a51bf306e7?hp=a759efa6dcc67b035726a4428157c35627653966 Added ident client from `fw'. --- diff --git a/ident.c b/ident.c new file mode 100644 index 0000000..342dc81 --- /dev/null +++ b/ident.c @@ -0,0 +1,373 @@ +/* -*-c-*- + * + * $Id: ident.c,v 1.1 1999/10/04 21:41:58 mdw Exp $ + * + * Nonblocking RFC931 client + * + * (c) 1999 Mark Wooding + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of the mLib utilities library. + * + * mLib is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * mLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with mLib; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/*----- Revision history --------------------------------------------------* + * + * $Log: ident.c,v $ + * Revision 1.1 1999/10/04 21:41:58 mdw + * Added ident client from `fw'. + * + */ + +/*----- Header files ------------------------------------------------------*/ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "conn.h" +#include "dstr.h" +#include "exc.h" +#include "ident.h" +#include "selbuf.h" + +/*----- Main code ---------------------------------------------------------*/ + +/* --- @next@ --- * + * + * Arguments: @char **pp@ = address of string pointer + * + * Returns: Address of next token. + * + * Use: Reads the next token from the result string. Tokens are + * terminated by whitespace, or `:' or `,' characters. The + * result string has had `\' escapes removed; it's stored in + * the same memory as the input string. The actual content + * of the delimiter doesn't seem to be interesting, so it + * gets thrown away. + */ + +static char *next(char **pp) +{ + char *p, *q, *r; + + /* --- Deal with reads past the end of the string --- */ + + if (!*pp) + return (""); + + /* --- Initialize various pointers into the string --- */ + + p = q = r = *pp; + + /* --- Skip past any leading whitespace --- */ + + while (isspace((unsigned char)*p)) + p++; + + /* --- Now start work on the string itself --- */ + + for (;;) { + if (*p == 0 || *p == ':' || *p == ',' || isspace((unsigned char)*p)) + break; + else if (*p == '\\') { + p++; + if (!*p) { + *q++ = '\\'; + break; + } + } + *q++ = *p++; + } + + /* --- Tidy up afterwards --- */ + + while (isspace((unsigned char)*p)) + p++; + if (*p == 0) + *pp = 0; + else if (*p == ':' || *p == ',') + *pp = p + 1; + else + *pp = p; + *q = 0; + + return (r); +} + +/* --- @parse@ --- * + * + * Arguments: @char *p@ = pointer to input string from identd + * @ident_reply *i@ = pointer to output block + * + * Returns: --- + * + * Use: Parses a result string from an RFC931 (identd) server. + */ + +static void parse(char *p, ident_reply *i) +{ + char *q; + + /* --- Read the source and destination port numbers --- */ + + i->sport = atoi(next(&p)); + i->dport = atoi(next(&p)); + + /* --- Find out what sort of a reply this is --- */ + + q = next(&p); + if (strcmp(q, "USERID") == 0) { + i->type = IDENT_USERID; + i->u.userid.os = next(&p); + i->u.userid.user = next(&p); + } else if (strcmp(q, "ERROR") == 0) { + i->type = IDENT_ERROR; + i->u.error = next(&p); + } else + i->type = IDENT_BAD; +} + +/* --- @line@ --- * + * + * Arguments: @char *s@ = pointer to string from ident server + * @void *p@ = pointer to my request block + * + * Returns: --- + * + * Use: Handles a string from an ident server. + */ + +static void line(char *s, void *p) +{ + ident_request *rq = p; + + rq->state = IDENT_DONE; + selbuf_disable(&rq->b); + close(rq->b.reader.fd); + if (!s) + rq->func(0, rq->p); + else { + ident_reply i; + parse(s, &i); + rq->func(&i, rq->p); + } +} + +/* --- @connected@ --- * + * + * Arguments: @int fd@ = file descriptor + * @void *p@ = pointer to request block + * + * Returns: --- + * + * Use: Handles a connection to a remote ident server. + */ + +static void connected(int fd, void *p) +{ + ident_request *rq = p; + dstr d = DSTR_INIT; + + /* --- Handle an error during the connect --- */ + + if (fd < 0) + goto fail_0; + + /* --- Initialize the string to send to the remote host --- */ + + TRY { + dstr_putf(&d, "%u, %u\r\n", + ntohs(rq->remote.sin_port), ntohs(rq->local.sin_port)); + } CATCH switch (exc_type) { + case EXC_NOMEM: + EXIT_TRY; + goto fail_1; + default: + RETHROW; + } END_TRY; + + /* --- Do the rest of the work --- */ + + if (write(fd, d.buf, d.len) < d.len) + goto fail_1; + dstr_destroy(&d); + rq->state = IDENT_READ; + selbuf_init(&rq->b, rq->s, fd, line, rq); + return; + + /* --- Tidy up after misfortunes --- */ + +fail_1: + dstr_destroy(&d); + close(fd); +fail_0: + rq->state = IDENT_DONE; + rq->func(0, rq->p); +} + +/* --- @ident_abort@ --- * + * + * Arguments: @ident_request *rq@ = pointer to request block + * + * Returns: --- + * + * Use: Cancels an ident request in progress. + */ + +void ident_abort(ident_request *rq) +{ + switch (rq->state) { + case IDENT_CONN: + conn_kill(&rq->c); + break; + case IDENT_READ: + selbuf_disable(&rq->b); + close(rq->b.reader.fd); + break; + } +} + +/* --- @go@ --- * + * + * Arguments: @ident_request *rq@ = pointer to request block + * + * Returns: --- + * + * Use: Starts a connection to the remote ident server. + */ + +static void go(ident_request *rq) +{ + int fd; + struct sockaddr_in sin; + int opt; + + /* --- Create the socket I'll use --- */ + + if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) + goto fail_0; + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = 0; + sin.sin_addr = rq->local.sin_addr; + if (bind(fd, (struct sockaddr *)&sin, sizeof(sin))) + goto fail_1; + + /* --- Out-of-band data would confuse us --- */ + + opt = 1; + setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt)); + + /* --- Start a connection to the remote server --- */ + + sin.sin_family = AF_INET; + sin.sin_port = htons(113); + sin.sin_addr = rq->remote.sin_addr; + conn_init(&rq->c, rq->s, fd, (struct sockaddr *)&sin, sizeof(sin), + connected, rq); + + /* --- Finish off initializing the block --- */ + + rq->state = IDENT_CONN; + return; + + /* --- Tidy up after lossage --- */ + +fail_1: + close(fd); +fail_0: + rq->state = IDENT_DONE; + rq->func(0, rq->p); +} + +/* --- @ident@ --- * + * + * Arguments: @ident_request *rq@ = pointer to request block + * @sel_state *s@ = I/O multiplexor + * @const struct sockaddr_in *local, *remote@ = addresses + * @void (*func)(ident_reply *i, void *p)@ = handler function + * @void *p@ = argument for handler + * + * Returns: --- + * + * Use: Initializes an ident request. + */ + +void ident(ident_request *rq, sel_state *s, + const struct sockaddr_in *local, + const struct sockaddr_in *remote, + void (*func)(ident_reply */*i*/, void */*p*/), + void *p) +{ + memcpy(&rq->local, local, sizeof(rq->local)); + memcpy(&rq->remote, remote, sizeof(rq->remote)); + rq->func = func; + rq->p = p; + rq->s = s; + go(rq); +} + +/* --- @ident_socket@ --- * + * + * Arguments: @ident_request *rq@ = pointer to request block + * @sel_state *s@ = I/O multiplexor + * @int sk@ = connected socket file descriptor + * @void (*func)(ident_reply *i, void *p)@ = handler function + * @void *p@ = argument for handler + * + * Returns: --- + * + * Use: An alternative interface to @ident@. Initializes an ident + * request from a connected socket, rather than from an explicit + * address. This will call @getsockname@ and @getpeername@ to + * find out what the socket is actually connected to, which adds + * convenience but wastes time. + */ + +void ident_socket(ident_request *rq, sel_state *s, int sk, + void (*func)(ident_reply */*i*/, void */*p*/), + void *p) +{ + int sinsz; + if ((sinsz = sizeof(struct sockaddr_in), + getsockname(sk, (struct sockaddr *)&rq->local, &sinsz)) || + (sinsz = sizeof(struct sockaddr_in), + getpeername(sk, (struct sockaddr *)&rq->remote, &sinsz))) { + rq->state = IDENT_DONE; + func(0, p); + return; + } + + rq->func = func; + rq->p = p; + rq->s = s; + go(rq); +} + +/*----- That's all, folks -------------------------------------------------*/ diff --git a/ident.h b/ident.h new file mode 100644 index 0000000..073855b --- /dev/null +++ b/ident.h @@ -0,0 +1,165 @@ +/* -*-c-*- + * + * $Id: ident.h,v 1.1 1999/10/04 21:41:58 mdw Exp $ + * + * Nonblocking RFC931 client + * + * (c) 1999 Mark Wooding + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of the mLib utilities library. + * + * mLib is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * mLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with mLib; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/*----- Revision history --------------------------------------------------* + * + * $Log: ident.h,v $ + * Revision 1.1 1999/10/04 21:41:58 mdw + * Added ident client from `fw'. + * + */ + +#ifndef IDENT_H +#define IDENT_H + +#ifdef __cplusplus + extern "C" { +#endif + +/*----- Header files ------------------------------------------------------*/ + +#include +#include +#include +#include + +#ifndef CONN_H +# include "conn.h" +#endif + +#ifndef SEL_H +# include "sel.h" +#endif + +#ifndef SELBUF_H +# include "selbuf.h" +#endif + +/*----- Data structures ---------------------------------------------------*/ + +/* --- Parsed response from ident server --- */ + +typedef struct ident_reply { + unsigned short sport, dport; /* Source and destination ports */ + unsigned type; /* Type of reply from server */ + union { + struct { + char *os; /* Operating system name */ + char *user; /* User name */ + } userid; + char *error; /* Error message from server */ + } u; +} ident_reply; + +/* --- Response type codes --- */ + +enum { + IDENT_USERID, + IDENT_ERROR, + IDENT_BAD +}; + +/* --- Request structure --- */ + +typedef struct ident_request { + struct sockaddr_in local, remote; + unsigned state; + void (*func)(ident_reply */*i*/, void */*p*/); + void *p; + sel_state *s; + conn c; + selbuf b; +} ident_request; + +enum { + IDENT_CONN, + IDENT_READ, + IDENT_DONE +}; + +/*----- Functions provided ------------------------------------------------*/ + +/* --- @ident_abort@ --- * + * + * Arguments: @ident_request *rq@ = pointer to request block + * + * Returns: --- + * + * Use: Cancels an ident request in progress. + */ + +extern void ident_abort(ident_request */*rq*/); + +/* --- @ident@ --- * + * + * Arguments: @ident_request *rq@ = pointer to request block + * @sel_state *s@ = I/O multiplexor + * @const struct sockaddr_in *local, *remote@ = addresses + * @void (*func)(ident_reply *i, void *p)@ = handler function + * @void *p@ = argument for handler + * + * Returns: --- + * + * Use: Initializes an ident request. + */ + +extern void ident(ident_request */*rq*/, sel_state */*s*/, + const struct sockaddr_in */*local*/, + const struct sockaddr_in */*remote*/, + void (*/*func*/)(ident_reply */*i*/, void */*p*/), + void */*p*/); + +/* --- @ident_socket@ --- * + * + * Arguments: @ident_request *rq@ = pointer to request block + * @sel_state *s@ = I/O multiplexor + * @int sk@ = connected socket file descriptor + * @void (*func)(ident_reply *i, void *p)@ = handler function + * @void *p@ = argument for handler + * + * Returns: --- + * + * Use: An alternative interface to @ident@. Initializes an ident + * request from a connected socket, rather than from an explicit + * address. This will call @getsockname@ and @getpeername@ to + * find out what the socket is actually connected to, which adds + * convenience but wastes time. + */ + +extern void ident_socket(ident_request */*rq*/, sel_state */*s*/, int /*sk*/, + void (*/*func*/)(ident_reply */*i*/, void */*p*/), + void */*p*/); + +/*----- That's all, folks -------------------------------------------------*/ + +#ifdef __cplusplus + } +#endif + +#endif