-
Notifications
You must be signed in to change notification settings - Fork 1
/
auth.c
131 lines (107 loc) · 2.9 KB
/
auth.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include <string.h>
#include <re.h>
#include "http.h"
#include "request.h"
struct realm {
char *realm;
char *nonce;
char *qop;
char *opaque;
char *user;
char *pass;
uint32_t nc;
enum sip_hdrid hdr;
};
static void realm_destructor(void *arg)
{
struct realm *realm = arg;
mem_deref(realm->realm);
mem_deref(realm->nonce);
mem_deref(realm->qop);
mem_deref(realm->opaque);
mem_deref(realm->user);
mem_deref(realm->pass);
}
static int mkdigest(uint8_t *digest, const struct realm *realm,
const char *met, const char *uri, uint64_t cnonce)
{
uint8_t ha1[MD5_SIZE], ha2[MD5_SIZE];
int err;
err = md5_printf(ha1, "%s:%s:%s",
realm->user, realm->realm, realm->pass);
if (err)
return err;
err = md5_printf(ha2, "%s:%s", met, uri);
if (err)
return err;
if (realm->qop)
return md5_printf(digest, "%w:%s:%08x:%016llx:auth:%w",
ha1, sizeof(ha1),
realm->nonce,
realm->nc,
cnonce,
ha2, sizeof(ha2));
else
return md5_printf(digest, "%w:%s:%w",
ha1, sizeof(ha1),
realm->nonce,
ha2, sizeof(ha2));
}
void write_auth(struct request *req, struct mbuf *mb)
{
int err;
struct realm *realm;
uint8_t digest[MD5_SIZE];
uint64_t cnonce;
if(!req->auth)
return;
realm = req->auth;
cnonce = rand_u64();
err = mkdigest(digest, realm, req->meth, req->path, cnonce);
err |= mbuf_write_str(mb, "Authorization: ");
err |= mbuf_printf(mb, "Digest username=\"%s\"", realm->user);
err |= mbuf_printf(mb, ", realm=\"%s\"", realm->realm);
err |= mbuf_printf(mb, ", nonce=\"%s\"", realm->nonce);
err |= mbuf_printf(mb, ", uri=\"%s\"", req->path);
err |= mbuf_printf(mb, ", response=\"%w\"",
digest, sizeof(digest));
if (realm->opaque)
err |= mbuf_printf(mb, ", opaque=\"%s\"", realm->opaque);
if (realm->qop) {
err |= mbuf_printf(mb, ", cnonce=\"%016llx\"", cnonce);
err |= mbuf_write_str(mb, ", qop=auth");
err |= mbuf_printf(mb, ", nc=%08x", realm->nc);
}
++realm->nc;
err |= mbuf_write_str(mb, "\r\n");
}
int http_auth(struct request *old, struct request **new, char* user, char*password)
{
int ok;
struct request *req;
struct httpauth_digest_chall ch;
struct realm* realm;
re_printf("auth %r\n", &old->www_auth);
if(old->retry)
return -EACCES;
ok = httpauth_digest_challenge_decode(&ch, &old->www_auth);
if(ok!=0)
return ok;
if (pl_isset(&ch.algorithm) && pl_strcasecmp(&ch.algorithm, "md5")) {
ok = ENOSYS;
goto out;
}
realm = mem_zalloc(sizeof(*realm), realm_destructor);
ok = pl_strdup(&realm->realm, &ch.realm);
str_dup(&realm->user, user);
str_dup(&realm->pass, password);
ok = pl_strdup(&realm->nonce, &ch.nonce);
http_clone(&req, old);
req->auth = realm;
req->retry = old->retry +1;
re_printf("resend after auth %d\n", req->retry);
*new = req;
return 0;
out:
return ok;
}