1 /* $Id$ */
2 /*
3  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <pjsip/sip_auth_parser.h>
21 #include <pjsip/sip_auth_msg.h>
22 #include <pjsip/sip_parser.h>
23 #include <pj/assert.h>
24 #include <pj/string.h>
25 #include <pj/except.h>
26 #include <pj/pool.h>
27 
28 static pjsip_hdr* parse_hdr_authorization       ( pjsip_parse_ctx *ctx );
29 static pjsip_hdr* parse_hdr_proxy_authorization ( pjsip_parse_ctx *ctx );
30 static pjsip_hdr* parse_hdr_www_authenticate    ( pjsip_parse_ctx *ctx );
31 static pjsip_hdr* parse_hdr_proxy_authenticate  ( pjsip_parse_ctx *ctx );
32 
33 static void parse_digest_credential ( pj_scanner *scanner, pj_pool_t *pool,
34                                       pjsip_digest_credential *cred);
35 static void parse_pgp_credential    ( pj_scanner *scanner, pj_pool_t *pool,
36                                       pjsip_pgp_credential *cred);
37 static void parse_digest_challenge  ( pj_scanner *scanner, pj_pool_t *pool,
38                                       pjsip_digest_challenge *chal);
39 static void parse_pgp_challenge     ( pj_scanner *scanner, pj_pool_t *pool,
40                                       pjsip_pgp_challenge *chal);
41 
42 const pj_str_t	pjsip_USERNAME_STR =	    { "username", 8 },
43 		pjsip_REALM_STR =	    { "realm", 5},
44 		pjsip_NONCE_STR =	    { "nonce", 5},
45 		pjsip_URI_STR =		    { "uri", 3 },
46 		pjsip_RESPONSE_STR =	    { "response", 8 },
47 		pjsip_ALGORITHM_STR =	    { "algorithm", 9 },
48 		pjsip_DOMAIN_STR =	    { "domain", 6 },
49 		pjsip_STALE_STR =	    { "stale", 5},
50 		pjsip_QOP_STR =		    { "qop", 3},
51 		pjsip_CNONCE_STR =	    { "cnonce", 6},
52 		pjsip_OPAQUE_STR =	    { "opaque", 6},
53 		pjsip_NC_STR =		    { "nc", 2},
54 		pjsip_TRUE_STR =	    { "true", 4},
55 		pjsip_QUOTED_TRUE_STR =	    { "\"true\"", 6},
56 		pjsip_FALSE_STR =	    { "false", 5},
57 		pjsip_QUOTED_FALSE_STR =    { "\"false\"", 7},
58 		pjsip_DIGEST_STR =	    { "Digest", 6},
59 		pjsip_QUOTED_DIGEST_STR =   { "\"Digest\"", 8},
60 		pjsip_PGP_STR =		    { "PGP", 3 },
61 		pjsip_QUOTED_PGP_STR =	    { "\"PGP\"", 5 },
62 		pjsip_BEARER_STR =          { "Bearer", 6 },
63 		pjsip_MD5_STR =		    { "md5", 3 },
64 		pjsip_QUOTED_MD5_STR =	    { "\"md5\"", 5},
65 		pjsip_AUTH_STR =	    { "auth", 4},
66 		pjsip_QUOTED_AUTH_STR =	    { "\"auth\"", 6 };
67 
68 
parse_digest_credential(pj_scanner * scanner,pj_pool_t * pool,pjsip_digest_credential * cred)69 static void parse_digest_credential( pj_scanner *scanner, pj_pool_t *pool,
70                                      pjsip_digest_credential *cred)
71 {
72     pj_list_init(&cred->other_param);
73 
74     for (;;) {
75 	pj_str_t name, value;
76 
77 	pjsip_parse_param_imp(scanner, pool, &name, &value,
78 			      PJSIP_PARSE_REMOVE_QUOTE);
79 
80 	if (!pj_stricmp(&name, &pjsip_USERNAME_STR)) {
81 	    cred->username = value;
82 
83 	} else if (!pj_stricmp(&name, &pjsip_REALM_STR)) {
84 	    cred->realm = value;
85 
86 	} else if (!pj_stricmp(&name, &pjsip_NONCE_STR)) {
87 	    cred->nonce = value;
88 
89 	} else if (!pj_stricmp(&name, &pjsip_URI_STR)) {
90 	    cred->uri = value;
91 
92 	} else if (!pj_stricmp(&name, &pjsip_RESPONSE_STR)) {
93 	    cred->response = value;
94 
95 	} else if (!pj_stricmp(&name, &pjsip_ALGORITHM_STR)) {
96 	    cred->algorithm = value;
97 
98 	} else if (!pj_stricmp(&name, &pjsip_CNONCE_STR)) {
99 	    cred->cnonce = value;
100 
101 	} else if (!pj_stricmp(&name, &pjsip_OPAQUE_STR)) {
102 	    cred->opaque = value;
103 
104 	} else if (!pj_stricmp(&name, &pjsip_QOP_STR)) {
105 	    cred->qop = value;
106 
107 	} else if (!pj_stricmp(&name, &pjsip_NC_STR)) {
108 	    cred->nc = value;
109 
110 	} else {
111 	    pjsip_param *p = PJ_POOL_ALLOC_T(pool, pjsip_param);
112 	    p->name = name;
113 	    p->value = value;
114 	    pj_list_insert_before(&cred->other_param, p);
115 	}
116 
117 	/* Eat comma */
118 	if (!pj_scan_is_eof(scanner) && *scanner->curptr == ',')
119 	    pj_scan_get_char(scanner);
120 	else
121 	    break;
122     }
123 }
124 
parse_pgp_credential(pj_scanner * scanner,pj_pool_t * pool,pjsip_pgp_credential * cred)125 static void parse_pgp_credential( pj_scanner *scanner, pj_pool_t *pool,
126                                   pjsip_pgp_credential *cred)
127 {
128     PJ_UNUSED_ARG(scanner);
129     PJ_UNUSED_ARG(pool);
130     PJ_UNUSED_ARG(cred);
131 
132     PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
133 }
134 
parse_digest_challenge(pj_scanner * scanner,pj_pool_t * pool,pjsip_digest_challenge * chal)135 static void parse_digest_challenge( pj_scanner *scanner, pj_pool_t *pool,
136                                     pjsip_digest_challenge *chal)
137 {
138     pj_list_init(&chal->other_param);
139 
140     for (;;) {
141 	pj_str_t name, value, unquoted_value;
142 
143 	pjsip_parse_param_imp(scanner, pool, &name, &value, 0);
144 
145         if (value.ptr && (value.ptr[0] == '"')) {
146 	    unquoted_value.ptr = value.ptr + 1;
147 	    unquoted_value.slen = value.slen - 2;
148 	} else {
149 	    unquoted_value.ptr = value.ptr;
150 	    unquoted_value.slen = value.slen;
151 	}
152 
153 	if (!pj_stricmp(&name, &pjsip_REALM_STR)) {
154 	    chal->realm = unquoted_value;
155 
156 	} else if (!pj_stricmp(&name, &pjsip_DOMAIN_STR)) {
157 	    chal->domain = unquoted_value;
158 
159 	} else if (!pj_stricmp(&name, &pjsip_NONCE_STR)) {
160 	    chal->nonce = unquoted_value;
161 
162 	} else if (!pj_stricmp(&name, &pjsip_OPAQUE_STR)) {
163 	    chal->opaque = unquoted_value;
164 
165 	} else if (!pj_stricmp(&name, &pjsip_STALE_STR)) {
166 	    if (!pj_stricmp(&value, &pjsip_TRUE_STR) ||
167                 !pj_stricmp(&value, &pjsip_QUOTED_TRUE_STR))
168             {
169 		chal->stale = 1;
170             }
171 
172 	} else if (!pj_stricmp(&name, &pjsip_ALGORITHM_STR)) {
173 	    chal->algorithm = unquoted_value;
174 
175 
176 	} else if (!pj_stricmp(&name, &pjsip_QOP_STR)) {
177 	    chal->qop = unquoted_value;
178 
179 	} else {
180 	    pjsip_param *p = PJ_POOL_ALLOC_T(pool, pjsip_param);
181 	    p->name = name;
182 	    p->value = value;
183 	    pj_list_insert_before(&chal->other_param, p);
184 	}
185 
186 	/* Eat comma */
187 	if (!pj_scan_is_eof(scanner) && *scanner->curptr == ',')
188 	    pj_scan_get_char(scanner);
189 	else
190 	    break;
191     }
192 }
193 
parse_pgp_challenge(pj_scanner * scanner,pj_pool_t * pool,pjsip_pgp_challenge * chal)194 static void parse_pgp_challenge( pj_scanner *scanner, pj_pool_t *pool,
195                                  pjsip_pgp_challenge *chal)
196 {
197     PJ_UNUSED_ARG(scanner);
198     PJ_UNUSED_ARG(pool);
199     PJ_UNUSED_ARG(chal);
200 
201     PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
202 }
203 
int_parse_hdr_authorization(pj_scanner * scanner,pj_pool_t * pool,pjsip_authorization_hdr * hdr)204 static void int_parse_hdr_authorization( pj_scanner *scanner, pj_pool_t *pool,
205 					 pjsip_authorization_hdr *hdr)
206 {
207     const pjsip_parser_const_t *pc = pjsip_parser_const();
208 
209     if (*scanner->curptr == '"') {
210 	pj_scan_get_quote(scanner, '"', '"', &hdr->scheme);
211 	hdr->scheme.ptr++;
212 	hdr->scheme.slen -= 2;
213     } else {
214 	pj_scan_get(scanner, &pc->pjsip_TOKEN_SPEC, &hdr->scheme);
215     }
216 
217     if (!pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR)) {
218 
219 	parse_digest_credential(scanner, pool, &hdr->credential.digest);
220 
221     } else if (!pj_stricmp(&hdr->scheme, &pjsip_PGP_STR)) {
222 
223 	parse_pgp_credential( scanner, pool, &hdr->credential.pgp);
224 
225     } else {
226 	PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
227     }
228 
229     pjsip_parse_end_hdr_imp( scanner );
230 }
231 
int_parse_hdr_authenticate(pj_scanner * scanner,pj_pool_t * pool,pjsip_www_authenticate_hdr * hdr)232 static void int_parse_hdr_authenticate( pj_scanner *scanner, pj_pool_t *pool,
233 					pjsip_www_authenticate_hdr *hdr)
234 {
235     const pjsip_parser_const_t *pc = pjsip_parser_const();
236 
237     if (*scanner->curptr == '"') {
238 	pj_scan_get_quote(scanner, '"', '"', &hdr->scheme);
239 	hdr->scheme.ptr++;
240 	hdr->scheme.slen -= 2;
241     } else {
242 	pj_scan_get(scanner, &pc->pjsip_TOKEN_SPEC, &hdr->scheme);
243     }
244 
245     if (!pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR)) {
246 
247 	parse_digest_challenge(scanner, pool, &hdr->challenge.digest);
248 
249     } else if (!pj_stricmp(&hdr->scheme, &pjsip_PGP_STR)) {
250 
251 	parse_pgp_challenge(scanner, pool, &hdr->challenge.pgp);
252 
253     } else {
254 	PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
255     }
256 
257     pjsip_parse_end_hdr_imp( scanner );
258 }
259 
260 
parse_hdr_authorization(pjsip_parse_ctx * ctx)261 static pjsip_hdr* parse_hdr_authorization( pjsip_parse_ctx *ctx )
262 {
263     pjsip_authorization_hdr *hdr = pjsip_authorization_hdr_create(ctx->pool);
264     int_parse_hdr_authorization(ctx->scanner, ctx->pool, hdr);
265     return (pjsip_hdr*)hdr;
266 }
267 
parse_hdr_proxy_authorization(pjsip_parse_ctx * ctx)268 static pjsip_hdr* parse_hdr_proxy_authorization( pjsip_parse_ctx *ctx )
269 {
270     pjsip_proxy_authorization_hdr *hdr =
271         pjsip_proxy_authorization_hdr_create(ctx->pool);
272     int_parse_hdr_authorization(ctx->scanner, ctx->pool, hdr);
273     return (pjsip_hdr*)hdr;
274 }
275 
parse_hdr_www_authenticate(pjsip_parse_ctx * ctx)276 static pjsip_hdr* parse_hdr_www_authenticate( pjsip_parse_ctx *ctx )
277 {
278     pjsip_www_authenticate_hdr *hdr =
279         pjsip_www_authenticate_hdr_create(ctx->pool);
280     int_parse_hdr_authenticate(ctx->scanner, ctx->pool, hdr);
281     return (pjsip_hdr*)hdr;
282 }
283 
parse_hdr_proxy_authenticate(pjsip_parse_ctx * ctx)284 static pjsip_hdr* parse_hdr_proxy_authenticate( pjsip_parse_ctx *ctx )
285 {
286     pjsip_proxy_authenticate_hdr *hdr =
287         pjsip_proxy_authenticate_hdr_create(ctx->pool);
288     int_parse_hdr_authenticate(ctx->scanner, ctx->pool, hdr);
289     return (pjsip_hdr*)hdr;
290 }
291 
292 
pjsip_auth_init_parser()293 PJ_DEF(pj_status_t) pjsip_auth_init_parser()
294 {
295     pj_status_t status;
296 
297     status = pjsip_register_hdr_parser( "Authorization", NULL,
298                                         &parse_hdr_authorization);
299     PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
300     status = pjsip_register_hdr_parser( "Proxy-Authorization", NULL,
301                                         &parse_hdr_proxy_authorization);
302     PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
303     status = pjsip_register_hdr_parser( "WWW-Authenticate", NULL,
304                                         &parse_hdr_www_authenticate);
305     PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
306     status = pjsip_register_hdr_parser( "Proxy-Authenticate", NULL,
307                                         &parse_hdr_proxy_authenticate);
308     PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
309 
310     return PJ_SUCCESS;
311 }
312 
pjsip_auth_deinit_parser()313 PJ_DEF(void) pjsip_auth_deinit_parser()
314 {
315 }
316 
317