Exemple #1
0
/*
 *  Function: MatchDialTemplate()
 *
 *  Parameters: pattern - pattern string to match
 *              line    - line number to match
 *                        (May be 0 to match all lines)
 *              timeout - returned dial timeout in seconds
 *                        (May be NULL to not get a timeout)
 *              rewrite - buffer to hold rewritten string
 *                        (May be NULL for no rewrite)
 *              rewritelen - Bytes available in the buffer to write to
 *              routemode - pointer to location to hold route mode returned
 *                          (May be NULL to not get a routemode)
 *              tone - pointer to location to hold tone returned
 *
 *  Description: Find the best template to match a pattern
 *
 *  Returns: DialMatchAction
 */
DialMatchAction
MatchDialTemplate (const char *pattern,
                   const line_t line,
                   int *timeout,
                   char *rewrite,
                   int rewritelen,
                   RouteMode *pRouteMode,
                   vcm_tones_t *pTone)
{
    DialMatchAction result = DIAL_NOMATCH;
    struct DialTemplate *ptempl = basetemplate;
    struct DialTemplate *pbestmatch = NULL;
    boolean bestmatch_dialnow = FALSE;
    int best_comma_count = 0;
    DialMatchAction partialmatch_type = DIAL_NOMATCH;
    boolean partialmatch = FALSE;

    int matchlen = 0;
    int partialmatchlen = 0;
    int givedialtone = 0;
    int comma_counter = 0;

    /*
     * We need to provide a default rewrite string in case we do not have any template matches.
     * This happens when there is no template match (such as no * pattern) and when they have
     * no dial plan file at all
     */
    if (rewrite != NULL) {
        char *output = rewrite;
        int room = rewritelen;

        addbytes(&output, &room, pattern, -1);
    }

    /*
     * If the dialplan is empty, check to see if a # is in the pattern
     * and return DIAL_IMMEDIATELY. If not go ahead and return
     * DIAL_NOMATCH since there will be no template match in
     * an empty dialplan.
     */
    if (ptempl == NULL) {
        if (strchr(pattern, '#') && (poundDialingEnabled())) {
            return DIAL_IMMEDIATELY;
        } else {
            return DIAL_NOMATCH;
        }
    }

    /*
     * Iterate through all the templates. Skip the this template if it's not
     * for this line or all lines.
     */
    while (ptempl != NULL) {
        if (MatchLineNumber(ptempl->line, line)) {
            char *pinput = (char *) pattern;
            char *pmatch = ptempl->pattern;
            int thismatchlen = 0;
            DialMatchAction thismatch = DIAL_FULLMATCH;
            char *subs[MAX_SUBTITUTIONS];
            int subslen[MAX_SUBTITUTIONS];
            int subscount = -1;
            boolean dialnow = FALSE;

            while (*pinput) {
                int idx;

                /* Since the code below combines multiple ,
                 * in a row into "one" , only increment
                 * comma counter once instead of once
                 * for each comma combined.
                 */
                if (pmatch[0] == ',') {
                    comma_counter++;
                }

                /*
                 * Skip over any dial tone characters
                 */
                while (pmatch[0] == ',') {
                    pmatch++;
                }
                /*
                 * If this is a pattern character, we need to capture the digits for the
                 * substitution strings
                 */
                if (((pmatch[0] == '.') && isDialedDigit(pinput[0])) ||
                     (pmatch[0] == '*')) {
                    /*
                     * Get the next index in the substitution array (if any)
                     * Note that if they have more pattern sections in the pattern string
                     * the last one will get the counts for the characters.  So for example
                     * with the MAX_SUBSTITUTIONS of 5 and a pattern of
                     *  1.2.3.4.5.6.7.
                     * and an input string of
                     *  1a2b3c4d5e6f7g
                     * the arrays of substitions would come out as follows:
                     *   %0 = 1a2b3c4d5e6f7g  (as expected)
                     *   %1 = a               (as expected)
                     *   %2 = b               (as expected)
                     *   %3 = c               (as expected)
                     *   %4 = d               (as expected)
                     *   %5 = e6f    NOT what they really wanted, but predictable from the algorithm
                     */
                    if (subscount < (MAX_SUBTITUTIONS - 1)) {
                        subscount++;
                        subs[subscount] = pinput;
                        subslen[subscount] = 1;
                    }
                    if (pmatch[0] == '.') {
                        thismatch = DIAL_FULLPATTERN;
                        /*
                         * . in the pattern will match anything but doesn't contribute
                         * to our matching length for finding the best template
                         */
                        while (isdigit(pinput[1]) && (pmatch[1] == '.')) {
                            pinput++;
                            pmatch++;
                            subslen[subscount]++;
                        }
                    } else {
                        thismatch = DIAL_WILDPATTERN;
                        /*
                         * '*' is a wild card to match 1 or more characters
                         * Do a hungry first match
                         *
                         * Note: If match is currently pointing to an escape character,
                         *       we need to go past it to match the actual character.
                         */
                        if (pmatch[1] == DIAL_ESCAPE) {
                            idx = 2;
                        } else {
                            idx = 1;
                        }

                        /*
                         * The '*' will not match the '#' character since its' default use
                         * causes the phone to "dial immediately"
                         */
                        if ((pinput[0] == '#') && (poundDialingEnabled())) {
                            dialnow = TRUE;
                        } else {
                            while ((pinput[1] != '\0') &&
                                   (pinput[1] != pmatch[idx])) {
                                /*
                                 * If '#' is found and pound dialing is enabled, break out of the loop.
                                 */
                                if ((pinput[1] == '#') &&
                                    (poundDialingEnabled())) {
                                    break;
                                }
                                pinput++;
                                subslen[subscount]++;
                            }
                        }
                    }
                    /*
                     * Any other character must match exactly
                     */
                } else {
                    /*
                     * Look for the Escape character '\' and remove it
                     * Right now, the only character that needs to be escaped is '*'
                     * Note that we treat \ at the end of a line as a non-special
                     * character
                     */
                    if ((pmatch[0] == DIAL_ESCAPE) && (pmatch[1] != '\0')) {
                        pmatch++;
                    }

                    if (pmatch[0] != pinput[0]) {
                        /*
                         * We found a '#' that doesn't match the current match template
                         * This means that the '#" should be interpreted as the dial
                         * termination character.
                         */
                        if ((pinput[0] == '#') && (poundDialingEnabled())) {
                            dialnow = TRUE;
                            break;
                        }
                        /*
                         * No match, so abandon with no pattern to select
                         */
                        thismatchlen = -1;
                        thismatch = DIAL_NOMATCH;
                        break;

                    } else {
                        /*
                         * We matched one character, count it for the overall template match
                         */
                        thismatchlen++;
                    }
                }
                pmatch++;
                pinput++;
            }

            /*
             * *pinput = NULL means we matched everything that
             * was dialed in this template
             * Partial never matches * rules
             * Since 97. should have precendence over 9..
             * also check matchlen.
             * Since fullmatches (exact digits) have precendence
             * over fullpattern (.) check matchtype
             */
            if ((*pinput == NUL) || (dialnow)) {
                if ((thismatchlen > partialmatchlen) ||
                    ((thismatchlen == partialmatchlen) &&
                     (thismatch > partialmatch_type))) {
                    partialmatch_type = thismatch;
                    partialmatchlen = thismatchlen;
                    pbestmatch = ptempl;
                    partialmatch = TRUE;
                    bestmatch_dialnow = dialnow;
                    best_comma_count = comma_counter;
                    result = DIAL_NOMATCH;
                }
            }

            /*
             * If we exhausted the match string, then the template is a perfect match
             * However, we don't want to take this as the best template unless it matched
             * more digits than any other pattern.  For example if we have a pattern of
             *   9011*
             *   9.11
             *  We would want 9011 to match against the first one even though it is not complete
             *
             * We also have to be careful that a pattern such as
             *   *
             * does not beat something like
             *   9.......
             * when you have 94694210
             */
            if (pmatch[0] == '\0') {
                /*
                 * If this pattern is better, we want to adopt it
                 */
                if ((thismatchlen > matchlen) ||
                    ((thismatchlen == matchlen) && (thismatch > result)) ||
                    ((thismatch == DIAL_WILDPATTERN) &&
                     ((result == DIAL_NOMATCH) && (partialmatch == FALSE)))) {
                    /*
                     * this is a better match than what we found before
                     */
                    pbestmatch = ptempl;
                    bestmatch_dialnow = dialnow;
                    matchlen = thismatchlen;
                    result = thismatch;
                    /*
                     * Generate a rewrite string
                     *
                     *  <TEMPLATE MATCH="31."     Timeout="0" User="******" Rewrite="11111111%s"/>
                     *      310 -> 111111110
                     *  <TEMPLATE MATCH="32.."    Timeout="0" User="******" Rewrite="122222232.."/>
                     *      3255 -> 12222223255
                     *  <TEMPLATE MATCH="33..."   Timeout="0" User="******" Rewrite="13333333%1"/>
                     *  <TEMPLATE MATCH="34..1.." Timeout="0" User="******" Rewrite="14444%155%2"/>
                     *  <TEMPLATE MATCH="34..2.." Timeout="0" User="******" Rewrite="1444%s"/>
                     *  <TEMPLATE MATCH="34..3.." Timeout="0" User="******" Rewrite="11..11.."/>
                     */
                    if (rewrite != NULL) {
                        int dotindex = -1;
                        int dotsleft = 0;
                        char *output = rewrite;
                        int room = rewritelen;
                        char *prewrite = pbestmatch->rewrite;

                        if ((prewrite == NULL) || (prewrite[0] == '\0')) {
                            /*
                             * Null or empty patterns produce the input as the result
                             */
                            addbytes(&output, &room, pattern, -1);
                        } else {
                            while (prewrite[0] != '\0') {
                                if (prewrite[0] == '.') {
                                    /*
                                     * For a dot, we copy over the single previously matched character
                                     */
                                    while ((dotsleft == 0) &&
                                           (dotindex < subscount)) {
                                        dotindex++;
                                        dotsleft = subslen[dotindex];
                                    }
                                    if (dotsleft > 0) {
                                        addbytes(&output, &room,
                                                 subs[dotindex] +
                                                 subslen[dotindex] - dotsleft,
                                                 1);
                                        dotsleft--;
                                    }
                                } else if (prewrite[0] == '%') {
                                    int idx = prewrite[1] - '1';

                                    prewrite++; // Consume the %
                                    if ((prewrite[0] == 's') ||
                                        (prewrite[0] == '0')) {
                                        /*
                                         * %0 or %s means copy the entire input string
                                         */
                                        addbytes(&output, &room, pattern, -1);
                                    } else if ((idx >= 0) &&
                                               (idx <= subscount)) {
                                        /*
                                         * %n where n is withing the range of substitution patterns copies over
                                         * all of the characters that matched that group
                                         */
                                        addbytes(&output, &room, subs[idx],
                                                 subslen[idx]);
                                    } else if (prewrite[0]) {
                                        /*
                                         * %anything copies over anything.  This is how you would get a
                                         * % in the rewrite string
                                         */
                                        addbytes(&output, &room, prewrite, 1);
                                    }
                                } else {
                                    /*
                                     * Just a normal character, just copy it over
                                     */
                                    addbytes(&output, &room, prewrite, 1);
                                }
                                /*
                                 * Consume the character we used (if any)
                                 */
                                if (prewrite[0]) {
                                    prewrite++;
                                }
                            }
                        }
                        /*
                         * Put on the usermode (if specified)
                         */
                        switch (pbestmatch->userMode) {
                        case UserPhone:
                            if (*(output - 1) == '>') {
                                --room;
                                --output;
                                addbytes(&output, &room, ";user=phone>", -1);
                            } else {
                                addbytes(&output, &room, ";user=phone", -1);
                            }
                            break;
                        case UserIP:
                            if (*(output - 1) == '>') {
                                --room;
                                --output;
                                addbytes(&output, &room, ";user=ip>", -1);
                            } else {
                                addbytes(&output, &room, ";user=ip", -1);
                            }
                            break;
                        default:
                            break;
                        }
                    }
                }
            } else if (pmatch[0] == ',') {
                givedialtone = 1;
            }

            /*
             * Even if this pattern was not taken as a full match, remember the longest length
             */
            if (thismatchlen > matchlen) {
                matchlen = thismatchlen;
            }
        }
        /*
         * Try the next template
         */
        ptempl = ptempl->next;
        comma_counter = 0;
    }
    /*
     * Did we get any templates at all?
     */
    switch (result) {
    case DIAL_FULLPATTERN:
    case DIAL_FULLMATCH:
        givedialtone = 0;
        /* FALLTHROUGH */
    case DIAL_WILDPATTERN:
        if (timeout != NULL) {
            *timeout = pbestmatch->timeout;
        }
        if (pRouteMode != NULL) {
            *pRouteMode = pbestmatch->routeMode;
        }
        break;

    default:
        /*
         * If we have received a partial match, set the timeout
         * to be the default timeout (i.e. interdigit timeout)
         * to allow for additional digit collection.
         */
        if (partialmatch) {
            if ((timeout != NULL) && (*timeout == 0)) {
                *timeout = DIAL_TIMEOUT;
            }
        } else if ((*(pattern + strlen(pattern) - 1) == '#') &&
                   (poundDialingEnabled())) {
            /*
             * No template was matched, however if the dialplan
             * does not have the default '*' rule and the pattern
             * dialed did not match any other template this code
             * would be hit. Therefore check for a # to see if
             * we need to set the dial immediately flag.
             */
            result = DIAL_IMMEDIATELY;
        }
        break;
    }

    /*
     * If the bestmatch template says to dialnow, do it.
     */
    if (bestmatch_dialnow) {
        /*
         * If there is partial match, and dialled pattern has "#",
         * then do not Dial immediately. Give user a chance to edit
         * the mistake if any.
         */
        if (!((poundDialingEnabled()) && (strchr(pattern, '#')) &&
              partialmatch)) {
            result = DIAL_IMMEDIATELY;
            if (timeout != NULL) {
                *timeout = 0;
            }
        }
    }

    if (givedialtone) {
        /*
         * Give user dial-tone. The tone given
         * is based on the rule. Default tone
         * is Outside-Dial-Tone.
         */
        if (pTone != NULL) {
            *pTone = VCM_DEFAULT_TONE;
            if (pbestmatch != NULL) {
                if (best_comma_count < pbestmatch->tones_defined) {
                    *pTone = pbestmatch->tone[best_comma_count];
                }
            }
        }
        result = DIAL_GIVETONE;
    }

    return result;   // Nothing special to match against
}
Exemple #2
0
int
bootpass(Boot *b, void *vbuf, int nbuf)
{
	char *buf, *ebuf;
	Hdr *hdr;
	ulong magic, entry, data, text, bss;
	uvlong entry64;

	if(b->state == FAILED)
		return FAIL;

	if(nbuf == 0)
		goto Endofinput;

	buf = vbuf;
	ebuf = buf+nbuf;
	while(addbytes(&b->wp, b->ep, &buf, ebuf) == 0) {
		switch(b->state) {
		case INITKERNEL:
			b->state = READEXEC;
			b->bp = (char*)&b->hdr;
			b->wp = b->bp;
			b->ep = b->bp+sizeof(Hdr);
			break;
		case READEXEC:
			hdr = &b->hdr;
			magic = GLLONG(hdr->magic);
			if(magic == I_MAGIC || magic == S_MAGIC) {
				b->state = READ9TEXT;
				b->bp = (char*)PADDR(GLLONG(hdr->entry));
				b->wp = b->bp;
				b->ep = b->wp+GLLONG(hdr->text);

				if(magic == I_MAGIC){
					memmove(b->bp, b->hdr.uvl, sizeof(b->hdr.uvl));
					b->wp += sizeof(b->hdr.uvl);
				}

				print("%lud", GLLONG(hdr->text));
				break;
			}

			/* check for gzipped kernel */
			if(b->bp[0] == 0x1F && (uchar)b->bp[1] == 0x8B && b->bp[2] == 0x08) {
				b->state = READGZIP;
				b->bp = (char*)malloc(1440*1024);
				b->wp = b->bp;
				b->ep = b->wp + 1440*1024;
				memmove(b->bp, &b->hdr, sizeof(Hdr));
				b->wp += sizeof(Hdr);
				print("gz...");
				break;
			}

			/*
			 * Check for ELF.
			 */
			if(memcmp(b->bp, elfident, 4) == 0){
				b->state = READEHDR;
				b->bp = (char*)&ehdr;
				b->wp = b->bp;
				b->ep = b->wp + sizeof(Ehdr);
				memmove(b->bp, &b->hdr, sizeof(Hdr));
				b->wp += sizeof(Hdr);
				print("elf...");
				break;
			}

			print("bad kernel format (magic == %#lux)\n", magic);
			b->state = FAILED;
			return FAIL;

		case READ9TEXT:
			hdr = &b->hdr;
			b->state = READ9DATA;
			b->bp = (char*)PGROUND(PADDR(GLLONG(hdr->entry))+GLLONG(hdr->text));
			b->wp = b->bp;
			b->ep = b->wp + GLLONG(hdr->data);
			print("+%ld", GLLONG(hdr->data));
			break;

		case READ9DATA:
			hdr = &b->hdr;
			bss = GLLONG(hdr->bss);
			memset(b->ep, 0, bss);
			print("+%ld=%ld\n",
				bss, GLLONG(hdr->text)+GLLONG(hdr->data)+bss);
			b->state = TRYBOOT;
			return ENOUGH;

		case READEHDR:
			if(!readehdr(b)){
				print("readehdr failed\n");
				b->state = FAILED;
				return FAIL;
			}
			break;

		case READPHDR:
			if(!readphdr(b)){
				b->state = FAILED;
				return FAIL;
			}
			break;

		case READEPAD:
			if(!readepad(b)){
				b->state = FAILED;
				return FAIL;
			}
			break;

		case READEDATA:
			if(!readedata(b)){
				b->state = FAILED;
				return FAIL;
			}
			if(b->state == TRYBOOT)
				return ENOUGH;
			break;

		case TRYBOOT:
		case TRYEBOOT:
		case READGZIP:
			return ENOUGH;

		case READ9LOAD:
		case INIT9LOAD:
			panic("9load");

		default:
			panic("bootstate");
		}
	}
	return MORE;


Endofinput:
	/* end of input */
	switch(b->state) {
	case INITKERNEL:
	case READEXEC:
	case READ9TEXT:
	case READ9DATA:
	case READEHDR:
	case READPHDR:
	case READEPAD:
	case READEDATA:
		print("premature EOF\n");
		b->state = FAILED;
		return FAIL;

	case TRYBOOT:
		entry = GLLONG(b->hdr.entry);
		magic = GLLONG(b->hdr.magic);
		if(magic == I_MAGIC){
			print("entry: 0x%lux\n", entry);
			warp9(PADDR(entry));
		}
		else if(magic == S_MAGIC){
			entry64 = beswav(b->hdr.uvl[0]);
			warp64(entry64);
		}
		b->state = FAILED;
		return FAIL;

	case TRYEBOOT:
		entry = GLLONG(b->hdr.entry);
		if(ehdr.machine == I386){
			print("entry: 0x%lux\n", entry);
			warp9(PADDR(entry));
		}
		else if(ehdr.machine == AMD64){
			print("entry: 0x%lux\n", entry);
			warp64(entry);
		}
		b->state = FAILED;
		return FAIL;

	case READGZIP:
		hdr = &b->hdr;
		if(b->bp[0] != 0x1F || (uchar)b->bp[1] != 0x8B || b->bp[2] != 0x08)
			print("lost magic\n");

		print("%ld => ", b->wp - b->bp);
		if(gunzip((uchar*)hdr, sizeof(*hdr), (uchar*)b->bp, b->wp - b->bp) < sizeof(*hdr)) {
			print("badly compressed kernel\n");
			return FAIL;
		}

		entry = GLLONG(hdr->entry);
		text = GLLONG(hdr->text);
		data = GLLONG(hdr->data);
		bss = GLLONG(hdr->bss);
		print("%lud+%lud+%lud=%lud\n", text, data, bss, text+data+bss);

		if(gunzip((uchar*)PADDR(entry)-sizeof(Exec), sizeof(Exec)+text+data,
		     (uchar*)b->bp, b->wp-b->bp) < sizeof(Exec)+text+data) {
			print("error uncompressing kernel\n");
			return FAIL;
		}

		/* relocate data to start at page boundary */
		memmove((void*)PGROUND(PADDR(entry+text)), (void*)(PADDR(entry+text)), data);

		entry = GLLONG(b->hdr.entry);
		magic = GLLONG(b->hdr.magic);
		if(magic == I_MAGIC){
			print("entry: 0x%lux\n", entry);
			warp9(PADDR(entry));
		}
		else if(magic == S_MAGIC){
			entry64 = beswav(b->hdr.uvl[0]);
			warp64(entry64);
		}
		b->state = FAILED;
		return FAIL;

	case INIT9LOAD:
	case READ9LOAD:
		panic("end 9load");

	default:
		panic("bootdone");
	}
	b->state = FAILED;
	return FAIL;
}