link against libcrypt
[project/uhttpd.git] / auth.c
1 /*
2  * uhttpd - Tiny single-threaded httpd
3  *
4  *   Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org>
5  *   Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
6  *
7  *  Licensed under the Apache License, Version 2.0 (the "License");
8  *  you may not use this file except in compliance with the License.
9  *  You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *  Unless required by applicable law or agreed to in writing, software
14  *  distributed under the License is distributed on an "AS IS" BASIS,
15  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *  See the License for the specific language governing permissions and
17  *  limitations under the License.
18  */
19
20 #define _GNU_SOURCE
21 #define _XOPEN_SOURCE   700
22 #include "uhttpd.h"
23
24 static LIST_HEAD(auth_realms);
25
26 void uh_auth_add(const char *path, const char *user, const char *pass)
27 {
28         struct auth_realm *new = NULL;
29         struct passwd *pwd;
30         const char *new_pass = NULL;
31         char *dest_path, *dest_user, *dest_pass;
32
33 #ifdef HAVE_SHADOW
34         struct spwd *spwd;
35 #endif
36
37         /* given password refers to a passwd entry */
38         if ((strlen(pass) > 3) && !strncmp(pass, "$p$", 3)) {
39 #ifdef HAVE_SHADOW
40                 /* try to resolve shadow entry */
41                 spwd = getspnam(&pass[3]);
42                 if (spwd)
43                         new_pass = spwd->sp_pwdp;
44 #endif
45                 if (!new_pass) {
46                         pwd = getpwnam(&pass[3]);
47                         if (pwd && pwd->pw_passwd && pwd->pw_passwd[0] &&
48                             pwd->pw_passwd[0] != '!')
49                                 new_pass = pwd->pw_passwd;
50                 }
51         } else {
52                 new_pass = pass;
53         }
54
55         if (!new_pass || !new_pass[0])
56                 return;
57
58         new = calloc_a(sizeof(*new),
59                 &dest_path, strlen(path) + 1,
60                 &dest_user, strlen(user) + 1,
61                 &dest_pass, strlen(new_pass) + 1);
62
63         if (!new)
64                 return;
65
66         new->path = strcpy(dest_path, path);
67         new->user = strcpy(dest_user, user);
68         new->pass = strcpy(dest_pass, new_pass);
69         list_add(&new->list, &auth_realms);
70 }
71
72 bool uh_auth_check(struct client *cl, struct path_info *pi)
73 {
74         struct http_request *req = &cl->request;
75         struct auth_realm *realm;
76         bool user_match = false;
77         char *user = NULL;
78         char *pass = NULL;
79         int plen;
80
81         if (pi->auth && !strncasecmp(pi->auth, "Basic ", 6)) {
82                 const char *auth = pi->auth + 6;
83
84                 uh_b64decode(uh_buf, sizeof(uh_buf), auth, strlen(auth));
85                 pass = strchr(uh_buf, ':');
86                 if (pass) {
87                         user = uh_buf;
88                         *pass++ = 0;
89                 }
90         }
91
92         req->realm = NULL;
93         plen = strlen(pi->name);
94         list_for_each_entry(realm, &auth_realms, list) {
95                 int rlen = strlen(realm->path);
96
97                 if (plen < rlen)
98                         continue;
99
100                 if (strncasecmp(pi->name, realm->path, rlen) != 0)
101                         continue;
102
103                 req->realm = realm;
104                 if (!user)
105                         break;
106
107                 if (strcmp(user, realm->user) != 0)
108                         continue;
109
110                 user_match = true;
111                 break;
112         }
113
114         if (!req->realm)
115                 return true;
116
117         if (user_match && !strcmp(crypt(pass, realm->pass), realm->pass))
118                 return true;
119
120         uh_http_header(cl, 401, "Authorization Required");
121         ustream_printf(cl->us,
122                                   "WWW-Authenticate: Basic realm=\"%s\"\r\n"
123                                   "Content-Type: text/plain\r\n\r\n",
124                                   conf.realm);
125         uh_chunk_printf(cl, "Authorization Required\n");
126         uh_request_done(cl);
127
128         return false;
129 }