2 * pageant.c: cross-platform code to implement Pageant.
14 * We need this to link with the RSA code, because rsaencrypt()
15 * pads its data with random bytes. Since we only use rsadecrypt()
16 * and the signing functions, which are deterministic, this should
19 * If it _is_ called, there is a _serious_ problem, because it
20 * won't generate true random numbers. So we must scream, panic,
21 * and exit immediately if that should happen.
25 modalfatalbox("Internal error: attempt to use random numbers in Pageant");
27 return 0; /* unreachable, but placate optimiser */
31 * rsakeys stores SSH-1 RSA keys. ssh2keys stores all SSH-2 keys.
33 static tree234 *rsakeys, *ssh2keys;
36 * Blob structure for passing to the asymmetric SSH-2 key compare
37 * function, prototyped here.
40 const unsigned char *blob;
43 static int cmpkeys_ssh2_asymm(void *av, void *bv);
46 * Key comparison function for the 2-3-4 tree of RSA keys.
48 static int cmpkeys_rsa(void *av, void *bv)
50 struct RSAKey *a = (struct RSAKey *) av;
51 struct RSAKey *b = (struct RSAKey *) bv;
58 * Compare by length of moduli.
60 alen = bignum_bitcount(am);
61 blen = bignum_bitcount(bm);
67 * Now compare by moduli themselves.
69 alen = (alen + 7) / 8; /* byte count */
72 abyte = bignum_byte(am, alen);
73 bbyte = bignum_byte(bm, alen);
76 else if (abyte < bbyte)
86 * Key comparison function for the 2-3-4 tree of SSH-2 keys.
88 static int cmpkeys_ssh2(void *av, void *bv)
90 struct ssh2_userkey *a = (struct ssh2_userkey *) av;
91 struct ssh2_userkey *b = (struct ssh2_userkey *) bv;
94 unsigned char *ablob, *bblob;
98 * Compare purely by public blob.
100 ablob = a->alg->public_blob(a->data, &alen);
101 bblob = b->alg->public_blob(b->data, &blen);
104 for (i = 0; i < alen && i < blen; i++) {
105 if (ablob[i] < bblob[i]) {
108 } else if (ablob[i] > bblob[i]) {
113 if (c == 0 && i < alen)
114 c = +1; /* a is longer */
115 if (c == 0 && i < blen)
116 c = -1; /* a is longer */
125 * Key comparison function for looking up a blob in the 2-3-4 tree
128 static int cmpkeys_ssh2_asymm(void *av, void *bv)
130 struct blob *a = (struct blob *) av;
131 struct ssh2_userkey *b = (struct ssh2_userkey *) bv;
134 const unsigned char *ablob;
135 unsigned char *bblob;
139 * Compare purely by public blob.
143 bblob = b->alg->public_blob(b->data, &blen);
146 for (i = 0; i < alen && i < blen; i++) {
147 if (ablob[i] < bblob[i]) {
150 } else if (ablob[i] > bblob[i]) {
155 if (c == 0 && i < alen)
156 c = +1; /* a is longer */
157 if (c == 0 && i < blen)
158 c = -1; /* a is longer */
166 * Create an SSH-1 key list in a malloc'ed buffer; return its
169 void *pageant_make_keylist1(int *length)
173 unsigned char *blob, *p, *ret;
177 * Count up the number and length of keys we hold.
181 for (i = 0; NULL != (key = index234(rsakeys, i)); i++) {
183 blob = rsa_public_blob(key, &bloblen);
186 len += 4 + strlen(key->comment);
189 /* Allocate the buffer. */
190 p = ret = snewn(len, unsigned char);
191 if (length) *length = len;
195 for (i = 0; NULL != (key = index234(rsakeys, i)); i++) {
196 blob = rsa_public_blob(key, &bloblen);
197 memcpy(p, blob, bloblen);
200 PUT_32BIT(p, strlen(key->comment));
201 memcpy(p + 4, key->comment, strlen(key->comment));
202 p += 4 + strlen(key->comment);
205 assert(p - ret == len);
210 * Create an SSH-2 key list in a malloc'ed buffer; return its
213 void *pageant_make_keylist2(int *length)
215 struct ssh2_userkey *key;
217 unsigned char *blob, *p, *ret;
221 * Count up the number and length of keys we hold.
225 for (i = 0; NULL != (key = index234(ssh2keys, i)); i++) {
227 len += 4; /* length field */
228 blob = key->alg->public_blob(key->data, &bloblen);
231 len += 4 + strlen(key->comment);
234 /* Allocate the buffer. */
235 p = ret = snewn(len, unsigned char);
236 if (length) *length = len;
239 * Packet header is the obvious five bytes, plus four
240 * bytes for the key count.
244 for (i = 0; NULL != (key = index234(ssh2keys, i)); i++) {
245 blob = key->alg->public_blob(key->data, &bloblen);
246 PUT_32BIT(p, bloblen);
248 memcpy(p, blob, bloblen);
251 PUT_32BIT(p, strlen(key->comment));
252 memcpy(p + 4, key->comment, strlen(key->comment));
253 p += 4 + strlen(key->comment);
256 assert(p - ret == len);
260 char *fingerprint_ssh2_blob(const void *blob, int bloblen)
262 unsigned char digest[16];
263 char fingerprint_str[16*3];
267 MD5Simple(blob, bloblen, digest);
268 for (i = 0; i < 16; i++)
269 sprintf(fingerprint_str + i*3, "%02x%s", digest[i], i==15 ? "" : ":");
271 stringlen = GET_32BIT((const unsigned char *)blob);
272 if (stringlen < bloblen-4)
273 return dupprintf("%.*s %s", (int)stringlen, (const char *)blob + 4,
276 return dupstr(fingerprint_str);
279 static void plog(void *logctx, pageant_logfn_t logfn, const char *fmt, ...)
281 __attribute__ ((format (printf, 3, 4)))
285 static void plog(void *logctx, pageant_logfn_t logfn, const char *fmt, ...)
288 * This is the wrapper that takes a variadic argument list and
289 * turns it into the va_list that the log function really expects.
290 * It's safe to call this with logfn==NULL, because we
291 * double-check that below; but if you're going to do lots of work
292 * before getting here (such as looping, or hashing things) then
293 * you should probably check logfn manually before doing that.
298 logfn(logctx, fmt, ap);
303 void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
304 void *logctx, pageant_logfn_t logfn)
306 const unsigned char *p = msg;
307 const unsigned char *msgend;
308 unsigned char *ret = snewn(AGENT_MAX_MSGLEN, unsigned char);
310 const char *fail_reason;
315 * Get the message type.
318 fail_reason = "message contained no type code";
324 case SSH1_AGENTC_REQUEST_RSA_IDENTITIES:
326 * Reply with SSH1_AGENT_RSA_IDENTITIES_ANSWER.
332 plog(logctx, logfn, "request: SSH1_AGENTC_REQUEST_RSA_IDENTITIES");
334 ret[4] = SSH1_AGENT_RSA_IDENTITIES_ANSWER;
335 keylist = pageant_make_keylist1(&len);
336 if (len + 5 > AGENT_MAX_MSGLEN) {
338 fail_reason = "output would exceed max msglen";
341 PUT_32BIT(ret, len + 1);
342 memcpy(ret + 5, keylist, len);
344 plog(logctx, logfn, "reply: SSH1_AGENT_RSA_IDENTITIES_ANSWER");
345 if (logfn) { /* skip this loop if not logging */
348 for (i = 0; NULL != (rkey = pageant_nth_ssh1_key(i)); i++) {
349 char fingerprint[128];
350 rsa_fingerprint(fingerprint, sizeof(fingerprint), rkey);
351 plog(logctx, logfn, "returned key: %s", fingerprint);
357 case SSH2_AGENTC_REQUEST_IDENTITIES:
359 * Reply with SSH2_AGENT_IDENTITIES_ANSWER.
365 plog(logctx, logfn, "request: SSH2_AGENTC_REQUEST_IDENTITIES");
367 ret[4] = SSH2_AGENT_IDENTITIES_ANSWER;
368 keylist = pageant_make_keylist2(&len);
369 if (len + 5 > AGENT_MAX_MSGLEN) {
371 fail_reason = "output would exceed max msglen";
374 PUT_32BIT(ret, len + 1);
375 memcpy(ret + 5, keylist, len);
377 plog(logctx, logfn, "reply: SSH2_AGENT_IDENTITIES_ANSWER");
378 if (logfn) { /* skip this loop if not logging */
380 struct ssh2_userkey *skey;
381 for (i = 0; NULL != (skey = pageant_nth_ssh2_key(i)); i++) {
382 char *fingerprint = skey->alg->fingerprint(skey->data);
383 plog(logctx, logfn, "returned key: %s %s",
384 fingerprint, skey->comment);
392 case SSH1_AGENTC_RSA_CHALLENGE:
394 * Reply with either SSH1_AGENT_RSA_RESPONSE or
395 * SSH_AGENT_FAILURE, depending on whether we have that key
399 struct RSAKey reqkey, *key;
400 Bignum challenge, response;
401 unsigned char response_source[48], response_md5[16];
402 struct MD5Context md5c;
405 plog(logctx, logfn, "request: SSH1_AGENTC_RSA_CHALLENGE");
408 i = ssh1_read_bignum(p, msgend - p, &reqkey.exponent);
410 fail_reason = "request truncated before key exponent";
414 i = ssh1_read_bignum(p, msgend - p, &reqkey.modulus);
416 freebn(reqkey.exponent);
417 fail_reason = "request truncated before key modulus";
421 i = ssh1_read_bignum(p, msgend - p, &challenge);
423 freebn(reqkey.exponent);
424 freebn(reqkey.modulus);
425 fail_reason = "request truncated before challenge";
430 freebn(reqkey.exponent);
431 freebn(reqkey.modulus);
433 fail_reason = "request truncated before session id";
436 memcpy(response_source + 32, p, 16);
439 freebn(reqkey.exponent);
440 freebn(reqkey.modulus);
442 fail_reason = "request truncated before response type";
445 if (GET_32BIT(p) != 1) {
446 freebn(reqkey.exponent);
447 freebn(reqkey.modulus);
449 fail_reason = "response type other than 1 not supported";
453 char fingerprint[128];
454 reqkey.comment = NULL;
455 rsa_fingerprint(fingerprint, sizeof(fingerprint), &reqkey);
456 plog(logctx, logfn, "requested key: %s", fingerprint);
458 if ((key = find234(rsakeys, &reqkey, NULL)) == NULL) {
459 freebn(reqkey.exponent);
460 freebn(reqkey.modulus);
462 fail_reason = "key not found";
465 response = rsadecrypt(challenge, key);
466 for (i = 0; i < 32; i++)
467 response_source[i] = bignum_byte(response, 31 - i);
470 MD5Update(&md5c, response_source, 48);
471 MD5Final(response_md5, &md5c);
472 smemclr(response_source, 48); /* burn the evidence */
473 freebn(response); /* and that evidence */
474 freebn(challenge); /* yes, and that evidence */
475 freebn(reqkey.exponent); /* and free some memory ... */
476 freebn(reqkey.modulus); /* ... while we're at it. */
479 * Packet is the obvious five byte header, plus sixteen
483 PUT_32BIT(ret, len - 4);
484 ret[4] = SSH1_AGENT_RSA_RESPONSE;
485 memcpy(ret + 5, response_md5, 16);
487 plog(logctx, logfn, "reply: SSH1_AGENT_RSA_RESPONSE");
490 case SSH2_AGENTC_SIGN_REQUEST:
492 * Reply with either SSH2_AGENT_SIGN_RESPONSE or
493 * SSH_AGENT_FAILURE, depending on whether we have that key
497 struct ssh2_userkey *key;
499 const unsigned char *data;
500 unsigned char *signature;
501 int datalen, siglen, len;
503 plog(logctx, logfn, "request: SSH2_AGENTC_SIGN_REQUEST");
506 fail_reason = "request truncated before public key";
509 b.len = toint(GET_32BIT(p));
510 if (b.len < 0 || b.len > msgend - (p+4)) {
511 fail_reason = "request truncated before public key";
518 fail_reason = "request truncated before string to sign";
521 datalen = toint(GET_32BIT(p));
523 if (datalen < 0 || datalen > msgend - p) {
524 fail_reason = "request truncated before string to sign";
529 char *fingerprint = fingerprint_ssh2_blob(b.blob, b.len);
530 plog(logctx, logfn, "requested key: %s", fingerprint);
533 key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm);
535 fail_reason = "key not found";
538 signature = key->alg->sign(key->data, (const char *)data,
540 len = 5 + 4 + siglen;
541 PUT_32BIT(ret, len - 4);
542 ret[4] = SSH2_AGENT_SIGN_RESPONSE;
543 PUT_32BIT(ret + 5, siglen);
544 memcpy(ret + 5 + 4, signature, siglen);
547 plog(logctx, logfn, "reply: SSH2_AGENT_SIGN_RESPONSE");
550 case SSH1_AGENTC_ADD_RSA_IDENTITY:
552 * Add to the list and return SSH_AGENT_SUCCESS, or
553 * SSH_AGENT_FAILURE if the key was malformed.
560 plog(logctx, logfn, "request: SSH1_AGENTC_ADD_RSA_IDENTITY");
562 key = snew(struct RSAKey);
563 memset(key, 0, sizeof(struct RSAKey));
565 n = makekey(p, msgend - p, key, NULL, 1);
569 fail_reason = "request truncated before public key";
574 n = makeprivate(p, msgend - p, key);
578 fail_reason = "request truncated before private key";
583 /* SSH-1 names p and q the other way round, i.e. we have
584 * the inverse of p mod q and not of q mod p. We swap the
585 * names, because our internal RSA wants iqmp. */
587 n = ssh1_read_bignum(p, msgend - p, &key->iqmp); /* p^-1 mod q */
591 fail_reason = "request truncated before iqmp";
596 n = ssh1_read_bignum(p, msgend - p, &key->q); /* p */
600 fail_reason = "request truncated before p";
605 n = ssh1_read_bignum(p, msgend - p, &key->p); /* q */
609 fail_reason = "request truncated before q";
617 fail_reason = "request truncated before key comment";
620 commentlen = toint(GET_32BIT(p));
622 if (commentlen < 0 || commentlen > msgend - p) {
625 fail_reason = "request truncated before key comment";
629 comment = snewn(commentlen+1, char);
631 memcpy(comment, p + 4, commentlen);
632 comment[commentlen] = '\0';
633 key->comment = comment;
637 char fingerprint[128];
638 rsa_fingerprint(fingerprint, sizeof(fingerprint), key);
639 plog(logctx, logfn, "submitted key: %s", fingerprint);
642 if (add234(rsakeys, key) == key) {
645 ret[4] = SSH_AGENT_SUCCESS;
647 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
652 fail_reason = "key already present";
657 case SSH2_AGENTC_ADD_IDENTITY:
659 * Add to the list and return SSH_AGENT_SUCCESS, or
660 * SSH_AGENT_FAILURE if the key was malformed.
663 struct ssh2_userkey *key;
669 plog(logctx, logfn, "request: SSH2_AGENTC_ADD_IDENTITY");
672 fail_reason = "request truncated before key algorithm";
675 alglen = toint(GET_32BIT(p));
677 if (alglen < 0 || alglen > msgend - p) {
678 fail_reason = "request truncated before key algorithm";
681 alg = (const char *)p;
684 key = snew(struct ssh2_userkey);
685 key->alg = find_pubkey_alg_len(alglen, alg);
688 fail_reason = "algorithm unknown";
692 bloblen = msgend - p;
693 key->data = key->alg->openssh_createkey(&p, &bloblen);
696 fail_reason = "key setup failed";
701 * p has been advanced by openssh_createkey, but
702 * certainly not _beyond_ the end of the buffer.
707 key->alg->freekey(key->data);
709 fail_reason = "request truncated before key comment";
712 commlen = toint(GET_32BIT(p));
715 if (commlen < 0 || commlen > msgend - p) {
716 key->alg->freekey(key->data);
718 fail_reason = "request truncated before key comment";
721 comment = snewn(commlen + 1, char);
723 memcpy(comment, p, commlen);
724 comment[commlen] = '\0';
726 key->comment = comment;
729 char *fingerprint = key->alg->fingerprint(key->data);
730 plog(logctx, logfn, "submitted key: %s %s",
731 fingerprint, key->comment);
735 if (add234(ssh2keys, key) == key) {
738 ret[4] = SSH_AGENT_SUCCESS;
740 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
742 key->alg->freekey(key->data);
746 fail_reason = "key already present";
751 case SSH1_AGENTC_REMOVE_RSA_IDENTITY:
753 * Remove from the list and return SSH_AGENT_SUCCESS, or
754 * perhaps SSH_AGENT_FAILURE if it wasn't in the list to
758 struct RSAKey reqkey, *key;
761 plog(logctx, logfn, "request: SSH1_AGENTC_REMOVE_RSA_IDENTITY");
763 n = makekey(p, msgend - p, &reqkey, NULL, 0);
765 fail_reason = "request truncated before public key";
770 char fingerprint[128];
771 reqkey.comment = NULL;
772 rsa_fingerprint(fingerprint, sizeof(fingerprint), &reqkey);
773 plog(logctx, logfn, "unwanted key: %s", fingerprint);
776 key = find234(rsakeys, &reqkey, NULL);
777 freebn(reqkey.exponent);
778 freebn(reqkey.modulus);
781 plog(logctx, logfn, "found with comment: %s", key->comment);
783 del234(rsakeys, key);
787 ret[4] = SSH_AGENT_SUCCESS;
789 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
791 fail_reason = "key not found";
796 case SSH2_AGENTC_REMOVE_IDENTITY:
798 * Remove from the list and return SSH_AGENT_SUCCESS, or
799 * perhaps SSH_AGENT_FAILURE if it wasn't in the list to
803 struct ssh2_userkey *key;
806 plog(logctx, logfn, "request: SSH2_AGENTC_REMOVE_IDENTITY");
809 fail_reason = "request truncated before public key";
812 b.len = toint(GET_32BIT(p));
815 if (b.len < 0 || b.len > msgend - p) {
816 fail_reason = "request truncated before public key";
823 char *fingerprint = fingerprint_ssh2_blob(b.blob, b.len);
824 plog(logctx, logfn, "unwanted key: %s", fingerprint);
828 key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm);
830 fail_reason = "key not found";
834 plog(logctx, logfn, "found with comment: %s", key->comment);
836 del234(ssh2keys, key);
838 key->alg->freekey(key->data);
841 ret[4] = SSH_AGENT_SUCCESS;
843 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
846 case SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
848 * Remove all SSH-1 keys. Always returns success.
853 plog(logctx, logfn, "request:"
854 " SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES");
856 while ((rkey = index234(rsakeys, 0)) != NULL) {
857 del234(rsakeys, rkey);
864 ret[4] = SSH_AGENT_SUCCESS;
866 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
869 case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
871 * Remove all SSH-2 keys. Always returns success.
874 struct ssh2_userkey *skey;
876 plog(logctx, logfn, "request: SSH2_AGENTC_REMOVE_ALL_IDENTITIES");
878 while ((skey = index234(ssh2keys, 0)) != NULL) {
879 del234(ssh2keys, skey);
880 skey->alg->freekey(skey->data);
886 ret[4] = SSH_AGENT_SUCCESS;
888 plog(logctx, logfn, "reply: SSH_AGENT_SUCCESS");
892 plog(logctx, logfn, "request: unknown message type %d", type);
894 fail_reason = "unrecognised message";
898 * Unrecognised message. Return SSH_AGENT_FAILURE.
901 ret[4] = SSH_AGENT_FAILURE;
902 plog(logctx, logfn, "reply: SSH_AGENT_FAILURE (%s)", fail_reason);
906 *outlen = 4 + GET_32BIT(ret);
910 void *pageant_failure_msg(int *outlen)
912 unsigned char *ret = snewn(5, unsigned char);
914 ret[4] = SSH_AGENT_FAILURE;
919 void pageant_init(void)
921 rsakeys = newtree234(cmpkeys_rsa);
922 ssh2keys = newtree234(cmpkeys_ssh2);
925 struct RSAKey *pageant_nth_ssh1_key(int i)
927 return index234(rsakeys, i);
930 struct ssh2_userkey *pageant_nth_ssh2_key(int i)
932 return index234(ssh2keys, i);
935 int pageant_count_ssh1_keys(void)
937 return count234(rsakeys);
940 int pageant_count_ssh2_keys(void)
942 return count234(ssh2keys);
945 int pageant_add_ssh1_key(struct RSAKey *rkey)
947 return add234(rsakeys, rkey) == rkey;
950 int pageant_add_ssh2_key(struct ssh2_userkey *skey)
952 return add234(ssh2keys, skey) == skey;
955 int pageant_delete_ssh1_key(struct RSAKey *rkey)
957 struct RSAKey *deleted = del234(rsakeys, rkey);
960 assert(deleted == rkey);
964 int pageant_delete_ssh2_key(struct ssh2_userkey *skey)
966 struct ssh2_userkey *deleted = del234(ssh2keys, skey);
969 assert(deleted == skey);
973 /* ----------------------------------------------------------------------
978 * Coroutine macros similar to, but simplified from, those in ssh.c.
980 #define crBegin(v) { int *crLine = &v; switch(v) { case 0:;
981 #define crFinish(z) } *crLine = 0; return (z); }
982 #define crGetChar(c) do \
985 *crLine =__LINE__; return 1; case __LINE__:; \
988 (c) = (unsigned char)*data++; \
991 struct pageant_conn_state {
992 const struct plug_function_table *fn;
993 /* the above variable absolutely *must* be the first in this structure */
997 pageant_logfn_t logfn;
998 unsigned char lenbuf[4], pktbuf[AGENT_MAX_MSGLEN];
1001 int crLine; /* for coroutine in pageant_conn_receive */
1004 static int pageant_conn_closing(Plug plug, const char *error_msg,
1005 int error_code, int calling_back)
1007 struct pageant_conn_state *pc = (struct pageant_conn_state *)plug;
1009 plog(pc->logctx, pc->logfn, "%p: error: %s", pc, error_msg);
1011 plog(pc->logctx, pc->logfn, "%p: connection closed", pc);
1012 sk_close(pc->connsock);
1017 static void pageant_conn_sent(Plug plug, int bufsize)
1019 /* struct pageant_conn_state *pc = (struct pageant_conn_state *)plug; */
1022 * We do nothing here, because we expect that there won't be a
1023 * need to throttle and unthrottle the connection to an agent -
1024 * clients will typically not send many requests, and will wait
1025 * until they receive each reply before sending a new request.
1029 static void pageant_conn_log(void *logctx, const char *fmt, va_list ap)
1031 /* Wrapper on pc->logfn that prefixes the connection identifier */
1032 struct pageant_conn_state *pc = (struct pageant_conn_state *)logctx;
1033 char *formatted = dupvprintf(fmt, ap);
1034 plog(pc->logctx, pc->logfn, "%p: %s", pc, formatted);
1038 static int pageant_conn_receive(Plug plug, int urgent, char *data, int len)
1040 struct pageant_conn_state *pc = (struct pageant_conn_state *)plug;
1043 crBegin(pc->crLine);
1047 while (pc->got < 4) {
1049 pc->lenbuf[pc->got++] = c;
1052 pc->len = GET_32BIT(pc->lenbuf);
1054 pc->real_packet = (pc->len < AGENT_MAX_MSGLEN-4);
1056 while (pc->got < pc->len) {
1058 if (pc->real_packet)
1059 pc->pktbuf[pc->got] = c;
1067 if (pc->real_packet) {
1068 reply = pageant_handle_msg(pc->pktbuf, pc->len, &replylen, pc,
1069 pc->logfn?pageant_conn_log:NULL);
1071 plog(pc->logctx, pc->logfn, "%p: overlong message (%u)",
1073 plog(pc->logctx, pc->logfn, "%p: reply: SSH_AGENT_FAILURE "
1074 "(message too long)", pc);
1075 reply = pageant_failure_msg(&replylen);
1077 sk_write(pc->connsock, reply, replylen);
1078 smemclr(reply, replylen);
1085 struct pageant_listen_state {
1086 const struct plug_function_table *fn;
1087 /* the above variable absolutely *must* be the first in this structure */
1091 pageant_logfn_t logfn;
1094 static int pageant_listen_closing(Plug plug, const char *error_msg,
1095 int error_code, int calling_back)
1097 struct pageant_listen_state *pl = (struct pageant_listen_state *)plug;
1099 plog(pl->logctx, pl->logfn, "listening socket: error: %s", error_msg);
1100 sk_close(pl->listensock);
1101 pl->listensock = NULL;
1105 static int pageant_listen_accepting(Plug plug,
1106 accept_fn_t constructor, accept_ctx_t ctx)
1108 static const struct plug_function_table connection_fn_table = {
1109 NULL, /* no log function, because that's for outgoing connections */
1110 pageant_conn_closing,
1111 pageant_conn_receive,
1113 NULL /* no accepting function, because we've already done it */
1115 struct pageant_listen_state *pl = (struct pageant_listen_state *)plug;
1116 struct pageant_conn_state *pc;
1119 pc = snew(struct pageant_conn_state);
1120 pc->fn = &connection_fn_table;
1121 pc->logfn = pl->logfn;
1122 pc->logctx = pl->logctx;
1125 pc->connsock = constructor(ctx, (Plug) pc);
1126 if ((err = sk_socket_error(pc->connsock)) != NULL) {
1127 sk_close(pc->connsock);
1132 sk_set_frozen(pc->connsock, 0);
1134 /* FIXME: can we get any useful peer id info? */
1135 plog(pl->logctx, pl->logfn, "%p: new connection", pc);
1140 struct pageant_listen_state *pageant_listener_new(void)
1142 static const struct plug_function_table listener_fn_table = {
1143 NULL, /* no log function, because that's for outgoing connections */
1144 pageant_listen_closing,
1145 NULL, /* no receive function on a listening socket */
1146 NULL, /* no sent function on a listening socket */
1147 pageant_listen_accepting
1150 struct pageant_listen_state *pl = snew(struct pageant_listen_state);
1151 pl->fn = &listener_fn_table;
1154 pl->listensock = NULL;
1158 void pageant_listener_got_socket(struct pageant_listen_state *pl, Socket sock)
1160 pl->listensock = sock;
1163 void pageant_listener_set_logfn(struct pageant_listen_state *pl,
1164 void *logctx, pageant_logfn_t logfn)
1166 pl->logctx = logctx;
1170 void pageant_listener_free(struct pageant_listen_state *pl)
1173 sk_close(pl->listensock);