/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * devtls - record layer for transport layer security 1.0 and secure sockets layer 3.0 */#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/error.h" #include <libsec.h> typedef struct OneWay OneWay;typedef struct Secret Secret;typedef struct TlsRec TlsRec;typedef struct TlsErrs TlsErrs; enum { Statlen= 1024, /* max. length of status or stats message */ /* buffer limits */ MaxRecLen = 1<<14, /* max payload length of a record layer message */ MaxCipherRecLen = MaxRecLen + 2048, RecHdrLen = 5, MaxMacLen = SHA1dlen, /* protocol versions we can accept */ TLSVersion = 0x0301, SSL3Version = 0x0300, ProtocolVersion = 0x0301, /* maximum version we speak */ MinProtoVersion = 0x0300, /* limits on version we accept */ MaxProtoVersion = 0x03ff, /* connection states */ SHandshake = 1 << 0, /* doing handshake */ SOpen = 1 << 1, /* application data can be sent */ SRClose = 1 << 2, /* remote side has closed down */ SLClose = 1 << 3, /* sent a close notify alert */ SAlert = 1 << 5, /* sending or sent a fatal alert */ SError = 1 << 6, /* some sort of error has occured */ SClosed = 1 << 7, /* it is all over */ /* record types */ RChangeCipherSpec = 20, RAlert, RHandshake, RApplication, SSL2ClientHello = 1, HSSL2ClientHello = 9, /* local convention; see tlshand.c */ /* alerts */ ECloseNotify = 0, EUnexpectedMessage = 10, EBadRecordMac = 20, EDecryptionFailed = 21, ERecordOverflow = 22, EDecompressionFailure = 30, EHandshakeFailure = 40, ENoCertificate = 41, EBadCertificate = 42, EUnsupportedCertificate = 43, ECertificateRevoked = 44, ECertificateExpired = 45, ECertificateUnknown = 46, EIllegalParameter = 47, EUnknownCa = 48, EAccessDenied = 49, EDecodeError = 50, EDecryptError = 51, EExportRestriction = 60, EProtocolVersion = 70, EInsufficientSecurity = 71, EInternalError = 80, EUserCanceled = 90, ENoRenegotiation = 100, EMAX = 256}; struct Secret{ char *encalg; /* name of encryption alg */ char *hashalg; /* name of hash alg */ int (*enc)(Secret*, uchar*, int); int (*dec)(Secret*, uchar*, int); int (*unpad)(uchar*, int, int); DigestState *(*mac)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); int block; /* encryption block len, 0 if none */ int maclen; void *enckey; uchar mackey[MaxMacLen];}; struct OneWay{ QLock io; /* locks io access */ QLock seclock; /* locks secret paramaters */ ulong seq; Secret *sec; /* cipher in use */ Secret *new; /* cipher waiting for enable */}; struct TlsRec{ Chan *c; /* io channel */ int ref; /* serialized by tdlock for atomic destroy */ int version; /* version of the protocol we are speaking */ char verset; /* version has been set */ char opened; /* opened command every issued? */ char err[ERRMAX]; /* error message to return to handshake requests */ vlong handin; /* bytes communicated by the record layer */ vlong handout; vlong datain; vlong dataout; Lock statelk; int state; /* record layer mac functions for different protocol versions */ void (*packMac)(Secret*, uchar*, uchar*, uchar*, uchar*, int, uchar*); /* input side -- protected by in.io */ OneWay in; Block *processed; /* next bunch of application data */ Block *unprocessed; /* data read from c but not parsed into records */ /* handshake queue */ Lock hqlock; /* protects hqref, alloc & free of handq, hprocessed */ int hqref; Queue *handq; /* queue of handshake messages */ Block *hprocessed; /* remainder of last block read from handq */ QLock hqread; /* protects reads for hprocessed, handq */ /* output side */ OneWay out; /* protections */ char *user; int perm;}; struct TlsErrs{ int err; int sslerr; int tlserr; int fatal; char *msg;}; static TlsErrs tlserrs[] = { {ECloseNotify, ECloseNotify, ECloseNotify, 0, "close notify"}, {EUnexpectedMessage, EUnexpectedMessage, EUnexpectedMessage, 1, "unexpected message"}, {EBadRecordMac, EBadRecordMac, EBadRecordMac, 1, "bad record mac"}, {EDecryptionFailed, EIllegalParameter, EDecryptionFailed, 1, "decryption failed"}, {ERecordOverflow, EIllegalParameter, ERecordOverflow, 1, "record too long"}, {EDecompressionFailure, EDecompressionFailure, EDecompressionFailure, 1, "decompression failed"}, {EHandshakeFailure, EHandshakeFailure, EHandshakeFailure, 1, "could not negotiate acceptable security paramters"}, {ENoCertificate, ENoCertificate, ECertificateUnknown, 1, "no appropriate certificate available"}, {EBadCertificate, EBadCertificate, EBadCertificate, 1, "corrupted or invalid certificate"}, {EUnsupportedCertificate, EUnsupportedCertificate, EUnsupportedCertificate, 1, "unsupported certificate type"}, {ECertificateRevoked, ECertificateRevoked, ECertificateRevoked, 1, "revoked certificate"}, {ECertificateExpired, ECertificateExpired, ECertificateExpired, 1, "expired certificate"}, {ECertificateUnknown, ECertificateUnknown, ECertificateUnknown, 1, "unacceptable certificate"}, {EIllegalParameter, EIllegalParameter, EIllegalParameter, 1, "illegal parameter"}, {EUnknownCa, EHandshakeFailure, EUnknownCa, 1, "unknown certificate authority"}, {EAccessDenied, EHandshakeFailure, EAccessDenied, 1, "access denied"}, {EDecodeError, EIllegalParameter, EDecodeError, 1, "error decoding message"}, {EDecryptError, EIllegalParameter, EDecryptError, 1, "error decrypting message"}, {EExportRestriction, EHandshakeFailure, EExportRestriction, 1, "export restriction violated"}, {EProtocolVersion, EIllegalParameter, EProtocolVersion, 1, "protocol version not supported"}, {EInsufficientSecurity, EHandshakeFailure, EInsufficientSecurity, 1, "stronger security routines required"}, {EInternalError, EHandshakeFailure, EInternalError, 1, "internal error"}, {EUserCanceled, ECloseNotify, EUserCanceled, 0, "handshake canceled by user"}, {ENoRenegotiation, EUnexpectedMessage, ENoRenegotiation, 0, "no renegotiation"},}; enum{ /* max. open tls connections */ MaxTlsDevs = 1024}; static Lock tdlock;static int tdhiwat;static int maxtlsdevs = 128;static TlsRec **tlsdevs;static char **trnames;static char *encalgs;static char *hashalgs; enum{ Qtopdir = 1, /* top level directory */ Qprotodir, Qclonus, Qencalgs, Qhashalgs, Qconvdir, /* directory for a conversation */ Qdata, Qctl, Qhand, Qstatus, Qstats,}; #define TYPE(x) ((x).path & 0xf)#define CONV(x) (((x).path >> 5)&(MaxTlsDevs-1))#define QID(c, y) (((c)<<5) | (y)) static void checkstate(TlsRec *, int, int);static void ensure(TlsRec*, Block**, int);static void consume(Block**, uchar*, int);static Chan* buftochan(char*);static void tlshangup(TlsRec*);static void tlsError(TlsRec*, char *);static void alertHand(TlsRec*, char *);static TlsRec *newtls(Chan *c);static TlsRec *mktlsrec(void);static DigestState*sslmac_md5(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s);static DigestState*sslmac_sha1(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s);static DigestState*nomac(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s);static void sslPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac);static void tlsPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac);static void put64(uchar *p, vlong x);static void put32(uchar *p, u32int);static void put24(uchar *p, int);static void put16(uchar *p, int);static u32int get32(uchar *p);static int get16(uchar *p);static void tlsSetState(TlsRec *tr, int new, int old);static void rcvAlert(TlsRec *tr, int err);static void sendAlert(TlsRec *tr, int err);static void rcvError(TlsRec *tr, int err, char *msg, ...);static int rc4enc(Secret *sec, uchar *buf, int n);static int des3enc(Secret *sec, uchar *buf, int n);static int des3dec(Secret *sec, uchar *buf, int n);static int noenc(Secret *sec, uchar *buf, int n);static int sslunpad(uchar *buf, int n, int block);static int tlsunpad(uchar *buf, int n, int block);static void freeSec(Secret *sec);static char *tlsstate(int s); #pragma varargck argpos rcvError 3 static char *tlsnames[] = {[Qclonus] "clone",[Qencalgs] "encalgs",[Qhashalgs] "hashalgs",[Qdata] "data",[Qctl] "ctl",[Qhand] "hand",[Qstatus] "status",[Qstats] "stats",}; static int convdir[] = { Qctl, Qdata, Qhand, Qstatus, Qstats }; static inttlsgen(Chan *c, char*, Dirtab *, int, int s, Dir *dp){ Qid q; TlsRec *tr; char *name, *nm; int perm, t; q.vers = 0; q.type = QTFILE; t = TYPE(c->qid); switch(t) { case Qtopdir: if(s == DEVDOTDOT){ q.path = QID(0, Qtopdir); q.type = QTDIR; devdir(c, q, "#a", 0, eve, 0555, dp); return 1; } if(s > 0) return -1; q.path = QID(0, Qprotodir); q.type = QTDIR; devdir(c, q, "tls", 0, eve, 0555, dp); return 1; case Qprotodir: if(s == DEVDOTDOT){ q.path = QID(0, Qtopdir); q.type = QTDIR; devdir(c, q, ".", 0, eve, 0555, dp); return 1; } if(s < 3){ switch(s) { default: return -1; case 0: q.path = QID(0, Qclonus); break; case 1: q.path = QID(0, Qencalgs); break; case 2: q.path = QID(0, Qhashalgs); break; } perm = 0444; if(TYPE(q) == Qclonus) perm = 0555; devdir(c, q, tlsnames[TYPE(q)], 0, eve, perm, dp); return 1; } s -= 3; if(s >= tdhiwat) return -1; q.path = QID(s, Qconvdir); q.type = QTDIR; lock(&tdlock); tr = tlsdevs[s]; if(tr != nil) nm = tr->user; else nm = eve; if((name = trnames[s]) == nil) { name = trnames[s] = smalloc(16); sprint(name, "%d", s); } devdir(c, q, name, 0, nm, 0555, dp); unlock(&tdlock); return 1; case Qconvdir: if(s == DEVDOTDOT){ q.path = QID(0, Qprotodir); q.type = QTDIR; devdir(c, q, "tls", 0, eve, 0555, dp); return 1; } if(s < 0 || s >= nelem(convdir)) return -1; lock(&tdlock); tr = tlsdevs[CONV(c->qid)]; if(tr != nil){ nm = tr->user; perm = tr->perm; }else{ perm = 0; nm = eve; } t = convdir[s]; if(t == Qstatus || t == Qstats) perm &= 0444; q.path = QID(CONV(c->qid), t); devdir(c, q, tlsnames[t], 0, nm, perm, dp); unlock(&tdlock); return 1; case Qclonus: case Qencalgs: case Qhashalgs: perm = 0444; if(t == Qclonus) perm = 0555; devdir(c, c->qid, tlsnames[t], 0, eve, perm, dp); return 1; default: lock(&tdlock); tr = tlsdevs[CONV(c->qid)]; if(tr != nil){ nm = tr->user; perm = tr->perm; }else{ perm = 0; nm = eve; } if(t == Qstatus || t == Qstats) perm &= 0444; devdir(c, c->qid, tlsnames[t], 0, nm, perm, dp); unlock(&tdlock); return 1; } return -1;} static Chan*tlsattach(char *spec){ Chan *c; c = devattach('a', spec); c->qid.path = QID(0, Qtopdir); c->qid.type = QTDIR; c->qid.vers = 0; return c;} static Walkqid*tlswalk(Chan *c, Chan *nc, char **name, int nname){ return devwalk(c, nc, name, nname, nil, 0, tlsgen);} static inttlsstat(Chan *c, uchar *db, int n){ return devstat(c, db, n, nil, 0, tlsgen);} static Chan*tlsopen(Chan *c, int omode){ TlsRec *tr, **pp; int t, perm; perm = 0; omode &= 3; switch(omode) { case OREAD: perm = 4; break; case OWRITE: perm = 2; break; case ORDWR: perm = 6; break; } t = TYPE(c->qid); switch(t) { default: panic("tlsopen"); case Qtopdir: case Qprotodir: case Qconvdir: if(omode != OREAD) error(Eperm); break; case Qclonus: tr = newtls(c); if(tr == nil) error(Enodev); break; case Qctl: case Qdata: case Qhand: case Qstatus: case Qstats: if((t == Qstatus || t == Qstats) && omode != OREAD) error(Eperm); if(waserror()) { unlock(&tdlock); nexterror(); } lock(&tdlock); pp = &tlsdevs[CONV(c->qid)]; tr = *pp; if(tr == nil) error("must open connection using clone"); if((perm & (tr->perm>>6)) != perm && (strcmp(up->user, tr->user) != 0 || (perm & tr->perm) != perm)) error(Eperm); if(t == Qhand){ if(waserror()){ unlock(&tr->hqlock); nexterror(); } lock(&tr->hqlock); if(tr->handq != nil) error(Einuse); tr->handq = qopen(2 * MaxCipherRecLen, 0, nil, nil); if(tr->handq == nil) error("can't allocate handshake queue"); tr->hqref = 1; unlock(&tr->hqlock); poperror(); } tr->ref++; unlock(&tdlock); poperror(); break; case Qencalgs: case Qhashalgs: if(omode != OREAD) error(Eperm); break; } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; c->iounit = qiomaxatomic; return c;} static intLines 1–500 of 2122. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * devtls - record layer for transport layer security 1.0 and secure sockets layer 3.0 */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include <libsec.h> typedef struct OneWay OneWay; typedef struct Secret Secret; typedef struct TlsRec TlsRec; typedef struct TlsErrs TlsErrs; enum { Statlen= 1024, /* max. length of status or stats message */ /* buffer limits */ MaxRecLen = 1<<14, /* max payload length of a record layer message */ MaxCipherRecLen = MaxRecLen + 2048, RecHdrLen = 5, MaxMacLen = SHA1dlen, /* protocol versions we can accept */ TLSVersion = 0x0301, SSL3Version = 0x0300, ProtocolVersion = 0x0301, /* maximum version we speak */ MinProtoVersion = 0x0300, /* limits on version we accept */ MaxProtoVersion = 0x03ff, /* connection states */ SHandshake = 1 << 0, /* doing handshake */ SOpen = 1 << 1, /* application data can be sent */ SRClose = 1 << 2, /* remote side has closed down */ SLClose = 1 << 3, /* sent a close notify alert */ SAlert = 1 << 5, /* sending or sent a fatal alert */ SError = 1 << 6, /* some sort of error has occured */ SClosed = 1 << 7, /* it is all over */ /* record types */ RChangeCipherSpec = 20, RAlert, RHandshake, RApplication, SSL2ClientHello = 1, HSSL2ClientHello = 9, /* local convention; see tlshand.c */ /* alerts */ ECloseNotify = 0, EUnexpectedMessage = 10, EBadRecordMac = 20, EDecryptionFailed = 21, ERecordOverflow = 22, EDecompressionFailure = 30, EHandshakeFailure = 40, ENoCertificate = 41, EBadCertificate = 42, EUnsupportedCertificate = 43, ECertificateRevoked = 44, ECertificateExpired = 45, ECertificateUnknown = 46, EIllegalParameter = 47, EUnknownCa = 48, EAccessDenied = 49, EDecodeError = 50, EDecryptError = 51, EExportRestriction = 60, EProtocolVersion = 70, EInsufficientSecurity = 71, EInternalError = 80, EUserCanceled = 90, ENoRenegotiation = 100, EMAX = 256 }; struct Secret { char *encalg; /* name of encryption alg */ char *hashalg; /* name of hash alg */ int (*enc)(Secret*, uchar*, int); int (*dec)(Secret*, uchar*, int); int (*unpad)(uchar*, int, int); DigestState *(*mac)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); int block; /* encryption block len, 0 if none */ int maclen; void *enckey; uchar mackey[MaxMacLen]; }; struct OneWay { QLock io; /* locks io access */ QLock seclock; /* locks secret paramaters */ ulong seq; Secret *sec; /* cipher in use */ Secret *new; /* cipher waiting for enable */ }; struct TlsRec { Chan *c; /* io channel */ int ref; /* serialized by tdlock for atomic destroy */ int version; /* version of the protocol we are speaking */ char verset; /* version has been set */ char opened; /* opened command every issued? */ char err[ERRMAX]; /* error message to return to handshake requests */ vlong handin; /* bytes communicated by the record layer */ vlong handout; vlong datain; vlong dataout; Lock statelk; int state; /* record layer mac functions for different protocol versions */ void (*packMac)(Secret*, uchar*, uchar*, uchar*, uchar*, int, uchar*); /* input side -- protected by in.io */ OneWay in; Block *processed; /* next bunch of application data */ Block *unprocessed; /* data read from c but not parsed into records */ /* handshake queue */ Lock hqlock; /* protects hqref, alloc & free of handq, hprocessed */ int hqref; Queue *handq; /* queue of handshake messages */ Block *hprocessed; /* remainder of last block read from handq */ QLock hqread; /* protects reads for hprocessed, handq */ /* output side */ OneWay out; /* protections */ char *user; int perm; }; struct TlsErrs{ int err; int sslerr; int tlserr; int fatal; char *msg; }; static TlsErrs tlserrs[] = { {ECloseNotify, ECloseNotify, ECloseNotify, 0, "close notify"}, {EUnexpectedMessage, EUnexpectedMessage, EUnexpectedMessage, 1, "unexpected message"}, {EBadRecordMac, EBadRecordMac, EBadRecordMac, 1, "bad record mac"}, {EDecryptionFailed, EIllegalParameter, EDecryptionFailed, 1, "decryption failed"}, {ERecordOverflow, EIllegalParameter, ERecordOverflow, 1, "record too long"}, {EDecompressionFailure, EDecompressionFailure, EDecompressionFailure, 1, "decompression failed"}, {EHandshakeFailure, EHandshakeFailure, EHandshakeFailure, 1, "could not negotiate acceptable security paramters"}, {ENoCertificate, ENoCertificate, ECertificateUnknown, 1, "no appropriate certificate available"}, {EBadCertificate, EBadCertificate, EBadCertificate, 1, "corrupted or invalid certificate"}, {EUnsupportedCertificate, EUnsupportedCertificate, EUnsupportedCertificate, 1, "unsupported certificate type"}, {ECertificateRevoked, ECertificateRevoked, ECertificateRevoked, 1, "revoked certificate"}, {ECertificateExpired, ECertificateExpired, ECertificateExpired, 1, "expired certificate"}, {ECertificateUnknown, ECertificateUnknown, ECertificateUnknown, 1, "unacceptable certificate"}, {EIllegalParameter, EIllegalParameter, EIllegalParameter, 1, "illegal parameter"}, {EUnknownCa, EHandshakeFailure, EUnknownCa, 1, "unknown certificate authority"}, {EAccessDenied, EHandshakeFailure, EAccessDenied, 1, "access denied"}, {EDecodeError, EIllegalParameter, EDecodeError, 1, "error decoding message"}, {EDecryptError, EIllegalParameter, EDecryptError, 1, "error decrypting message"}, {EExportRestriction, EHandshakeFailure, EExportRestriction, 1, "export restriction violated"}, {EProtocolVersion, EIllegalParameter, EProtocolVersion, 1, "protocol version not supported"}, {EInsufficientSecurity, EHandshakeFailure, EInsufficientSecurity, 1, "stronger security routines required"}, {EInternalError, EHandshakeFailure, EInternalError, 1, "internal error"}, {EUserCanceled, ECloseNotify, EUserCanceled, 0, "handshake canceled by user"}, {ENoRenegotiation, EUnexpectedMessage, ENoRenegotiation, 0, "no renegotiation"}, }; enum { /* max. open tls connections */ MaxTlsDevs = 1024 }; static Lock tdlock; static int tdhiwat; static int maxtlsdevs = 128; static TlsRec **tlsdevs; static char **trnames; static char *encalgs; static char *hashalgs; enum{ Qtopdir = 1, /* top level directory */ Qprotodir, Qclonus, Qencalgs, Qhashalgs, Qconvdir, /* directory for a conversation */ Qdata, Qctl, Qhand, Qstatus, Qstats, }; #define TYPE(x) ((x).path & 0xf) #define CONV(x) (((x).path >> 5)&(MaxTlsDevs-1)) #define QID(c, y) (((c)<<5) | (y)) static void checkstate(TlsRec *, int, int); static void ensure(TlsRec*, Block**, int); static void consume(Block**, uchar*, int); static Chan* buftochan(char*); static void tlshangup(TlsRec*); static void tlsError(TlsRec*, char *); static void alertHand(TlsRec*, char *); static TlsRec *newtls(Chan *c); static TlsRec *mktlsrec(void); static DigestState*sslmac_md5(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s); static DigestState*sslmac_sha1(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s); static DigestState*nomac(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s); static void sslPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac); static void tlsPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac); static void put64(uchar *p, vlong x); static void put32(uchar *p, u32int); static void put24(uchar *p, int); static void put16(uchar *p, int); static u32int get32(uchar *p); static int get16(uchar *p); static void tlsSetState(TlsRec *tr, int new, int old); static void rcvAlert(TlsRec *tr, int err); static void sendAlert(TlsRec *tr, int err); static void rcvError(TlsRec *tr, int err, char *msg, ...); static int rc4enc(Secret *sec, uchar *buf, int n); static int des3enc(Secret *sec, uchar *buf, int n); static int des3dec(Secret *sec, uchar *buf, int n); static int noenc(Secret *sec, uchar *buf, int n); static int sslunpad(uchar *buf, int n, int block); static int tlsunpad(uchar *buf, int n, int block); static void freeSec(Secret *sec); static char *tlsstate(int s); #pragma varargck argpos rcvError 3 static char *tlsnames[] = { [Qclonus] "clone", [Qencalgs] "encalgs", [Qhashalgs] "hashalgs", [Qdata] "data", [Qctl] "ctl", [Qhand] "hand", [Qstatus] "status", [Qstats] "stats", }; static int convdir[] = { Qctl, Qdata, Qhand, Qstatus, Qstats }; static int tlsgen(Chan *c, char*, Dirtab *, int, int s, Dir *dp) { Qid q; TlsRec *tr; char *name, *nm; int perm, t; q.vers = 0; q.type = QTFILE; t = TYPE(c->qid); switch(t) { case Qtopdir: if(s == DEVDOTDOT){ q.path = QID(0, Qtopdir); q.type = QTDIR; devdir(c, q, "#a", 0, eve, 0555, dp); return 1; } if(s > 0) return -1; q.path = QID(0, Qprotodir); q.type = QTDIR; devdir(c, q, "tls", 0, eve, 0555, dp); return 1; case Qprotodir: if(s == DEVDOTDOT){ q.path = QID(0, Qtopdir); q.type = QTDIR; devdir(c, q, ".", 0, eve, 0555, dp); return 1; } if(s < 3){ switch(s) { default: return -1; case 0: q.path = QID(0, Qclonus); break; case 1: q.path = QID(0, Qencalgs); break; case 2: q.path = QID(0, Qhashalgs); break; } perm = 0444; if(TYPE(q) == Qclonus) perm = 0555; devdir(c, q, tlsnames[TYPE(q)], 0, eve, perm, dp); return 1; } s -= 3; if(s >= tdhiwat) return -1; q.path = QID(s, Qconvdir); q.type = QTDIR; lock(&tdlock); tr = tlsdevs[s]; if(tr != nil) nm = tr->user; else nm = eve; if((name = trnames[s]) == nil) { name = trnames[s] = smalloc(16); sprint(name, "%d", s); } devdir(c, q, name, 0, nm, 0555, dp); unlock(&tdlock); return 1; case Qconvdir: if(s == DEVDOTDOT){ q.path = QID(0, Qprotodir); q.type = QTDIR; devdir(c, q, "tls", 0, eve, 0555, dp); return 1; } if(s < 0 || s >= nelem(convdir)) return -1; lock(&tdlock); tr = tlsdevs[CONV(c->qid)]; if(tr != nil){ nm = tr->user; perm = tr->perm; }else{ perm = 0; nm = eve; } t = convdir[s]; if(t == Qstatus || t == Qstats) perm &= 0444; q.path = QID(CONV(c->qid), t); devdir(c, q, tlsnames[t], 0, nm, perm, dp); unlock(&tdlock); return 1; case Qclonus: case Qencalgs: case Qhashalgs: perm = 0444; if(t == Qclonus) perm = 0555; devdir(c, c->qid, tlsnames[t], 0, eve, perm, dp); return 1; default: lock(&tdlock); tr = tlsdevs[CONV(c->qid)]; if(tr != nil){ nm = tr->user; perm = tr->perm; }else{ perm = 0; nm = eve; } if(t == Qstatus || t == Qstats) perm &= 0444; devdir(c, c->qid, tlsnames[t], 0, nm, perm, dp); unlock(&tdlock); return 1; } return -1; } static Chan* tlsattach(char *spec) { Chan *c; c = devattach('a', spec); c->qid.path = QID(0, Qtopdir); c->qid.type = QTDIR; c->qid.vers = 0; return c; } static Walkqid* tlswalk(Chan *c, Chan *nc, char **name, int nname) { return devwalk(c, nc, name, nname, nil, 0, tlsgen); } static int tlsstat(Chan *c, uchar *db, int n) { return devstat(c, db, n, nil, 0, tlsgen); } static Chan* tlsopen(Chan *c, int omode) { TlsRec *tr, **pp; int t, perm; perm = 0; omode &= 3; switch(omode) { case OREAD: perm = 4; break; case OWRITE: perm = 2; break; case ORDWR: perm = 6; break; } t = TYPE(c->qid); switch(t) { default: panic("tlsopen"); case Qtopdir: case Qprotodir: case Qconvdir: if(omode != OREAD) error(Eperm); break; case Qclonus: tr = newtls(c); if(tr == nil) error(Enodev); break; case Qctl: case Qdata: case Qhand: case Qstatus: case Qstats: if((t == Qstatus || t == Qstats) && omode != OREAD) error(Eperm); if(waserror()) { unlock(&tdlock); nexterror(); } lock(&tdlock); pp = &tlsdevs[CONV(c->qid)]; tr = *pp; if(tr == nil) error("must open connection using clone"); if((perm & (tr->perm>>6)) != perm && (strcmp(up->user, tr->user) != 0 || (perm & tr->perm) != perm)) error(Eperm); if(t == Qhand){ if(waserror()){ unlock(&tr->hqlock); nexterror(); } lock(&tr->hqlock); if(tr->handq != nil) error(Einuse); tr->handq = qopen(2 * MaxCipherRecLen, 0, nil, nil); if(tr->handq == nil) error("can't allocate handshake queue"); tr->hqref = 1; unlock(&tr->hqlock); poperror(); } tr->ref++; unlock(&tdlock); poperror(); break; case Qencalgs: case Qhashalgs: if(omode != OREAD) error(Eperm); break; } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; c->iounit = qiomaxatomic; return c; } static int