From: Martin Mares Date: Sun, 23 Jul 2017 16:09:54 +0000 (+0200) Subject: PAM module X-Git-Tag: v0.9~34 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=c59bb6140af69010824c6ddbf5ad21350fb80eb8;p=subauth.git PAM module --- diff --git a/Makefile b/Makefile index d538520..830d7ec 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,7 @@ LIBS+=$(LIBUCW_LIBS) $(LIBUCW_JSON_LIBS) include $(s)/server/Makefile include $(s)/client/Makefile +include $(s)/pam/Makefile # And finally the default rules of the build system include $(BUILDSYS)/Makebottom diff --git a/pam/Makefile b/pam/Makefile new file mode 100644 index 0000000..06e68ad --- /dev/null +++ b/pam/Makefile @@ -0,0 +1,6 @@ +DIRS+=pam + +PROGS+=$(o)/pam/pam_subauth.so + +$(o)/pam/pam_subauth.so: $(o)/pam/pam_subauth.oo +$(o)/pam/pam_subauth.so: LIBS+=-lpam diff --git a/pam/pam_subauth.c b/pam/pam_subauth.c new file mode 100644 index 0000000..dd9340e --- /dev/null +++ b/pam/pam_subauth.c @@ -0,0 +1,212 @@ +/* + * Sub-authentication Client + * + * (c) 2017 Martin Mares + */ + +// FIXME: Includes + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "autoconf.h" + +#define PAM_SM_AUTH +#include +#include + +struct context { + pam_handle_t *pamh; + int debug; + int use_first_pass; + const char *socket_path; + const char *zone; + const char *user; + const char *passwd; + struct mempool *pool; + struct json_context *json; + struct json_node *reply; +}; + +static struct json_node *run_command(struct context *ctx, struct json_node *request) +{ + ctx->reply = NULL; + + int sk = socket(PF_UNIX, SOCK_SEQPACKET, 0); + if (sk < 0) + { + pam_syslog(ctx->pamh, LOG_ERR, "socket(PF_UNIX, SOCK_SEQPACKET): %m"); + return NULL; + } + + struct sockaddr_un sun; + sun.sun_family = AF_UNIX; + if (strlen(ctx->socket_path) >= sizeof(sun.sun_path)) + { + pam_syslog(ctx->pamh, LOG_ERR, "Socket path too long"); + goto fail1; + } + strcpy(sun.sun_path, ctx->socket_path); + + if (connect(sk, (struct sockaddr *) &sun, sizeof(sun)) < 0) + { + pam_syslog(ctx->pamh, LOG_ERR, "Cannot connect to %s: %m", ctx->socket_path); + goto fail1; + } + + struct fastbuf *rq_fb = fbgrow_create(4096); + json_write(ctx->json, rq_fb, request); + byte *rq_buf; + uint rq_len = fbgrow_get_buf(rq_fb, &rq_buf); + if (send(sk, rq_buf, rq_len, 0) < 0) + { + pam_syslog(ctx->pamh, LOG_ERR, "Cannot send request: %m"); + goto fail2; + } + + uint rp_bufsize = 16384; + byte *rp_buf = xmalloc(rp_bufsize); + int rp_len = recv(sk, rp_buf, rp_bufsize, 0); + if (rp_len < 0) + { + pam_syslog(ctx->pamh, LOG_ERR, "Cannot receive reply: %m"); + goto fail3; + } + + struct fastbuf rp_fb; + fbbuf_init_read(&rp_fb, rp_buf, rp_len, 0); + + TRANS_TRY + { + ctx->reply = json_parse(ctx->json, &rp_fb); + } + TRANS_CATCH(x) + { + goto fail3; + } + TRANS_END; + + if (ctx->reply->type != JSON_OBJECT) + { + pam_syslog(ctx->pamh, LOG_ERR, "Malformed reply: Top-level node is not an object"); + goto fail3; + } + +fail3: + free(rp_buf); +fail2: + bclose(rq_fb); +fail1: + close(sk); + return ctx->reply; +} + +static bool check_auth(struct context *ctx) +{ + bool ok = 0; + + ctx->json = json_new(); + struct json_node *rq = json_new_object(ctx->json); + json_object_set(rq, "cmd", json_new_string(ctx->json, "login")); + json_object_set(rq, "zone", json_new_string(ctx->json, ctx->zone)); + json_object_set(rq, "login", json_new_string(ctx->json, ctx->user)); + json_object_set(rq, "passwd", json_new_string(ctx->json, ctx->passwd)); + + struct json_node *rp = run_command(ctx, rq); + if (!rp) + goto done; + struct json_node *error = json_object_get(rp, "error"); + if (!error || error->type != JSON_STRING) + { + pam_syslog(ctx->pamh, LOG_ERR, "Malformed reply: No error status found"); + goto done; + } + if (!strcmp(error->string, "")) + ok = 1; + else if (ctx->debug) + pam_syslog(ctx->pamh, LOG_DEBUG, "Server returned error: %s", error->string); + +done: + json_delete(ctx->json); + return ok; +} + +int pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED, int argc, const char **argv) +{ + struct context ctx = { + .pamh = pamh, + .debug = 0, + .use_first_pass = 0, + .socket_path = INSTALL_RUN_DIR "/subauthd.socket", + .zone = "default", + .pool = mp_new(4096), + }; + + // Parse arguments + for (int i=0; i