mod_auth_basic_sandbox.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /* Licensed to the Apache Software Foundation (ASF) under one or more
  2. * contributor license agreements. See the NOTICE file distributed with
  3. * this work for additional information regarding copyright ownership.
  4. * The ASF licenses this file to You under the Apache License, Version 2.0
  5. * (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "apr_strings.h"
  17. #include "apr_md5.h" /* for apr_password_validate */
  18. #include "apr_lib.h" /* for apr_isspace */
  19. #include "apr_base64.h" /* for apr_base64_decode et al */
  20. #define APR_WANT_STRFUNC /* for strcasecmp */
  21. #include "apr_want.h"
  22. #include "apr_network_io.h"
  23. #include "ap_config.h"
  24. #include "httpd.h"
  25. #include "http_config.h"
  26. #include "http_core.h"
  27. #include "http_log.h"
  28. #include "http_protocol.h"
  29. #include "http_request.h"
  30. #include "ap_provider.h"
  31. #include "mod_auth.h"
  32. #include "shim_unistd.h"
  33. typedef struct {
  34. authn_provider_list *providers;
  35. char *dir;
  36. int authoritative;
  37. } auth_basic_config_rec;
  38. static void *create_auth_basic_dir_config(apr_pool_t *p, char *d)
  39. {
  40. auth_basic_config_rec *conf = apr_pcalloc(p, sizeof(*conf));
  41. conf->dir = d;
  42. /* Any failures are fatal. */
  43. conf->authoritative = 1;
  44. return conf;
  45. }
  46. static const char *add_authn_provider(cmd_parms *cmd, void *config,
  47. const char *arg)
  48. {
  49. auth_basic_config_rec *conf = (auth_basic_config_rec*)config;
  50. authn_provider_list *newp;
  51. newp = apr_pcalloc(cmd->pool, sizeof(authn_provider_list));
  52. newp->provider_name = arg;
  53. /* lookup and cache the actual provider now */
  54. newp->provider = ap_lookup_provider(AUTHN_PROVIDER_GROUP,
  55. newp->provider_name,
  56. AUTHN_PROVIDER_VERSION);
  57. if (newp->provider == NULL) {
  58. /* by the time they use it, the provider should be loaded and
  59. registered with us. */
  60. return apr_psprintf(cmd->pool,
  61. "Unknown Authn provider: %s",
  62. newp->provider_name);
  63. }
  64. if (!newp->provider->check_password) {
  65. /* if it doesn't provide the appropriate function, reject it */
  66. return apr_psprintf(cmd->pool,
  67. "The '%s' Authn provider doesn't support "
  68. "Basic Authentication", newp->provider_name);
  69. }
  70. /* Add it to the list now. */
  71. if (!conf->providers) {
  72. conf->providers = newp;
  73. }
  74. else {
  75. authn_provider_list *last = conf->providers;
  76. while (last->next) {
  77. last = last->next;
  78. }
  79. last->next = newp;
  80. }
  81. return NULL;
  82. }
  83. static const command_rec auth_basic_cmds[] =
  84. {
  85. AP_INIT_ITERATE("AuthBasicProvider", add_authn_provider, NULL, OR_AUTHCFG,
  86. "specify the auth providers for a directory or location"),
  87. AP_INIT_FLAG("AuthBasicAuthoritative", ap_set_flag_slot,
  88. (void *)APR_OFFSETOF(auth_basic_config_rec, authoritative),
  89. OR_AUTHCFG,
  90. "Set to 'Off' to allow access control to be passed along to "
  91. "lower modules if the UserID is not known to this module"),
  92. {NULL}
  93. };
  94. module AP_MODULE_DECLARE_DATA auth_basic_module;
  95. /* These functions return 0 if client is OK, and proper error status
  96. * if not... either HTTP_UNAUTHORIZED, if we made a check, and it failed, or
  97. * HTTP_INTERNAL_SERVER_ERROR, if things are so totally confused that we
  98. * couldn't figure out how to tell if the client is authorized or not.
  99. *
  100. * If they return DECLINED, and all other modules also decline, that's
  101. * treated by the server core as a configuration error, logged and
  102. * reported as such.
  103. */
  104. static void note_basic_auth_failure(request_rec *r)
  105. {
  106. apr_table_setn(r->err_headers_out,
  107. (PROXYREQ_PROXY == r->proxyreq) ? "Proxy-Authenticate"
  108. : "WWW-Authenticate",
  109. apr_pstrcat(r->pool, "Basic realm=\"", ap_auth_name(r),
  110. "\"", NULL));
  111. }
  112. static int hook_note_basic_auth_failure(request_rec *r, const char *auth_type)
  113. {
  114. if (strcasecmp(auth_type, "Basic"))
  115. return DECLINED;
  116. note_basic_auth_failure(r);
  117. return OK;
  118. }
  119. static int get_basic_auth(request_rec *r, const char **user,
  120. const char **pw)
  121. {
  122. const char *auth_line;
  123. char *decoded_line;
  124. int length;
  125. /* Get the appropriate header */
  126. auth_line = apr_table_get(r->headers_in, (PROXYREQ_PROXY == r->proxyreq)
  127. ? "Proxy-Authorization"
  128. : "Authorization");
  129. if (!auth_line) {
  130. note_basic_auth_failure(r);
  131. return HTTP_UNAUTHORIZED;
  132. }
  133. if (strcasecmp(ap_getword(r->pool, &auth_line, ' '), "Basic")) {
  134. /* Client tried to authenticate using wrong auth scheme */
  135. ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01614)
  136. "client used wrong authentication scheme: %s", r->uri);
  137. note_basic_auth_failure(r);
  138. return HTTP_UNAUTHORIZED;
  139. }
  140. /* Skip leading spaces. */
  141. while (apr_isspace(*auth_line)) {
  142. auth_line++;
  143. }
  144. decoded_line = apr_palloc(r->pool, apr_base64_decode_len(auth_line) + 1);
  145. length = apr_base64_decode(decoded_line, auth_line);
  146. /* Null-terminate the string. */
  147. decoded_line[length] = '\0';
  148. *user = ap_getword_nulls(r->pool, (const char**)&decoded_line, ':');
  149. *pw = decoded_line;
  150. /* set the user, even though the user is unauthenticated at this point */
  151. r->user = (char *) *user;
  152. return OK;
  153. }
  154. /* Determine user ID, and check if it really is that user, for HTTP
  155. * basic authentication...
  156. */
  157. static int authenticate_basic_user(request_rec *r)
  158. {
  159. auth_basic_config_rec *conf = ap_get_module_config(r->per_dir_config,
  160. &auth_basic_module);
  161. const char *sent_user, *sent_pw, *current_auth;
  162. int res;
  163. authn_status auth_result;
  164. authn_provider_list *current_provider;
  165. /* Are we configured to be Basic auth? */
  166. current_auth = ap_auth_type(r);
  167. if (!current_auth || strcasecmp(current_auth, "Basic")) {
  168. return DECLINED;
  169. }
  170. /* We need an authentication realm. */
  171. if (!ap_auth_name(r)) {
  172. ap_log_rerror(APLOG_MARK, APLOG_ERR,
  173. 0, r, APLOGNO(01615) "need AuthName: %s", r->uri);
  174. return HTTP_INTERNAL_SERVER_ERROR;
  175. }
  176. r->ap_auth_type = (char*)current_auth;
  177. res = get_basic_auth(r, &sent_user, &sent_pw);
  178. if (res) {
  179. return res;
  180. }
  181. current_provider = conf->providers;
  182. do {
  183. const authn_provider *provider;
  184. /* For now, if a provider isn't set, we'll be nice and use the file
  185. * provider.
  186. */
  187. if (!current_provider) {
  188. provider = ap_lookup_provider(AUTHN_PROVIDER_GROUP,
  189. AUTHN_DEFAULT_PROVIDER,
  190. AUTHN_PROVIDER_VERSION);
  191. if (!provider || !provider->check_password) {
  192. ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01616)
  193. "No Authn provider configured");
  194. auth_result = AUTH_GENERAL_ERROR;
  195. break;
  196. }
  197. apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, AUTHN_DEFAULT_PROVIDER);
  198. }
  199. else {
  200. provider = current_provider->provider;
  201. apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, current_provider->provider_name);
  202. }
  203. auth_result = provider->check_password(r, sent_user, sent_pw);
  204. apr_table_unset(r->notes, AUTHN_PROVIDER_NAME_NOTE);
  205. /* Something occured. Stop checking. */
  206. if (auth_result != AUTH_USER_NOT_FOUND) {
  207. break;
  208. }
  209. /* If we're not really configured for providers, stop now. */
  210. if (!conf->providers) {
  211. break;
  212. }
  213. current_provider = current_provider->next;
  214. } while (current_provider);
  215. if (auth_result != AUTH_GRANTED) {
  216. int return_code;
  217. /* If we're not authoritative, then any error is ignored. */
  218. if (!(conf->authoritative) && auth_result != AUTH_DENIED) {
  219. return DECLINED;
  220. }
  221. switch (auth_result) {
  222. case AUTH_DENIED:
  223. ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01617)
  224. "user %s: authentication failure for \"%s\": "
  225. "Password Mismatch",
  226. sent_user, r->uri);
  227. return_code = HTTP_UNAUTHORIZED;
  228. break;
  229. case AUTH_USER_NOT_FOUND:
  230. ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01618)
  231. "user %s not found: %s", sent_user, r->uri);
  232. return_code = HTTP_UNAUTHORIZED;
  233. break;
  234. case AUTH_GENERAL_ERROR:
  235. default:
  236. /* We'll assume that the module has already said what its error
  237. * was in the logs.
  238. */
  239. return_code = HTTP_INTERNAL_SERVER_ERROR;
  240. break;
  241. }
  242. /* If we're returning 403, tell them to try again. */
  243. if (return_code == HTTP_UNAUTHORIZED) {
  244. note_basic_auth_failure(r);
  245. }
  246. return return_code;
  247. }
  248. apr_socket_t *conn = ap_get_conn_socket(r->connection);
  249. struct apr_sockaddr_t *l_sa, *r_sa;
  250. apr_socket_addr_get(&l_sa, APR_LOCAL, conn);
  251. apr_socket_addr_get(&r_sa, APR_REMOTE, conn);
  252. struct net_sb net_sb;
  253. struct net_sb_rule net_sb_rule;
  254. net_sb.nrules = 1;
  255. net_sb.rules = &net_sb_rule;
  256. net_sb_rule.l_addrlen = l_sa->ipaddr_len;
  257. net_sb_rule.l_addr = l_sa->ipaddr_ptr;
  258. net_sb_rule.r_addrlen = r_sa->ipaddr_len;
  259. net_sb_rule.r_addr = r_sa->ipaddr_ptr;
  260. if (sandbox_create(SANDBOX_FS|SANDBOX_NET|SANDBOX_RPC,
  261. ap_document_root(r),
  262. &net_sb) < 0)
  263. return HTTP_INTERNAL_SERVER_ERROR;
  264. return OK;
  265. }
  266. static void register_hooks(apr_pool_t *p)
  267. {
  268. ap_hook_check_authn(authenticate_basic_user, NULL, NULL, APR_HOOK_MIDDLE,
  269. AP_AUTH_INTERNAL_PER_CONF);
  270. ap_hook_note_auth_failure(hook_note_basic_auth_failure, NULL, NULL,
  271. APR_HOOK_MIDDLE);
  272. }
  273. AP_DECLARE_MODULE(auth_basic_sandbox) =
  274. {
  275. STANDARD20_MODULE_STUFF,
  276. create_auth_basic_dir_config, /* dir config creater */
  277. NULL, /* dir merger --- default is to override */
  278. NULL, /* server config */
  279. NULL, /* merge server config */
  280. auth_basic_cmds, /* command apr_table_t */
  281. register_hooks /* register hooks */
  282. };