ref: 3e05a1d462b44a519621901be94566e9300eca93
parent: b181d62f485e617f54518a8e875b1a30bef02e54
author: Jacob Moody <moody@posixcafe.org>
date: Sat Jul 3 16:33:09 EDT 2021
Add pam module Default to compiling code as PIC. Split up cpu.c to make it a bit easier to use partial code from it. Add pam.c and pam_p9.so make target.
--- a/Make.config
+++ b/Make.config
@@ -1,7 +1,7 @@
AR=ar
RANLIB=ranlib
CC=gcc
-CFLAGS=-Wall -Wno-missing-braces -Wno-parentheses -ggdb -I$(ROOT) -I$(ROOT)/include -c -D_THREAD_SAFE -O2
+CFLAGS=-Wall -Wno-missing-braces -Wno-parentheses -ggdb -I$(ROOT) -I$(ROOT)/include -c -D_THREAD_SAFE -O2 -fPIC
O=o
LDADD=
TARG=tlsclient
--- a/Makefile
+++ b/Makefile
@@ -8,18 +8,27 @@
libc/libc.a\
libsec/libsec.a\
-OFILES=cpu.$O
+OFILES=cpu.$O p9any.$O
default: $(TARG)
$(TARG): $(LIBS) $(OFILES)
$(CC) `pkg-config openssl --libs` $(LDFLAGS) -o $(TARG) $(OFILES) $(LIBS) $(LDADD)
+pam_p9.so: $(LIBS) p9any.$O pam.$O
+ $(CC) -shared -o pam_p9.so p9any.$O pam.$O $(LIBS)
+
cpu.$O: cpu.c
$(CC) `pkg-config openssl --cflags` $(CFLAGS) cpu.c -o cpu.o
+p9any.$O: p9any.c
+ $(CC) $(CFLAGS) p9any.c -o p9any.o
+
+pam.$O: pam.c
+ $(CC) $(CFLAGS) pam.c -o pam.o
+
.PHONY: clean
clean:
- rm -f *.o */*.o */*.a *.a $(TARG)
+ rm -f *.o */*.o */*.a *.a $(TARG) pam_p9.so
.PHONY: libauthsrv/libauthsrv.a
libauthsrv/libauthsrv.a:
--- a/README
+++ b/README
@@ -1,10 +1,15 @@
tlsclient: tlsclient(1) for unix
-This repo contains three programs, tlsclient itself, 9cpu and git-remote-hjgit.
-9cpu acts as rcpu(1).
-Git-remote-hjgit is a git remote helper for unix git that allows use of hjgit repos.
+This repo contains:
+ 9cpu: rcpu(1) on unix
+ tlsclient: tlsclient(1) on unix
+ git-remote-hjgit: git remote helper for using hjgit repos.
+ pam_p9.so: A pam module that authenticates against a 9front auth server.
Most of the tlsclient code is pillaged from jsdrawterm: https://github.com/aiju/jsdrawterm
+The main difference between tlsclient and drawterm is that tlsclient has stripped out the
+plan9 kernel that runs in userspace. This means we use openssl for TLS and and don't provide
+things like /mnt/term, but gain some more flexibility.
Usage:
tlsclient [ -R ] [ -u user] [ -h host ] [ -a auth ] -p port cmd...
@@ -15,6 +20,3 @@
# with git-remote-hjgit in your $PATH
git clone hjgit://shithub.us/user/repo
-
-Bugs:
- Currently tlsclient uses gnutls, a better alternative is welcome.
--- a/cpu.c
+++ b/cpu.c
@@ -2,18 +2,12 @@
* cpu.c - Make a connection to a cpu server
*/
#include <stdio.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <arpa/inet.h>
-#include <netdb.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
-#include <netinet/in.h>
#include <openssl/ssl.h>
-#include <openssl/err.h>
#include <u.h>
#include <args.h>
@@ -22,15 +16,12 @@
#include <authsrv.h>
#include <libsec.h>
-static AuthInfo *p9any(int);
-static int getkey(Authkey*, char*, char*, char*, char*);
-static int p9authtls(int);
+#include "fncs.h"
char *argv0;
-static char *host;
char *authserver;
-char *user, *pass;
+static char *user, *pass;
SSL_CTX *ssl_ctx;
SSL *ssl_conn;
@@ -51,39 +42,23 @@
return nsecret;
}
-void errstr(char *s){}
-
-int
-unix_dial(char *host, char *port)
+/*
+ * p9any authentication followed by tls-psk encryption
+ */
+static int
+p9authtls(int fd)
{
- int fd;
- struct sockaddr_in server;
- struct hostent *he;
- struct in_addr **addr_list;
+ ai = p9any(user, pass, fd);
+ if(ai == nil)
+ sysfatal("can't authenticate");
- he = gethostbyname(host);
- if(he == nil){
- sysfatal("could not resolve %s", host);
- }
- fd = socket(AF_INET, SOCK_STREAM, 0);
- addr_list = (struct in_addr **) he->h_addr_list;
- server.sin_addr.s_addr = inet_addr(inet_ntoa(*addr_list[0]));
- server.sin_family = AF_INET;
- server.sin_port = htons(atoi(port));
- if(connect(fd, (struct sockaddr*)&server, sizeof(server)) < 0)
- return -1;
+ SSL_set_fd(ssl_conn, fd);
+ if(SSL_connect(ssl_conn) < 0)
+ sysfatal("ssl could not connect");
+
return fd;
}
-char*
-estrdup(char *s)
-{
- s = strdup(s);
- if(s == nil)
- sysfatal("out of memory");
- return s;
-}
-
typedef size_t (*iofunc)(int, void*, size_t);
size_t tls_send(int f, void *b, size_t n) { return SSL_write(ssl_conn, b, n); }
size_t tls_recv(int f, void *b, size_t n) { return SSL_read(ssl_conn, b, n); }
@@ -114,11 +89,12 @@
main(int argc, char **argv)
{
int Rflag;
- int fd, res;
+ int fd;
char buf2[1024];
char buf[1024];
size_t n;
char *port;
+ char *host;
int pin[2];
int pout[2];
int infd, outfd;
@@ -161,8 +137,6 @@
sysfatal("could not init openssl");
ssl_conn = SSL_new(ssl_ctx);
-
-
if(*argv && !Rflag){
pipe(pin);
pipe(pout);
@@ -220,292 +194,3 @@
kill(execc, SIGTERM);
}
-int
-readstr(int fd, char *str, int len)
-{
- int n;
-
- while(len) {
- n = read(fd, str, 1);
- if(n < 0)
- return -1;
- if(*str == '\0')
- return 0;
- str++;
- len--;
- }
- return -1;
-}
-
-/*
- * p9any authentication followed by tls-psk encryption
- */
-static int
-p9authtls(int fd)
-{
- ai = p9any(fd);
- if(ai == nil)
- sysfatal("can't authenticate: %r");
-
- SSL_set_fd(ssl_conn, fd);
- if(SSL_connect(ssl_conn) < 0)
- sysfatal("ssl could not connect");
-
- return fd;
-}
-
-int
-authdial(char *net, char *dom)
-{
- return unix_dial(authserver, "567");
-}
-
-static int
-getastickets(Authkey *key, Ticketreq *tr, uchar *y, char *tbuf, int tbuflen)
-{
- int asfd, rv;
- char *dom;
-
- dom = tr->authdom;
- asfd = authdial(nil, dom);
- if(asfd < 0)
- return -1;
- if(y != nil){
- PAKpriv p;
-
- rv = -1;
- tr->type = AuthPAK;
- if(_asrequest(asfd, tr) != 0 || write(asfd, y, PAKYLEN) != PAKYLEN)
- goto Out;
-
- authpak_new(&p, key, (uchar*)tbuf, 1);
- if(write(asfd, tbuf, PAKYLEN) != PAKYLEN)
- goto Out;
-
- if(_asrdresp(asfd, tbuf, 2*PAKYLEN) != 2*PAKYLEN)
- goto Out;
-
- memmove(y, tbuf, PAKYLEN);
- if(authpak_finish(&p, key, (uchar*)tbuf+PAKYLEN))
- goto Out;
- }
- tr->type = AuthTreq;
- rv = _asgetticket(asfd, tr, tbuf, tbuflen);
-Out:
- close(asfd);
- return rv;
-}
-
-static int
-mkservertickets(Authkey *key, Ticketreq *tr, uchar *y, char *tbuf, int tbuflen)
-{
- Ticket t;
- int ret;
-
- if(strcmp(tr->authid, tr->hostid) != 0)
- return -1;
- memset(&t, 0, sizeof(t));
- ret = 0;
- if(y != nil){
- PAKpriv p;
-
- t.form = 1;
- memmove(tbuf, y, PAKYLEN);
- authpak_new(&p, key, y, 0);
- authpak_finish(&p, key, (uchar*)tbuf);
- }
- memmove(t.chal, tr->chal, CHALLEN);
- strcpy(t.cuid, tr->uid);
- strcpy(t.suid, tr->uid);
- genrandom((uchar*)t.key, sizeof(t.key));
- t.num = AuthTc;
- ret += convT2M(&t, tbuf+ret, tbuflen-ret, key);
- t.num = AuthTs;
- ret += convT2M(&t, tbuf+ret, tbuflen-ret, key);
- memset(&t, 0, sizeof(t));
-
- return ret;
-}
-
-static int
-gettickets(Authkey *key, Ticketreq *tr, uchar *y, char *tbuf, int tbuflen)
-{
- int ret;
- ret = getastickets(key, tr, y, tbuf, tbuflen);
- if(ret > 0)
- return ret;
- return mkservertickets(key, tr, y, tbuf, tbuflen);
-}
-
-AuthInfo*
-p9any(int fd)
-{
- char buf[1024], buf2[1024], *bbuf, *p, *proto, *dom;
- uchar crand[2*NONCELEN], cchal[CHALLEN], y[PAKYLEN];
- char tbuf[2*MAXTICKETLEN+MAXAUTHENTLEN+PAKYLEN], trbuf[TICKREQLEN+PAKYLEN];
- Authkey authkey;
- Authenticator auth;
- int i, n, m, v2, dp9ik;
- Ticketreq tr;
- Ticket t;
- AuthInfo *ai;
-
- if(readstr(fd, buf, sizeof buf) < 0)
- sysfatal("cannot read p9any negotiation: %r");
- bbuf = buf;
- v2 = 0;
- if(strncmp(buf, "v.2 ", 4) == 0){
- v2 = 1;
- bbuf += 4;
- }
- dp9ik = 0;
- proto = nil;
- while(bbuf != nil){
- if((p = strchr(bbuf, ' ')))
- *p++ = 0;
- if((dom = strchr(bbuf, '@')) == nil)
- sysfatal("bad p9any domain");
- *dom++ = 0;
- if(strcmp(bbuf, "p9sk1") == 0 || strcmp(bbuf, "dp9ik") == 0){
- proto = bbuf;
- if(strcmp(proto, "dp9ik") == 0){
- dp9ik = 1;
- break;
- }
- }
- bbuf = p;
- }
- if(proto == nil)
- sysfatal("server did not offer p9sk1 or dp9ik");
- proto = estrdup(proto);
- sprint(buf2, "%s %s", proto, dom);
- if(write(fd, buf2, strlen(buf2)+1) != strlen(buf2)+1)
- sysfatal("cannot write user/domain choice in p9any");
- if(v2){
- if(readstr(fd, buf, sizeof buf) < 0)
- sysfatal("cannot read OK in p9any: %r");
- if(memcmp(buf, "OK\0", 3) != 0)
- sysfatal("did not get OK in p9any: got %s", buf);
- }
- genrandom(crand, 2*NONCELEN);
- genrandom(cchal, CHALLEN);
- if(write(fd, cchal, CHALLEN) != CHALLEN)
- sysfatal("cannot write p9sk1 challenge: %r");
-
- n = TICKREQLEN;
- if(dp9ik)
- n += PAKYLEN;
-
- if(readn(fd, trbuf, n) != n || convM2TR(trbuf, TICKREQLEN, &tr) <= 0)
- sysfatal("cannot read ticket request in p9sk1: %r");
-
-again:
- if(!getkey(&authkey, user, tr.authdom, proto, pass))
- sysfatal("no password");
-
- strecpy(tr.hostid, tr.hostid+sizeof tr.hostid, user);
- strecpy(tr.uid, tr.uid+sizeof tr.uid, user);
-
- if(dp9ik){
- memmove(y, trbuf+TICKREQLEN, PAKYLEN);
- n = gettickets(&authkey, &tr, y, tbuf, sizeof(tbuf));
- } else {
- n = gettickets(&authkey, &tr, nil, tbuf, sizeof(tbuf));
- }
- if(n <= 0)
- sysfatal("cannot get auth tickets in p9sk1: %r");
-
- m = convM2T(tbuf, n, &t, &authkey);
- if(m <= 0 || t.num != AuthTc){
- print("?password mismatch with auth server\n");
- if(pass != nil && *pass)
- sysfatal("wrong password");
- goto again;
- }
- n -= m;
- memmove(tbuf, tbuf+m, n);
-
- if(dp9ik && write(fd, y, PAKYLEN) != PAKYLEN)
- sysfatal("cannot send authpak public key back: %r");
-
- auth.num = AuthAc;
- memmove(auth.rand, crand, NONCELEN);
- memmove(auth.chal, tr.chal, CHALLEN);
- m = convA2M(&auth, tbuf+n, sizeof(tbuf)-n, &t);
- n += m;
-
- if(write(fd, tbuf, n) != n)
- sysfatal("cannot send ticket and authenticator back: %r");
-
- if((n=read(fd, tbuf, m)) != m || memcmp(tbuf, "cpu:", 4) == 0){
- if(n <= 4)
- sysfatal("cannot read authenticator");
-
- /*
- * didn't send back authenticator:
- * sent back fatal error message.
- */
- memmove(buf, tbuf, n);
- i = readn(fd, buf+n, sizeof buf-n-1);
- if(i > 0)
- n += i;
- buf[n] = 0;
- sysfatal("server says: %s", buf);
- }
-
- if(convM2A(tbuf, n, &auth, &t) <= 0
- || auth.num != AuthAs || tsmemcmp(auth.chal, cchal, CHALLEN) != 0){
- print("?you and auth server agree about password.\n");
- print("?server is confused.\n");
- sysfatal("server lies");
- }
- memmove(crand+NONCELEN, auth.rand, NONCELEN);
-
- // print("i am %s there.\n", t.suid);
-
- ai = mallocz(sizeof(AuthInfo), 1);
- ai->suid = estrdup(t.suid);
- ai->cuid = estrdup(t.cuid);
- if(dp9ik){
- static char info[] = "Plan 9 session secret";
- ai->nsecret = 256;
- ai->secret = mallocz(ai->nsecret, 1);
- hkdf_x( crand, 2*NONCELEN,
- (uchar*)info, sizeof(info)-1,
- (uchar*)t.key, NONCELEN,
- ai->secret, ai->nsecret,
- hmac_sha2_256, SHA2_256dlen);
- } else {
- ai->nsecret = 8;
- ai->secret = mallocz(ai->nsecret, 1);
- des56to64((uchar*)t.key, ai->secret);
- }
-
- memset(&t, 0, sizeof(t));
- memset(&auth, 0, sizeof(auth));
- memset(&authkey, 0, sizeof(authkey));
- memset(cchal, 0, sizeof(cchal));
- memset(crand, 0, sizeof(crand));
- free(proto);
-
- return ai;
-}
-
-static int
-getkey(Authkey *key, char *user, char *dom, char *proto, char *pass)
-{
- if(pass != nil && *pass)
- pass = estrdup(pass);
- else {
- sysfatal("getkey: no password");
- }
- if(pass != nil){
- memset(key, 0, sizeof(*key));
- passtokey(key, pass);
- if(strcmp(proto, "dp9ik") == 0) {
- authpak_hash(key, user);
- }
- return 1;
- }
- return 0;
-}
--- /dev/null
+++ b/fncs.h
@@ -1,0 +1,4 @@
+int unix_dial(char*, char*);
+AuthInfo* p9any(char *user, char *pass, int fd);
+
+extern char *authserver;
--- /dev/null
+++ b/p9any.c
@@ -1,0 +1,356 @@
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netinet/in.h>
+
+#include <u.h>
+#include <args.h>
+#include <libc.h>
+#include <auth.h>
+#include <authsrv.h>
+#include <libsec.h>
+
+#include "fncs.h"
+
+void errstr(char *s){}
+
+char*
+estrdup(char *s)
+{
+ s = strdup(s);
+ if(s == nil)
+ sysfatal("out of memory");
+ return s;
+}
+
+int
+unix_dial(char *host, char *port)
+{
+ int fd;
+ struct sockaddr_in server;
+ struct hostent *he;
+ struct in_addr **addr_list;
+
+ he = gethostbyname(host);
+ if(he == nil){
+ printf("could not resolve %s", host);
+ return -1;
+ }
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ addr_list = (struct in_addr **) he->h_addr_list;
+ server.sin_addr.s_addr = inet_addr(inet_ntoa(*addr_list[0]));
+ server.sin_family = AF_INET;
+ server.sin_port = htons(atoi(port));
+ if(connect(fd, (struct sockaddr*)&server, sizeof(server)) < 0)
+ return -1;
+ return fd;
+}
+
+static int
+getkey(Authkey *key, char *user, char *dom, char *proto, char *pass)
+{
+ if(pass != nil && *pass)
+ pass = estrdup(pass);
+ else {
+ printf("getkey: no password");
+ return 0;
+ }
+ if(pass != nil){
+ memset(key, 0, sizeof(*key));
+ passtokey(key, pass);
+ if(strcmp(proto, "dp9ik") == 0) {
+ authpak_hash(key, user);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+int
+authdial(char *net, char *dom)
+{
+ return unix_dial(authserver, "567");
+}
+
+static int
+getastickets(Authkey *key, Ticketreq *tr, uchar *y, char *tbuf, int tbuflen)
+{
+ int asfd, rv;
+ char *dom;
+
+ dom = tr->authdom;
+ asfd = authdial(nil, dom);
+ if(asfd < 0)
+ return -1;
+ if(y != nil){
+ PAKpriv p;
+
+ rv = -1;
+ tr->type = AuthPAK;
+ if(_asrequest(asfd, tr) != 0 || write(asfd, y, PAKYLEN) != PAKYLEN)
+ goto Out;
+
+ authpak_new(&p, key, (uchar*)tbuf, 1);
+ if(write(asfd, tbuf, PAKYLEN) != PAKYLEN)
+ goto Out;
+
+ if(_asrdresp(asfd, tbuf, 2*PAKYLEN) != 2*PAKYLEN)
+ goto Out;
+
+ memmove(y, tbuf, PAKYLEN);
+ if(authpak_finish(&p, key, (uchar*)tbuf+PAKYLEN))
+ goto Out;
+ }
+ tr->type = AuthTreq;
+ rv = _asgetticket(asfd, tr, tbuf, tbuflen);
+Out:
+ close(asfd);
+ return rv;
+}
+
+static int
+mkservertickets(Authkey *key, Ticketreq *tr, uchar *y, char *tbuf, int tbuflen)
+{
+ Ticket t;
+ int ret;
+
+ if(strcmp(tr->authid, tr->hostid) != 0)
+ return -1;
+ memset(&t, 0, sizeof(t));
+ ret = 0;
+ if(y != nil){
+ PAKpriv p;
+
+ t.form = 1;
+ memmove(tbuf, y, PAKYLEN);
+ authpak_new(&p, key, y, 0);
+ authpak_finish(&p, key, (uchar*)tbuf);
+ }
+ memmove(t.chal, tr->chal, CHALLEN);
+ strcpy(t.cuid, tr->uid);
+ strcpy(t.suid, tr->uid);
+ genrandom((uchar*)t.key, sizeof(t.key));
+ t.num = AuthTc;
+ ret += convT2M(&t, tbuf+ret, tbuflen-ret, key);
+ t.num = AuthTs;
+ ret += convT2M(&t, tbuf+ret, tbuflen-ret, key);
+ memset(&t, 0, sizeof(t));
+
+ return ret;
+}
+
+static int
+gettickets(Authkey *key, Ticketreq *tr, uchar *y, char *tbuf, int tbuflen)
+{
+ int ret;
+ ret = getastickets(key, tr, y, tbuf, tbuflen);
+ if(ret > 0)
+ return ret;
+ return mkservertickets(key, tr, y, tbuf, tbuflen);
+}
+
+int
+readstr(int fd, char *str, int len)
+{
+ int n;
+
+ while(len) {
+ n = read(fd, str, 1);
+ if(n < 0)
+ return -1;
+ if(*str == '\0')
+ return 0;
+ str++;
+ len--;
+ }
+ return -1;
+}
+
+AuthInfo*
+p9any(char *user, char *pass, int fd)
+{
+ char buf[1024], buf2[1024], *bbuf, *p, *proto, *dom;
+ uchar crand[2*NONCELEN], cchal[CHALLEN], y[PAKYLEN];
+ char tbuf[2*MAXTICKETLEN+MAXAUTHENTLEN+PAKYLEN], trbuf[TICKREQLEN+PAKYLEN];
+ Authkey authkey;
+ Authenticator auth;
+ int i, n, m, v2, dp9ik;
+ Ticketreq tr;
+ Ticket t;
+ AuthInfo *ai;
+
+ if(readstr(fd, buf, sizeof buf) < 0){
+ printf("cannot read p9any negotiation");
+ return nil;
+ }
+ bbuf = buf;
+ v2 = 0;
+ if(strncmp(buf, "v.2 ", 4) == 0){
+ v2 = 1;
+ bbuf += 4;
+ }
+ dp9ik = 0;
+ proto = nil;
+ while(bbuf != nil){
+ if((p = strchr(bbuf, ' ')))
+ *p++ = 0;
+ if((dom = strchr(bbuf, '@')) == nil){
+ printf("bad p9any domain");
+ return nil;
+ }
+ *dom++ = 0;
+ if(strcmp(bbuf, "p9sk1") == 0 || strcmp(bbuf, "dp9ik") == 0){
+ proto = bbuf;
+ if(strcmp(proto, "dp9ik") == 0){
+ dp9ik = 1;
+ break;
+ }
+ }
+ bbuf = p;
+ }
+ if(proto == nil){
+ printf("server did not offer p9sk1 or dp9ik");
+ return nil;
+ }
+ proto = estrdup(proto);
+ sprint(buf2, "%s %s", proto, dom);
+ if(write(fd, buf2, strlen(buf2)+1) != strlen(buf2)+1){
+ printf("cannot write user/domain choice in p9any");
+ return nil;
+ }
+ if(v2){
+ if(readstr(fd, buf, sizeof buf) < 0){
+ printf("cannot read OK in p9any");
+ return nil;
+ }
+ if(memcmp(buf, "OK\0", 3) != 0){
+ printf("did not get OK in p9any: got %s", buf);
+ return nil;
+ }
+ }
+ genrandom(crand, 2*NONCELEN);
+ genrandom(cchal, CHALLEN);
+ if(write(fd, cchal, CHALLEN) != CHALLEN){
+ printf("cannot write p9sk1 challenge");
+ return nil;
+ }
+
+ n = TICKREQLEN;
+ if(dp9ik)
+ n += PAKYLEN;
+
+ if(readn(fd, trbuf, n) != n || convM2TR(trbuf, TICKREQLEN, &tr) <= 0){
+ printf("cannot read ticket request in p9sk1");
+ return nil;
+ }
+
+again:
+ if(!getkey(&authkey, user, tr.authdom, proto, pass)){
+ printf("no password");
+ return nil;
+ }
+
+ strecpy(tr.hostid, tr.hostid+sizeof tr.hostid, user);
+ strecpy(tr.uid, tr.uid+sizeof tr.uid, user);
+
+ if(dp9ik){
+ memmove(y, trbuf+TICKREQLEN, PAKYLEN);
+ n = gettickets(&authkey, &tr, y, tbuf, sizeof(tbuf));
+ } else {
+ n = gettickets(&authkey, &tr, nil, tbuf, sizeof(tbuf));
+ }
+ if(n <= 0){
+ printf("cannot get auth tickets in p9sk1");
+ return nil;
+ }
+
+ m = convM2T(tbuf, n, &t, &authkey);
+ if(m <= 0 || t.num != AuthTc){
+ printf("?password mismatch with auth server\n");
+ if(pass != nil && *pass){
+ printf("wrong password");
+ return nil;
+ }
+ goto again;
+ }
+ n -= m;
+ memmove(tbuf, tbuf+m, n);
+
+ if(dp9ik && write(fd, y, PAKYLEN) != PAKYLEN){
+ printf("cannot send authpak public key back");
+ return nil;
+ }
+
+ auth.num = AuthAc;
+ memmove(auth.rand, crand, NONCELEN);
+ memmove(auth.chal, tr.chal, CHALLEN);
+ m = convA2M(&auth, tbuf+n, sizeof(tbuf)-n, &t);
+ n += m;
+
+ if(write(fd, tbuf, n) != n){
+ printf("cannot send ticket and authenticator back");
+ return nil;
+ }
+
+ if((n=read(fd, tbuf, m)) != m || memcmp(tbuf, "cpu:", 4) == 0){
+ if(n <= 4){
+ printf("cannot read authenticator");
+ return nil;
+ }
+
+ /*
+ * didn't send back authenticator:
+ * sent back fatal error message.
+ */
+ memmove(buf, tbuf, n);
+ i = readn(fd, buf+n, sizeof buf-n-1);
+ if(i > 0)
+ n += i;
+ buf[n] = 0;
+ printf("server says: %s", buf);
+ return nil;
+ }
+
+ if(convM2A(tbuf, n, &auth, &t) <= 0
+ || auth.num != AuthAs || tsmemcmp(auth.chal, cchal, CHALLEN) != 0){
+ print("?you and auth server agree about password.\n");
+ print("?server is confused.\n");
+ return nil;
+ }
+ memmove(crand+NONCELEN, auth.rand, NONCELEN);
+
+ // print("i am %s there.\n", t.suid);
+
+ ai = mallocz(sizeof(AuthInfo), 1);
+ ai->suid = estrdup(t.suid);
+ ai->cuid = estrdup(t.cuid);
+ if(dp9ik){
+ static char info[] = "Plan 9 session secret";
+ ai->nsecret = 256;
+ ai->secret = mallocz(ai->nsecret, 1);
+ hkdf_x( crand, 2*NONCELEN,
+ (uchar*)info, sizeof(info)-1,
+ (uchar*)t.key, NONCELEN,
+ ai->secret, ai->nsecret,
+ hmac_sha2_256, SHA2_256dlen);
+ } else {
+ ai->nsecret = 8;
+ ai->secret = mallocz(ai->nsecret, 1);
+ des56to64((uchar*)t.key, ai->secret);
+ }
+
+ memset(&t, 0, sizeof(t));
+ memset(&auth, 0, sizeof(auth));
+ memset(&authkey, 0, sizeof(authkey));
+ memset(cchal, 0, sizeof(cchal));
+ memset(crand, 0, sizeof(crand));
+ free(proto);
+
+ return ai;
+}
+
--- /dev/null
+++ b/pam.c
@@ -1,0 +1,61 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_ext.h>
+
+#include <u.h>
+#include <args.h>
+#include <libc.h>
+#include <auth.h>
+#include <authsrv.h>
+#include <libsec.h>
+
+#include "fncs.h"
+
+/* pasword change TODO */
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv )
+{
+ return PAM_SUCCESS;
+}
+
+/* For checking if the user has expired, has access to specific machine etc */
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+ return PAM_SUCCESS;
+}
+
+char *authserver;
+
+/* expected hook, this is where custom stuff happens */
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv )
+{
+ char *username;
+ char *password;
+ int fd;
+ AuthInfo *ai;
+
+ if(pam_get_user(pamh, &username, NULL) != PAM_SUCCESS)
+ return PAM_AUTH_ERR;
+ if(pam_get_authtok(pamh, PAM_AUTHTOK, &password, NULL) != PAM_SUCCESS)
+ return PAM_AUTH_ERR;
+
+ if(argc != 1)
+ return PAM_AUTH_ERR;
+
+ authserver = argv[0];
+
+ fd = unix_dial(authserver, "17019");
+ if(fd < 0)
+ return PAM_AUTH_ERR;
+
+ ai = p9any(username, password, fd);
+ if(ai == nil)
+ return PAM_AUTH_ERR;
+
+ return PAM_SUCCESS;
+}