1 /**
2 * @file sip/domain.c Mock SIP server -- domain handling
3 *
4 * Copyright (C) 2010 - 2016 Creytiv.com
5 */
6 #include <re.h>
7 #include "sipsrv.h"
8
9
10 #define DEBUG_MODULE "mock/sipsrv"
11 #define DEBUG_LEVEL 5
12 #include <re_dbg.h>
13
14
15 enum {
16 NONCE_EXPIRES = 300,
17 };
18
19
destructor(void * arg)20 static void destructor(void *arg)
21 {
22 struct domain *dom = arg;
23
24 hash_unlink(&dom->he);
25 hash_flush(dom->ht_usr);
26 mem_deref(dom->ht_usr);
27 mem_deref(dom->name);
28 }
29
30
lookup(struct sip_server * srv,const struct pl * name)31 static struct domain *lookup(struct sip_server *srv, const struct pl *name)
32 {
33 struct list *lst;
34 struct le *le;
35
36 lst = hash_list(srv->ht_dom, hash_joaat_ci(name->p, name->l));
37
38 for (le=list_head(lst); le; le=le->next) {
39
40 struct domain *dom = le->data;
41
42 if (pl_strcasecmp(name, dom->name))
43 continue;
44
45 return dom;
46 }
47
48 return NULL;
49 }
50
51
domain_add(struct sip_server * srv,const char * name)52 int domain_add(struct sip_server *srv, const char *name)
53 {
54 struct domain *dom;
55 int err;
56
57 dom = mem_zalloc(sizeof(*dom), destructor);
58 if (!dom)
59 return ENOMEM;
60
61 err = str_dup(&dom->name, name);
62 if (err)
63 goto out;
64
65 err = hash_alloc(&dom->ht_usr, 32);
66 if (err)
67 return err;
68
69 hash_append(srv->ht_dom, hash_joaat_str_ci(name), &dom->he, dom);
70
71 out:
72 if (err)
73 mem_deref(dom);
74
75 return err;
76 }
77
78
domain_find(struct sip_server * srv,const struct uri * uri)79 int domain_find(struct sip_server *srv, const struct uri *uri)
80 {
81 int err = ENOENT;
82 struct sa addr;
83
84 if (!uri)
85 return EINVAL;
86
87 if (!sa_set(&addr, &uri->host, uri->port)) {
88
89 if (!uri->port) {
90
91 uint16_t port = SIP_PORT;
92
93 if (!pl_strcasecmp(&uri->scheme, "sips"))
94 port = SIP_PORT_TLS;
95
96 sa_set_port(&addr, port);
97 }
98
99 if (sip_transp_isladdr(srv->sip, SIP_TRANSP_NONE, &addr))
100 return 0;
101
102 return ENOENT;
103 }
104
105 err = lookup(srv, &uri->host) ? 0 : ENOENT;
106
107 return err;
108 }
109
110
domain_auth(struct sip_server * srv,const struct uri * uri,bool user_match,const struct sip_msg * msg,enum sip_hdrid hdrid,struct auth * auth)111 int domain_auth(struct sip_server *srv,
112 const struct uri *uri, bool user_match,
113 const struct sip_msg *msg, enum sip_hdrid hdrid,
114 struct auth *auth)
115 {
116 struct domain *dom;
117 struct list *lst;
118 struct le *le;
119 int err = ENOENT;
120
121 if (!uri || !msg || !auth)
122 return EINVAL;
123
124 dom = lookup(srv, &uri->host);
125 if (!dom) {
126 DEBUG_WARNING("domain not found (%r)\n", &uri->host);
127 return ENOENT;
128 }
129
130 err = auth_set_realm(auth, dom->name);
131 if (err)
132 return err;
133
134 auth->stale = false;
135
136 lst = hash_list(msg->hdrht, hdrid);
137
138 for (le=list_head(lst); le; le=le->next) {
139
140 const struct sip_hdr *hdr = le->data;
141 struct httpauth_digest_resp resp;
142 const struct user *usr;
143
144 if (hdr->id != hdrid)
145 continue;
146
147 if (httpauth_digest_response_decode(&resp, &hdr->val))
148 continue;
149
150 if (pl_strcasecmp(&resp.realm, dom->name))
151 continue;
152
153 if (auth_chk_nonce(srv, &resp.nonce, NONCE_EXPIRES)) {
154 auth->stale = true;
155 continue;
156 }
157
158 auth->stale = false;
159
160 usr = user_find(dom->ht_usr, &resp.username);
161 if (!usr) {
162 DEBUG_WARNING("user not found (%r)\n", &resp.username);
163 break;
164 }
165
166 err = httpauth_digest_response_auth(&resp, &msg->met,
167 user_ha1(usr));
168 if (err)
169 return err;
170
171 if (user_match && pl_cmp(&resp.username, &uri->user))
172 return EPERM;
173
174 return 0;
175 }
176
177 return EAUTH;
178 }
179
180
domain_lookup(struct sip_server * srv,const char * name)181 struct domain *domain_lookup(struct sip_server *srv, const char *name)
182 {
183 struct pl pl;
184
185 pl_set_str(&pl, name);
186
187 return lookup(srv, &pl);
188 }
189