Annotation of libaitcli/src/telnet.c, revision 1.1.2.1
1.1.2.1 ! misho 1: /*************************************************************************
! 2: * (C) 2010 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
! 3: * by Michael Pounov <misho@openbsd-bg.org>
! 4: *
! 5: * $Author: misho $
! 6: * $Id: aittelnet.c,v 1.1.1.1.2.5 2010/05/03 08:46:27 misho Exp $
! 7: *
! 8: *************************************************************************/
! 9: #ifndef NDEBUG
! 10: #define TELOPTS
! 11: #define TELCMDS
! 12: #endif
! 13: #include "global.h"
! 14:
! 15:
! 16: /*
! 17: * cli_telnetRecv() Telnet receive commands, negotiate with telnet peer
! 18: * @sock = socket for communication
! 19: * @attr = received attributes list, must be free after use, but if NULL receive in binary mode
! 20: * @nAttr = received attributes list size, if is NULL receive in binary mode
! 21: * @pdata = received data in supplied buffer
! 22: * @datLen = buffer pdata size
! 23: * return: 0 not present data; -1 error:: can`t read; -2 timeout; -3 EOF; >0 number of received bytes
! 24: */
! 25: int
! 26: cli_telnetRecv(int sock, struct telnetAttrs **attr, int *nAttr, void *pdata, int datLen)
! 27: {
! 28: int readLen, ret, pos;
! 29: u_char buf[BUFSIZ], *data = NULL;
! 30: struct telnetAttrs ta;
! 31: register int i;
! 32: #ifdef SELECT_WAIT_FOR_READ
! 33: fd_set fds;
! 34: struct timeval tv = { DEFAULT_TELNET_TIMEOUT, 0 };
! 35: #endif
! 36:
! 37: if (attr && nAttr) {
! 38: *attr = NULL;
! 39: *nAttr = 0;
! 40: }
! 41:
! 42: data = pdata ? pdata : NULL;
! 43: if (!data || !datLen || BUFSIZ < datLen) {
! 44: cli_SetErr(EINVAL, "Data buffer or size is not valid!");
! 45: return -1;
! 46: } else
! 47: memset(data, 0, datLen);
! 48:
! 49: #ifdef SELECT_WAIT_FOR_READ
! 50: FD_ZERO(&fds);
! 51: FD_SET(sock, &fds);
! 52: if ((ret = select(sock + 1, &fds, NULL, NULL, &tv)) == -1) {
! 53: LOGERR;
! 54: return -1;
! 55: }
! 56: if (!ret) {
! 57: cli_SetErr(ETIMEDOUT, "Timeout!");
! 58: return -2; // Timeout
! 59: } else
! 60: ret = 0;
! 61: #endif
! 62:
! 63: memset(buf, 0, BUFSIZ);
! 64: readLen = read(sock, buf, BUFSIZ);
! 65: if (-1 == readLen) {
! 66: LOGERR;
! 67: return -1;
! 68: } else
! 69: if (!readLen)
! 70: return -3; // EOF
! 71:
! 72: // receive in binary mode ...
! 73: if (!attr || !nAttr) {
! 74: memcpy(data, buf, readLen > datLen ? datLen : readLen);
! 75: return readLen;
! 76: }
! 77:
! 78: // telnet ascii mode ...
! 79: for (ret = pos = i = 0; i < readLen && pos < datLen; i++) {
! 80: // raw(clear) mode
! 81: if (!ret) {
! 82: if (IAC != buf[i]) {
! 83: data[pos++] = buf[i];
! 84: } else {
! 85: ret = 1;
! 86: memset(&ta, 0, sizeof ta);
! 87: }
! 88:
! 89: continue;
! 90: }
! 91:
! 92: // check for command
! 93: if (1 == ret) {
! 94: if (xEOF > buf[i]) {
! 95: data[pos++] = buf[i - 1];
! 96: data[pos++] = buf[i];
! 97:
! 98: goto cmd_exit;
! 99: } else
! 100: ta.ta_cmd = buf[i];
! 101: if (SB > ta.ta_cmd) {
! 102: (*nAttr)++;
! 103: *attr = realloc(*attr, sizeof(struct telnetAttrs) * *nAttr);
! 104: if (!*attr) {
! 105: LOGERR;
! 106: return -1;
! 107: } else
! 108: memcpy(&(*attr)[*nAttr - 1], &ta, sizeof(struct telnetAttrs));
! 109:
! 110: goto cmd_exit;
! 111: }
! 112: if (IAC > ta.ta_cmd) {
! 113: ret = 2;
! 114: continue;
! 115: }
! 116: cmd_exit:
! 117: ret = 0;
! 118: continue;
! 119: }
! 120:
! 121: // check for option
! 122: if (2 == ret) {
! 123: if (!(TELOPT_KERMIT >= buf[i]) && TELOPT_EXOPL != buf[i]) {
! 124: data[pos++] = buf[i - 2];
! 125: data[pos++] = buf[i - 1];
! 126: data[pos++] = buf[i];
! 127:
! 128: goto opt_exit;
! 129: } else
! 130: ta.ta_opt = buf[i];
! 131: if (SB != ta.ta_cmd) {
! 132: (*nAttr)++;
! 133: *attr = realloc(*attr, sizeof(struct telnetAttrs) * *nAttr);
! 134: if (!*attr) {
! 135: LOGERR;
! 136: return -1;
! 137: } else
! 138: memcpy(&(*attr)[*nAttr - 1], &ta, sizeof(struct telnetAttrs));
! 139:
! 140: goto opt_exit;
! 141: }
! 142:
! 143: ret = 3;
! 144: continue;
! 145: opt_exit:
! 146: ret = 0;
! 147: continue;
! 148: }
! 149:
! 150: // sub-option
! 151: if (3 == ret) {
! 152: if (ta.ta_sublen < MAX_SUB_LEN) {
! 153: if (SE == buf[i] && IAC == ta.ta_sub[ta.ta_sublen - 1]) {
! 154: ta.ta_sublen--;
! 155: ta.ta_sub[ta.ta_sublen] = 0;
! 156:
! 157: (*nAttr)++;
! 158: *attr = realloc(*attr, sizeof(struct telnetAttrs) * *nAttr);
! 159: if (!*attr) {
! 160: LOGERR;
! 161: return -1;
! 162: } else
! 163: memcpy(&(*attr)[*nAttr - 1], &ta, sizeof(struct telnetAttrs));
! 164: ret = 0;
! 165: } else
! 166: ta.ta_sub[ta.ta_sublen++] = buf[i];
! 167: } else {
! 168: cli_SetErr(EPROTONOSUPPORT, "Protocol limitation in sub-option to %d!", MAX_SUB_LEN);
! 169: free(*attr);
! 170: *nAttr = 0;
! 171: return -1;
! 172: }
! 173: }
! 174: }
! 175:
! 176: return pos;
! 177: }
! 178:
! 179: #ifndef NDEBUG
! 180:
! 181: /*
! 182: * cli_telnet_DumpAttrs() Telnet debug attributes list, if NDEBUG defined not include
! 183: * @attr = attributes list
! 184: * @nAttr = attributes list size
! 185: * return: none
! 186: */
! 187: void
! 188: cli_telnet_DumpAttrs(struct telnetAttrs *attr, int nAttr)
! 189: {
! 190: register int i;
! 191:
! 192: for (i = 0; i < nAttr; i++) {
! 193: printf("DUMP:: Attribute(%d) = %s %s Sub(%d) => %s\n", i,
! 194: TELCMD(attr[i].ta_cmd), TELOPT(attr[i].ta_opt),
! 195: attr[i].ta_sublen, attr[i].ta_sub);
! 196: }
! 197: }
! 198:
! 199: #endif
! 200:
! 201: /*
! 202: * cli_telnetSend() Telnet send commands, negotiate with telnet peer
! 203: * @sock = socket for communication
! 204: * @attr = send attributes list
! 205: * @nAttr = send attributes list size
! 206: * @data = data for send
! 207: * @datLen = data size
! 208: * @Term = Terminate with GA (Go Ahead), 1 send after data GA command
! 209: * return: 0 not sended commands; -1 error:: can`t send; >0 number of sended bytes
! 210: */
! 211: int
! 212: cli_telnetSend(int sock, struct telnetAttrs *attr, int nAttr, void *data, int datLen, int Term)
! 213: {
! 214: register int i;
! 215: int writeLen, pos = 0, len = 0;
! 216: u_char *buf = NULL;
! 217:
! 218: /* add commands */
! 219:
! 220: if (attr && nAttr) {
! 221: for (i = 0; i < nAttr; i++) {
! 222: len = 2; // IAC CMD
! 223: if (attr[i].ta_cmd > GA && attr[i].ta_cmd < IAC) {
! 224: len++; // added OPT
! 225:
! 226: if (SB == attr[i].ta_cmd) {
! 227: len += 2; // added IAC SE to end ;)
! 228: len += attr[i].ta_sublen;
! 229: }
! 230: }
! 231:
! 232: buf = realloc(buf, pos + len);
! 233: if (!buf) {
! 234: LOGERR;
! 235: return -1;
! 236: }
! 237:
! 238: buf[pos++] = IAC;
! 239: buf[pos++] = attr[i].ta_cmd;
! 240: if (attr[i].ta_cmd > GA && attr[i].ta_cmd < IAC) {
! 241: buf[pos++] = attr[i].ta_opt;
! 242:
! 243: if (SB == attr[i].ta_cmd) {
! 244: memcpy(buf + pos, attr[i].ta_sub, attr[i].ta_sublen);
! 245: pos += attr[i].ta_sublen;
! 246: buf[pos++] = IAC;
! 247: buf[pos++] = SE;
! 248: }
! 249: }
! 250: }
! 251: }
! 252:
! 253: /* add data */
! 254:
! 255: if (data && datLen) {
! 256: buf = realloc(buf, pos + datLen);
! 257: if (!buf) {
! 258: LOGERR;
! 259: return -1;
! 260: }
! 261:
! 262: memcpy(buf + pos, data, datLen);
! 263: pos += datLen;
! 264: }
! 265:
! 266: /* add GA after end of all */
! 267:
! 268: if (Term) {
! 269: buf = realloc(buf, pos + 2);
! 270: if (!buf) {
! 271: LOGERR;
! 272: return -1;
! 273: }
! 274:
! 275: buf[pos++] = IAC;
! 276: buf[pos++] = GA;
! 277: }
! 278:
! 279: writeLen = write(sock, buf, pos);
! 280: if (-1 == writeLen)
! 281: LOGERR;
! 282:
! 283: if (buf)
! 284: free(buf);
! 285: return writeLen;
! 286: }
! 287:
! 288:
! 289: /*
! 290: * cli_telnet_Get_SubOpt() Telnet get sub option function
! 291: * @attr = input attribute
! 292: * @code = sub-option code for opt
! 293: * @data = sub-option data
! 294: * @datLen = data size set max size in input, output return copy size
! 295: * return: -1 can`t get option; !=-1 option code
! 296: */
! 297: inline int
! 298: cli_telnet_Get_SubOpt(struct telnetAttrs *attr, u_char *code, void *data, u_char *datLen)
! 299: {
! 300: u_char *pos, len;
! 301:
! 302: if (!attr || !data || !datLen || !*datLen)
! 303: return -1;
! 304: if (SB != attr->ta_cmd || !attr->ta_sublen) {
! 305: cli_SetErr(ENOTSUP, "Wrong attribute argument!");
! 306: return -1;
! 307: } else {
! 308: pos = attr->ta_sub;
! 309: len = attr->ta_sublen;
! 310: }
! 311:
! 312: memset(data, 0, *datLen);
! 313: if (0xFF != *code) {
! 314: *code = *pos++;
! 315: len--;
! 316: }
! 317:
! 318: *datLen = len > *datLen ? *datLen : len;
! 319: memcpy(data, pos, *datLen);
! 320:
! 321: return attr->ta_opt;
! 322: }
! 323:
! 324: /*
! 325: * cli_telnet_Set_SubOpt() Telnet set sub option function
! 326: * @attr = output attribute
! 327: * @opt = attribute option
! 328: * @code = sub-option code for opt, if 0xff not specified
! 329: * @data = sub-option data, if NULL not specified
! 330: * @datLen = data size, if 0 not specified
! 331: * return: -1 can`t set sub-otion; 0 ok
! 332: */
! 333: inline int
! 334: cli_telnet_Set_SubOpt(struct telnetAttrs *attr, u_char opt, u_char code, void *data, u_char datLen)
! 335: {
! 336: u_char len;
! 337:
! 338: if (!attr)
! 339: return -1;
! 340: if (!(TELOPT_KERMIT >= opt) && TELOPT_EXOPL != opt) {
! 341: cli_SetErr(EINVAL, "Invalid option argument!");
! 342: return -1;
! 343: }
! 344:
! 345: memset(attr, 0, sizeof(struct telnetAttrs));
! 346: attr->ta_cmd = SB;
! 347: attr->ta_opt = opt;
! 348:
! 349: if (0xFF != code) {
! 350: attr->ta_sublen++;
! 351: attr->ta_sub[0] = code;
! 352: }
! 353:
! 354: if (data && datLen) {
! 355: len = MAX_SUB_LEN > datLen ? datLen : MAX_SUB_LEN - 1;
! 356: attr->ta_sublen += len;
! 357: memcpy(attr->ta_sub + 1, data, len);
! 358: }
! 359:
! 360: return 0;
! 361: }
! 362:
! 363: /*
! 364: * cli_telnet_GetCmd() Telnet get command
! 365: * @attr = input attribute
! 366: * return: -1 can`t get command; !=-1 command <<24 return sublen, <<8 return option, <<0 command
! 367: */
! 368: inline u_int
! 369: cli_telnet_GetCmd(struct telnetAttrs *attr)
! 370: {
! 371: u_int ret = 0;
! 372:
! 373: if (!attr)
! 374: return -1;
! 375: if (xEOF > attr->ta_cmd) {
! 376: cli_SetErr(ENOTSUP, "Wrong attribute command argument!");
! 377: return -1;
! 378: }
! 379: if (GA < attr->ta_cmd && !(TELOPT_KERMIT >= attr->ta_opt) && TELOPT_EXOPL != attr->ta_opt) {
! 380: cli_SetErr(ENOTSUP, "Wrong attribute option argument!");
! 381: return -1;
! 382: }
! 383:
! 384: ret = attr->ta_sublen << 24;
! 385: ret |= attr->ta_opt << 8;
! 386: ret |= attr->ta_cmd;
! 387:
! 388: return ret;
! 389: }
! 390:
! 391: /*
! 392: * cli_telnet_SetCmd() Telnet set command
! 393: * @attr = input attribute
! 394: * @cmd = command
! 395: * @opt = option, if 0xff not specified
! 396: * @arg1 = sub-option code, if 0xff not specified
! 397: * @arg2 = sub-option data, if NULL not specified
! 398: * @arg3 = sub-option data size, if 0 not specified data
! 399: * return: -1 can`t set command; !=-1 ok
! 400: */
! 401: inline int
! 402: cli_telnet_SetCmd(struct telnetAttrs *attr, u_char cmd, u_char opt, ...)
! 403: {
! 404: va_list lst;
! 405: u_char res;
! 406: void *ptr;
! 407:
! 408: if (!attr)
! 409: return -1;
! 410: else
! 411: memset(attr, 0, sizeof(struct telnetAttrs));
! 412:
! 413: if (xEOF > cmd) {
! 414: cli_SetErr(EINVAL, "Invalid command argument!");
! 415: return -1;
! 416: } else
! 417: attr->ta_cmd = cmd;
! 418: if (GA < attr->ta_cmd) {
! 419: if (!(TELOPT_KERMIT >= attr->ta_opt) && TELOPT_EXOPL != attr->ta_opt) {
! 420: cli_SetErr(EINVAL, "Invalid option argument!");
! 421: return -1;
! 422: } else
! 423: attr->ta_opt = opt;
! 424: }
! 425: if (SB == attr->ta_cmd) {
! 426: va_start(lst, opt);
! 427: res = (u_char) va_arg(lst, int);
! 428: if (0xff != res) {
! 429: *attr->ta_sub = res;
! 430: attr->ta_sublen++;
! 431: }
! 432: ptr = va_arg(lst, void*);
! 433: res = (u_char) va_arg(lst, int);
! 434: if (ptr && MAX_SUB_LEN > res) {
! 435: memcpy(attr->ta_sub + 1, ptr, res);
! 436: attr->ta_sublen += res;
! 437: }
! 438: va_end(lst);
! 439: }
! 440:
! 441: return 0;
! 442: }
! 443:
! 444:
! 445: /*
! 446: * cli_telnet_Answer() Automatic generate commands answer to send from telnet
! 447: * @caps = Array of capability options
! 448: * @nCaps = number of capability options
! 449: * @attr = input attribute
! 450: * @nAttr = number of input attributes
! 451: * @ans = output answered attributes, must be free() after use
! 452: * @Ans = number of output answered attributes
! 453: * return: -1 can`t answer; !=-1 ok
! 454: */
! 455: int
! 456: cli_telnet_Answer(u_char *caps, int nCaps, struct telnetAttrs *attr, int nAttr,
! 457: struct telnetAttrs **ans, int *Ans)
! 458: {
! 459: register int i, j;
! 460: int flg;
! 461: struct telnetAttrs ta;
! 462:
! 463: if (!caps || !nCaps || !attr || !nAttr || !ans || !Ans)
! 464: return -1;
! 465: else {
! 466: *ans = NULL;
! 467: *Ans = 0;
! 468: }
! 469:
! 470: for (i = 0; i < nAttr; i++) {
! 471: if (SB > attr[i].ta_cmd || IAC == attr[i].ta_cmd || DONT == attr[i].ta_cmd || WONT == attr[i].ta_cmd)
! 472: continue;
! 473:
! 474: for (flg = -1, j = 0; j < nCaps; j++) {
! 475: if (!(TELOPT_KERMIT >= CAP(caps[j])) && TELOPT_EXOPL != CAP(caps[j]))
! 476: continue;
! 477:
! 478: if (attr[i].ta_opt == CAP(caps[j])) {
! 479: flg = j;
! 480: break;
! 481: }
! 482: }
! 483:
! 484: // make attribute ...
! 485: if (flg > -1) {
! 486: (*Ans)++;
! 487: *ans = realloc(*ans, sizeof(struct telnetAttrs) * *Ans);
! 488: if (!*ans) {
! 489: LOGERR;
! 490: return -1;
! 491: } else
! 492: memset(&ta, 0, sizeof ta);
! 493:
! 494: ta.ta_opt = attr[i].ta_opt;
! 495: switch (attr[i].ta_cmd) {
! 496: case DO:
! 497: ta.ta_cmd = SUP_CAPS(caps[flg]) ? WILL : WONT;
! 498: break;
! 499: case WILL:
! 500: ta.ta_cmd = SUP_CAPS(caps[flg]) ? DO : DONT;
! 501: break;
! 502: case SB:
! 503: ta.ta_cmd = SB;
! 504: break;
! 505: }
! 506:
! 507: memcpy(&(*ans)[*Ans - 1], &ta, sizeof(struct telnetAttrs));
! 508: }
! 509: }
! 510:
! 511: return 0;
! 512: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>