int parse_authenticate_body( str *body, struct authenticate_body *auth) { char *p; char *end; int n; int state; str name; str val; int quoted_val; if (body->s==0 || *body->s==0 ) { LM_ERR("empty body\n"); goto error; } memset( auth, 0, sizeof(struct authenticate_body)); p = body->s; end = body->s + body->len; /* parse the "digest" */ while (p<end && isspace((int)*p)) p++; if (p+AUTHENTICATE_DIGEST_LEN>=end ) goto parse_error; if ( LOWER4B( GET4B(p) ) != 0x64696765 /*dige*/ || LOWER1B(*(p+4))!=0x73 /*s*/ || LOWER1B(*(p+5))!=0x74 /*t*/) goto parse_error; p += AUTHENTICATE_DIGEST_LEN; if (!isspace((int)*p)) goto parse_error; p++; while (p<end && isspace((int)*p)) p++; if (p==end) goto parse_error; while (p<end) { state = OTHER_STATE; quoted_val = 0; /* get name */ name.s = p; if (p+4<end) { n = LOWER4B( GET4B(p) ); switch(n) { CASE_5B( 0x7265616c, 'm', REALM_STATE, 1); /*realm*/ CASE_5B( 0x6e6f6e63, 'e', NONCE_STATE, 1); /*nonce*/ CASE_5B( 0x7374616c, 'e', STALE_STATE, 0); /*stale*/ CASE_6B( 0x646f6d62, 'i', 'n', DOMAIN_STATE, 1); /*domain*/ CASE_6B( 0x6f706171, 'u', 'e', OPAQUE_STATE, 1); /*opaque*/ case 0x616c676f: /*algo*/ if (p+9<end && LOWER4B(GET4B(p+4))==0x72697468 && LOWER1B(*(p+8))=='m' ) { p+=9; state = ALGORITHM_STATE; } else { p+=4; } break; default: if ((n|0xff)==0x716f70ff) /*qop*/ { state = QOP_STATE; p+=3; } } } else if (p+3<end) { n = LOWER4B( GET3B(p) ); if (n==0x716f70ff) /*qop*/ { p+=3; state = QOP_STATE; } } /* parse to the "=" */ for( n=0 ; p<end&&!isspace((int)*p)&&*p!='=' ; n++,p++ ); if (p==end) goto parse_error; if (n!=0) state = OTHER_STATE; name.len = p-name.s; /* get the '=' */ while (p<end && isspace((int)*p)) p++; if (p==end || *p!='=') goto parse_error; p++; /* get the value (quoted or not) */ while (p<end && isspace((int)*p)) p++; if (p+1>=end || (quoted_val && *p!='\"')) goto parse_error; if (!quoted_val && *p=='\"') quoted_val = 1; if (quoted_val) { val.s = ++p; while (p<end && *p!='\"') p++; if (p==end) goto error; } else { val.s = p; while (p<end && !isspace((int)*p) && *p!=',') p++; } val.len = p - val.s; if (val.len==0) val.s = 0; /* consume the closing '"' if quoted */ p += quoted_val; while (p<end && isspace((int)*p)) p++; if (p<end && *p==',') { p++; while (p<end && isspace((int)*p)) p++; } LM_DBG("<%.*s>=\"%.*s\" state=%d\n", name.len,name.s,val.len,val.s,state); /* process the AVP */ switch (state) { case QOP_STATE: auth->qop = val; if(val.len>=4 && !strncasecmp(val.s, "auth", 4)) auth->flags |= QOP_AUTH; break; case REALM_STATE: auth->realm = val; break; case NONCE_STATE: auth->nonce = val; break; case DOMAIN_STATE: auth->domain = val; break; case OPAQUE_STATE: auth->opaque = val; break; case ALGORITHM_STATE: if (val.len==3) { if ( LOWER4B(GET3B(val.s))==0x6d6435ff) /*MD5*/ auth->flags |= AUTHENTICATE_MD5; } else { LM_ERR("unsupported algorithm \"%.*s\"\n",val.len,val.s); goto error; } break; case STALE_STATE: if (val.len==4 && LOWER4B(GET4B(val.s))==0x74727565) /*true*/ { auth->flags |= AUTHENTICATE_STALE; } else if ( !(val.len==5 && LOWER1B(val.s[4])=='e' && LOWER4B(GET4B(val.s))==0x66616c73) ) { LM_ERR("unsupported stale value \"%.*s\"\n",val.len,val.s); goto error; } break; default: break; } } /* some checkings */ if (auth->nonce.s==0 || auth->realm.s==0) { LM_ERR("realm or nonce missing\n"); goto error; } return 0; parse_error: LM_ERR("parse error in <%.*s> around %ld\n", body->len, body->s, (long)(p-body->s)); error: return -1; }
int parse_authenticate_body( str *body, struct authenticate_body *auth) { char *p; char *end; int n; int state; str name; str val; if (body->s==0 || *body->s==0 ) { LOG(L_ERR,"ERROR:uac:parse_authenticate_body: empty body\n"); goto error; } memset( auth, 0, sizeof(struct authenticate_body)); p = body->s; end = body->s + body->len; /* parse the "digest" */ while (p<end && isspace((int)*p)) p++; if (p+AUTHENTICATE_DIGEST_LEN>=end ) goto parse_error; if (strncmp(p,AUTHENTICATE_DIGEST_S,AUTHENTICATE_DIGEST_LEN)!=0) goto parse_error; p += AUTHENTICATE_DIGEST_LEN; if (!isspace((int)*p)) goto parse_error; p++; while (p<end && isspace((int)*p)) p++; if (p==end) goto parse_error; while (p<end) { state = OTHER_STATE; /* get name */ name.s = p; if (p+4<end) { n = LOWER4B( GET4B(p) ); switch(n) { CASE_5B( 0x7265616c, 'm', REALM_STATE); /*realm*/ CASE_5B( 0x6e6f6e63, 'e', NONCE_STATE); /*nonce*/ CASE_5B( 0x7374616c, 'e', STALE_STATE); /*stale*/ CASE_6B( 0x646f6d62, 'i', 'n', DOMAIN_STATE); /*domain*/ CASE_6B( 0x6f706171, 'u', 'e', OPAQUE_STATE); /*opaque*/ case 0x616c676f: /*algo*/ if (p+9<end && LOWER4B(GET4B(p+4))==0x72697468 && LOWER1B(*(p+9))=='m' ) { p+=9; state = ALGORITHM_STATE; } else { p+=4; } break; default: if ((n|0xff)==0x716f70ff) /*qop*/ { state = QOP_STATE; p+=3; } } } else if (p+3<end) { n = LOWER4B( GET3B(p) ); if (n==0x716f70ff) /*qop*/ { p+=3; state = QOP_STATE; } } /* parse to the "=" */ for( n=0 ; p<end&&!isspace((int)*p)&&*p!='=' ; n++,p++ ); if (p==end) goto parse_error; if (n!=0) state = OTHER_STATE; name.len = p-name.s; /* get the '=' */ while (p<end && isspace((int)*p)) p++; if (p==end || *p!='=') goto parse_error; p++; /* get the value */ while (p<end && isspace((int)*p)) p++; if (p+1>=end || *p!='\"') goto parse_error; val.s = ++p; while (p<end && *p!='\"') p++; if (p==end) goto error; val.len = p - val.s; if (val.len==0) val.s = 0; p++; while (p<end && isspace((int)*p)) p++; if (p<end && *p==',') { p++; while (p<end && isspace((int)*p)) p++; } DBG("DEBUG:uac:parse_authenticate_body: <%.*s>=\"%.*s\" state=%d\n", name.len,name.s,val.len,val.s,state); /* process the AVP */ switch (state) { case QOP_STATE: /* TODO - add qop support */ LOG(L_ERR,"ERROR:uac:parse_authenticate_body: no qop support " "for the moment :-(\n"); goto error; auth->qop = val; break; case REALM_STATE: auth->realm = val; break; case NONCE_STATE: auth->nonce = val; break; case DOMAIN_STATE: auth->domain = val; break; case OPAQUE_STATE: auth->opaque = val; break; case ALGORITHM_STATE: if (val.len==3) { if ( LOWER4B(GET3B(val.s))==0x6d6435ff) /*MD5*/ auth->flags |= AUTHENTICATE_MD5; } else { LOG(L_ERR,"ERROR:uac:parse_authenticate_body: " "unsupported algorithm \"%.*s\"\n",val.len,val.s); goto error; } break; case STALE_STATE: if (val.len==4 && LOWER4B(GET4B(val.s))==0x74727565) /*true*/ { auth->flags |= AUTHENTICATE_STALE; } else if ( !(val.len==5 && val.s[4]=='e' && LOWER4B(GET4B(val.s))==0x66616c73) ) { LOG(L_ERR,"ERROR:uac:parse_authenticate_body: " "unsupported stale value \"%.*s\"\n",val.len,val.s); goto error; } break; default: break; } } /* some checkings */ if (auth->nonce.s==0 || auth->realm.s==0) { LOG(L_ERR,"ERROR:uac:parse_authenticate_body: realm or " "nonce missing\n"); goto error; } return 0; parse_error: LOG(L_ERR,"ERROR:uac:parse_authenticate_body: parse error in <%.*s> " "around %ld\n", body->len, body->s, (long)(p-body->s)); error: return -1; }