1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
|
/* $Id: id_parse.c 550 2004-06-17 01:27:41Z eagle $
**
** Low-level function to receive and parse a reply from an ident server.
**
** Written by Peter Eriksson <pen@lysator.liu.se> with modifications by Pr
** Emanuelsson <pell@lysator.liu.se>. Support for S/Ident protocol added by
** Booker Bense <bbense@stanford.edu>.
*/
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif
#include "sident.h"
extern char *id_strtok();
/*
** Returns the string corresponding to an error response code.
*/
int
ident_result_code(char *error_string)
{
int i;
const char *error_text;
for (i = 0; i < IDENT_MAX_ERROR; i++) {
error_text = ident_err_txt[i];
if (strncmp(error_string, error_text, strlen(error_text)) == 0)
return i;
}
return IDENT_UNKNOWN_ERROR;
}
/*
** Read a line of data from the network with an optional timeout. The line
** of data will be left in id->buf on success. timeout, if given, is
** interpreted the same as when given to select(2). Returns the same set of
** error codes as id_parse returns.
*/
int
id_read_response(ident_t *id, struct timeval *timeout)
{
fd_set read_set;
int status;
size_t offset;
if (id == NULL)
return IDENT_SYSTEM_ERROR;
/* If timeout is set, use select to be sure there's data there to read. */
if (timeout != NULL) {
FD_ZERO(&read_set);
FD_SET(id->fd, &read_set);
status = select(FD_SETSIZE, &read_set, NULL, NULL, timeout);
if (status < 0)
return IDENT_SYSTEM_ERROR;
if (status == 0) {
errno = ETIMEDOUT;
return IDENT_TIMEOUT;
}
}
/* This is completely broken; it doesn't actually implement timeouts. */
offset = 0;
while (offset < sizeof(id->buf)) {
status = read(id->fd, id->buf + offset, sizeof(id->buf) - offset - 1);
offset += status;
id->buf[offset] = '\0';
#ifdef DEBUG
printf("Read response %ld %s\n", offset, id->buf);
#endif
if (status < 0)
return IDENT_SYSTEM_ERROR;
if (id->buf[offset - 1] == '\n' || id->buf[offset - 1] == '\r')
break;
if (status == 0) {
errno = ENOTCONN;
return IDENT_SYSTEM_ERROR;
}
}
return IDENT_AUTH_OKAY;
}
/*
** Parses the reply to a query sent off by id_query() and returns information
** to the locations pointed to by resp_port, req_port, identifier, opsys, and
** charset. For string data (identifier, opsys, and charset) pointers to
** allocated space are returned. The caller is responsible for freeing.
**
** Returns one of the following codes:
**
** -3 Illegal reply type from remote server. identifier is set to the
** illegal reply.
**
** -2 Cannot parse the reply from the server. identifier is normally set to
** the illegal reply, unless it could not be saved.
**
** -1 Some other general error or timeout.
**
** 0 Non-blocking mode is set (a timeout was specified) and id_parse has not
** finished parsing the reply from the server.
**
** 1 Complete success.
**
** 2 The query and reply (the basic protocol) were successful, but the
** remote site experienced some error. identifier is set to the error
** message from the remote server.
*/
int
id_parse(ident_t * id, struct timeval *timeout, int *resp_port,
int *req_port, char **identifier, char **opsys, char **charset,
struct ident_auth_client_data *auth_data)
{
char c, *cp, *tmp_cp;
int res, resp, reqp, rcode;
char *tmp_charset = NULL;
errno = 0;
if (id == NULL)
return -1;
if (resp_port != NULL)
*resp_port = 0;
if (req_port != NULL)
*req_port = 0;
if (identifier != NULL)
*identifier = NULL;
if (opsys != NULL)
*opsys = NULL;
if (charset != NULL)
*charset = NULL;
res = id_read_response(id, timeout);
if (res != IDENT_AUTH_OKAY)
return res;
/* Get first field (<resp_port> , <req_port>). */
cp = id_strtok(id->buf, ":", &c);
if (cp == NULL)
return IDENT_INVALID_RESP_INFO;
if (sscanf(cp, " %d , %d", &resp, &reqp) != 2) {
if (identifier) {
*identifier = strdup(cp);
if (*identifier == NULL)
return IDENT_SYSTEM_ERROR;
}
return IDENT_INVALID_RESP_INFO;
}
if (resp_port != NULL)
*resp_port = resp;
if (req_port != NULL)
*req_port = reqp;
/* Get second field (USERID , ERROR , AUTHENTICATE). */
cp = id_strtok((char *)0, ":", &c);
if (cp == NULL)
return IDENT_INVALID_RESP_INFO;
if (strcmp(cp, "ERROR") == 0) {
cp = id_strtok(NULL, "\n\r", &c);
if (cp == NULL)
return IDENT_INVALID_RESP_INFO;
if (identifier) {
*identifier = strdup(cp);
if (*identifier == NULL)
return IDENT_SYSTEM_ERROR;
}
return ident_result_code(*identifier);
} else if (strcmp(cp, "USERID") == 0) {
/* Get first subfield of third field <opsys>. */
cp = id_strtok(NULL, ",:", &c);
if (cp == NULL)
return IDENT_INVALID_RESP_INFO;
if (opsys != NULL) {
*opsys = strdup(cp);
if (*opsys == NULL)
return IDENT_SYSTEM_ERROR;
}
/* We have a second subfield (<charset>). */
if (c == ',') {
cp = id_strtok((char *)0, ":", &c);
if (cp == NULL)
return IDENT_INVALID_RESP_INFO;
tmp_charset = cp;
if (charset) {
*charset = strdup(cp);
if (*charset == NULL)
return IDENT_SYSTEM_ERROR;
}
/* We have even more subfields - ignore them. */
if (c == ',')
id_strtok(NULL, ":", &c);
}
if (tmp_charset != NULL && strcmp(tmp_charset, "OCTET") == 0)
cp = id_strtok(NULL, NULL, &c);
else
cp = id_strtok(NULL, "\n\r", &c);
if (identifier != NULL) {
*identifier = strdup(cp);
if (*identifier == NULL)
return IDENT_SYSTEM_ERROR;
}
return IDENT_AUTH_NOT_SUPPORTED;
} else if (strcmp(cp, "AUTHENTICATE") == 0) {
tmp_cp = id_strtok(NULL, "\n\r", &c) ;
strncpy(auth_data->authenticate_data, tmp_cp, MAX_AUTH_LEN);
rcode = (*auth_data->auth_struct->auth)(auth_data);
if (rcode == IDENT_AUTH_OKAY ) {
*identifier = strdup(auth_data->user_ident);
} else {
*identifier = strdup(cp);
}
return rcode;
} else {
if (identifier) {
*identifier = strdup(cp);
if (*identifier == NULL)
return IDENT_SYSTEM_ERROR;
}
return IDENT_UNKNOWN_ERROR;
}
}
|