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>