2 * Apache Module for the Sub-authentication Daemon
4 * (c) 2017 Martin Mares <mj@ucw.cz>
8 #include <ucw/mempool.h>
9 #include <ucw/string.h>
10 #include <ucw/trans.h>
11 #include <ucw-json/json.h>
13 #include <ap_config.h>
15 #include <http_config.h>
16 #include <http_core.h>
18 #include <http_request.h>
22 #include <sys/socket.h>
23 #include <sys/types.h>
35 AP_MODULE_DECLARE_DATA extern module authn_subauth_module;
39 struct dir_config *dir;
40 struct json_context *json;
41 struct json_node *reply;
44 static struct json_node *run_command(struct context *ctx, struct json_node *request)
48 int sk = socket(PF_UNIX, SOCK_SEQPACKET, 0);
50 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r, "SubAuth cannot create socket");
54 const char *path = ctx->dir->socket ? : INSTALL_RUN_DIR "/subauthd.socket";
55 struct sockaddr_un sun;
56 sun.sun_family = AF_UNIX;
57 if (strlen(path) >= sizeof(sun.sun_path)) {
58 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r, "SubAuth socket path too long");
61 strcpy(sun.sun_path, path);
63 if (connect(sk, (struct sockaddr *) &sun, sizeof(sun)) < 0) {
64 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r, "SubAuth cannot connect to server at %s", path);
68 struct fastbuf *rq_fb = fbgrow_create(4096);
69 json_write(ctx->json, rq_fb, request);
71 uint rq_len = fbgrow_get_buf(rq_fb, &rq_buf);
72 if (send(sk, rq_buf, rq_len, 0) < 0) {
73 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r, "SubAuth error sending to server");
77 uint rp_bufsize = 16384;
78 byte *rp_buf = xmalloc(rp_bufsize);
79 int rp_len = recv(sk, rp_buf, rp_bufsize, 0);
81 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r, "SubAuth error receiving from server");
86 fbbuf_init_read(&rp_fb, rp_buf, rp_len, 0);
88 struct json_node *reply = NULL;
90 reply = json_parse(ctx->json, &rp_fb);
95 if (reply->type != JSON_OBJECT) {
96 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r, "SubAuth malformed server reply: Top-level node is not an object");
111 static authn_status check_password(request_rec *r, const char *user, const char *password)
113 struct dir_config *dir = ap_get_module_config(r->per_dir_config, &authn_subauth_module);
116 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "SubAuthZone not specified in the configuration");
117 return AUTH_GENERAL_ERROR;
120 authn_status status = AUTH_GENERAL_ERROR;
121 struct context ctx0 = { .r = r, .dir = dir };
122 struct context *ctx = &ctx0;
124 ctx->json = json_new();
125 struct json_node *rq = json_new_object(ctx->json);
126 json_object_set(rq, "cmd", json_new_string(ctx->json, "login"));
127 json_object_set(rq, "zone", json_new_string(ctx->json, dir->zone));
128 json_object_set(rq, "login", json_new_string(ctx->json, user));
129 json_object_set(rq, "passwd", json_new_string(ctx->json, password));
131 struct json_node *rp = run_command(ctx, rq);
134 struct json_node *error = json_object_get(rp, "error");
135 if (!error || error->type != JSON_STRING) {
136 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "SubAuth malformed server reply: No error status found");
139 if (!strcmp(error->string, ""))
140 status = AUTH_GRANTED;
142 status = AUTH_DENIED;
145 json_delete(ctx->json);
149 static const authn_provider authn_subauth_provider = {
151 NULL, // get_realm_hash
155 register_hooks(apr_pool_t *p)
157 ap_register_auth_provider(p,
158 AUTHN_PROVIDER_GROUP,
160 AUTHN_PROVIDER_VERSION,
161 &authn_subauth_provider,
162 AP_AUTH_INTERNAL_PER_CONF);
165 /*** Configuration ***/
168 dir_create_config(apr_pool_t *p, char *dd UNUSED)
170 struct dir_config *dir = apr_pcalloc(p, sizeof(*dir));
175 dir_merge_config(apr_pool_t *p, void *base, void *over)
177 struct dir_config *dir = apr_pcalloc(p, sizeof(*dir));
178 struct dir_config *b = base;
179 struct dir_config *o = over;
180 dir->socket = o->socket ? : b->socket;
181 dir->zone = o->zone ? : b->zone;
186 config_socket(cmd_parms *cmd UNUSED, void *d, const char *arg)
188 struct dir_config *dir = d;
194 config_zone(cmd_parms *cmd UNUSED, void *d, const char *arg)
196 struct dir_config *dir = d;
201 static const command_rec cmds[] = {
202 AP_INIT_TAKE1("SubAuthSocket", config_socket, NULL, OR_AUTHCFG, "socket of subauth daemon"),
203 AP_INIT_TAKE1("SubAuthZone", config_zone, NULL, OR_AUTHCFG, "name of subauth zone"),
209 AP_DECLARE_MODULE(authn_subauth) = {
210 STANDARD20_MODULE_STUFF,
213 NULL, // srv_create_config,
214 NULL, // srv_merge_config,