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