9eb8f857bc4c264649025477df9c95dabbf07ad6
[sip-router] / parser / digest / digest.c
1 /*
2  * $Id$
3  *
4  * Digest credentials parser interface
5  */
6
7 #include "digest.h"
8 #include "../../mem/mem.h"  /* pkg_malloc */
9 #include "../../dprint.h"   /* Guess what */
10 #include <stdio.h>          /* printf */
11
12
13 /*
14  * Create and initialize a new credentials structure
15  */
16 static inline int new_credentials(struct hdr_field* _h)
17 {
18         auth_body_t* b;
19
20         b = (auth_body_t*)pkg_malloc(sizeof(auth_body_t));
21         if (b == 0) {
22                 LOG(L_ERR, "parse_credentials(): No memory left\n");
23                 return -2;
24         }
25                 
26         init_dig_cred(&(b->digest));
27         b->stale = 0;
28         b->nonce_retries = 0;
29         b->authorized = 0;
30
31         _h->parsed = (void*)b;
32
33         return 0;
34 }
35
36
37 /*
38  * Parse digest credentials
39  */
40 int parse_credentials(struct hdr_field* _h)
41 {
42         int res;
43
44         if (_h->parsed) {
45                 return 0;  /* Already parsed */
46         }
47
48         if (new_credentials(_h) < 0) {
49                 LOG(L_ERR, "parse_credentials(): Can't create new credentials\n");
50                 return -1;
51         }
52
53         res = parse_digest_cred(&(_h->body), &(((auth_body_t*)(_h->parsed))->digest));
54         
55         if (res != 0) {
56                 free_credentials((auth_body_t**)&(_h->parsed));
57         }
58
59         return res;
60 }
61
62
63 /*
64  * Free all memory
65  */
66 void free_credentials(auth_body_t** _b)
67 {
68         pkg_free(*_b);
69         *_b = 0;
70 }
71
72
73 /*
74  * Check semantics of a digest credentials structure
75  * Make sure that all attributes needed to verify response 
76  * string are set or at least have a default value
77  *
78  * The returned value is logical OR of all errors encountered
79  * during the check, see dig_err_t type for more details 
80  */
81 dig_err_t check_dig_cred(dig_cred_t* _c)
82 {
83         dig_err_t res = E_DIG_OK;
84
85              /* Username must be present */
86         if (_c->username.s == 0) res |= E_DIG_USERNAME;
87
88              /* Realm must be present */
89         if (_c->realm.s == 0) res |= E_DIG_REALM;
90
91              /* Nonce that was used must be specified */
92         if (_c->nonce.s == 0) res |= E_DIG_NONCE;
93
94              /* URI must be specified */
95         if (_c->uri.s == 0) res |= E_DIG_URI;
96
97              /* We cannot check credentials without response */
98         if (_c->response.s == 0) res |= E_DIG_RESPONSE;
99
100              /* If QOP parameter is present, some additional
101               * requirements must be met
102               */
103         if ((_c->qop.qop_parsed == QOP_AUTH) || (_c->qop.qop_parsed == QOP_AUTHINT)) {
104                      /* CNONCE must be specified */
105                 if (_c->cnonce.s == 0) res |= E_DIG_CNONCE;
106                      /* and also nonce count must be specified */
107                 if (_c->nc.s == 0) res |= E_DIG_NC;
108         }
109                 
110         return res;     
111 }
112
113
114 /*
115  * Print credential structure content to stdout
116  * Just for debugging
117  */
118 void print_cred(dig_cred_t* _c)
119 {
120         printf("===Digest credentials===\n");
121         if (_c) {
122                 printf("Username  = \'%.*s\'\n", _c->username.len, _c->username.s);
123                 printf("Realm     = \'%.*s\'\n", _c->realm.len, _c->realm.s);
124                 printf("Nonce     = \'%.*s\'\n", _c->nonce.len, _c->nonce.s);
125                 printf("URI       = \'%.*s\'\n", _c->uri.len, _c->uri.s);
126                 printf("Response  = \'%.*s\'\n", _c->response.len, _c->response.s);
127                 printf("Algorithm = \'%.*s\'\n", _c->alg.alg_str.len, _c->alg.alg_str.s);
128                 printf("\\--parsed = ");
129
130                 switch(_c->alg.alg_parsed) {
131                 case ALG_UNSPEC:  printf("ALG_UNSPEC\n");  break;
132                 case ALG_MD5:     printf("ALG_MD5\n");     break;
133                 case ALG_MD5SESS: printf("ALG_MD5SESS\n"); break;
134                 case ALG_OTHER:   printf("ALG_OTHER\n");   break;
135                 }
136
137                 printf("Cnonce    = \'%.*s\'\n", _c->cnonce.len, _c->cnonce.s);
138                 printf("Opaque    = \'%.*s\'\n", _c->opaque.len, _c->opaque.s);
139                 printf("QOP       = \'%.*s\'\n", _c->qop.qop_str.len, _c->qop.qop_str.s);
140                 printf("\\--parsed = ");
141
142                 switch(_c->qop.qop_parsed) {
143                 case QOP_UNSPEC:  printf("QOP_UNSPEC\n");  break;
144                 case QOP_AUTH:    printf("QOP_AUTH\n");    break;
145                 case QOP_AUTHINT: printf("QOP_AUTHINT\n"); break;
146                 case QOP_OTHER:   printf("QOP_OTHER\n");   break;
147                 }
148                 printf("NC        = \'%.*s\'\n", _c->nc.len, _c->nc.s);
149         }
150         printf("===/Digest credentials===\n");
151 }
152
153
154 /*
155  * Mark credentials as selected so functions
156  * following authorize know which credentials
157  * to use if the message contained more than
158  * one
159  */
160 int mark_authorized_cred(struct sip_msg* _m, struct hdr_field* _h)
161 {
162         struct hdr_field* f;
163         
164         switch(_h->type) {
165         case HDR_AUTHORIZATION: f = _m->authorization; break;
166         case HDR_PROXYAUTH:     f = _m->proxy_auth;    break;
167         default:
168                 LOG(L_ERR, "mark_authorized_cred(): Invalid header field type\n");
169                 return -1;
170         }
171
172         if (!(f->parsed)) {
173                 if (new_credentials(f) < 0) {
174                         LOG(L_ERR, "mark_authorized_cred(): Error in new_credentials\n");
175                         return -1;
176                 }
177         }
178
179         ((auth_body_t*)(f->parsed))->authorized = _h;
180
181         return 0;
182 }
183
184
185 /*
186  * Get pointer to authorized credentials, if there are no
187  * authorized credentials, 0 is returned
188  */
189 int get_authorized_cred(struct hdr_field* _f, struct hdr_field** _h)
190 {
191         if (_f && _f->parsed) {
192                 *_h = ((auth_body_t*)(_f->parsed))->authorized;
193         } else {
194                 *_h = 0;
195         }
196         
197         return 0;
198 }