-/*
- * Run down a list of queued frames for a krb5_conn, and if we find one
- * that matches the passed handle, fire the read event. Only
- * process one frame.
- *
- * Returns 1 if a frame was found and processed.
- */
-static int
-conn_run_frameq(
- /*@keep@*/ struct krb5_conn * kc,
- /*@keep@*/ struct krb5_stream * ks)
-{
- struct krb5_frame *kf, *nextkf;
- gss_buffer_desc *enctok, *dectok;
-#ifdef AMANDA_KRB5_ENCRYPT
- OM_uint32 min_stat;
- gss_buffer_desc tok;
-#endif
-
- /*
- * Iterate through all of the frames in the queue. If one
- * is for us, process it. If we hit an EOF frame, shut down.
- * Stop after processing one frame, because we are only supposed
- * to return one read request.
- */
- for (kf = TAILQ_FIRST(&kc->frameq); kf != NULL; kf = nextkf) {
- nextkf = TAILQ_NEXT(kf, tq);
-
- if (kf->handle != ks->handle && kf->handle != H_EOF) {
- k5printf(("krb5: conn_frameq_run: not for us (handle %d)\n",
- kf->handle));
- continue;
- }
- /*
- * We want all listeners to see the EOF, so never remove it.
- * It will get cleaned up when the connection is closed
- * in conn_put().
- */
- if (kf->handle != H_EOF)
- TAILQ_REMOVE(&kc->frameq, kf, tq);
-
- /*
- * Remove the event first, and then call the callback.
- * We remove it first because we don't want to get in their
- * way if they reschedule it.
- */
- krb5_stream_read_cancel(ks);
-
- enctok = &kf->tok;
-
- if (enctok->length == 0) {
- assert(kf->handle == H_EOF);
- k5printf(("krb5: stream_read_callback: EOF\n"));
- (*ks->fn)(ks->arg, NULL, 0);
- return (1); /* stop after EOF */
- }
-
-#ifdef AMANDA_KRB5_ENCRYPT
- dectok = &tok;
- if (kdecrypt(ks, enctok, &tok) < 0) {
- k5printf(("krb5: stream_read_callback: kdecrypt error\n"));
- (*ks->fn)(ks->arg, NULL, -1);
- } else
-#else
- dectok = enctok;
-#endif
- {
- k5printf(("krb5: stream_read_callback: read %d bytes from %s:%d\n",
- dectok->length, ks->kc->hostname, ks->handle));
- (*ks->fn)(ks->arg, dectok->value, (ssize_t)dectok->length);
-#ifdef AMANDA_KRB5_ENCRYPT
- gss_release_buffer(&min_stat, dectok);
-#endif
- }
- amfree(enctok->value);
- amfree(kf);
- return (1); /* stop after one frame */
- }
- return (0);
-}
-
-/*
- * The callback for the netfd for the event handler
- * Determines if this packet is for this security handle,
- * and does the real callback if so.
- */
-static void
-conn_read_callback(
- void * cookie)
-{
- struct krb5_conn *kc = cookie;
- struct krb5_handle *kh;
- struct krb5_frame *kf;
- pkt_t pkt;
- gss_buffer_desc *dectok;
- int rc;
-#ifdef AMANDA_KRB5_ENCRYPT
- gss_buffer_desc tok;
- OM_uint32 min_stat;
-#endif
-
- assert(cookie != NULL);
-
- k5printf(("krb5: conn_read_callback\n"));
-
- kf = alloc(SIZEOF(*kf));
- TAILQ_INSERT_TAIL(&kc->frameq, kf, tq);
-
- /* Read the data off the wire. If we get errors, shut down. */
- rc = recv_token(kc, &kf->handle, &kf->tok, 5);
- k5printf(("krb5: conn_read_callback: recv_token returned %d handle = %d\n",
- rc, kf->handle));
- if (rc <= 0) {
- kf->tok.value = NULL;
- kf->tok.length = 0;
- kf->handle = H_EOF;
- rc = event_wakeup((event_id_t)kc);
- k5printf(("krb5: conn_read_callback: event_wakeup return %d\n", rc));
- return;
- }
-
- /* If there are events waiting on this handle, we're done */
- rc = event_wakeup((event_id_t)kc);
- k5printf(("krb5: conn_read_callback: event_wakeup return %d\n", rc));
- if (rc > 0)
- return;
-
- /*
- * If there is no accept fn registered, then just leave the
- * packet queued. The caller may register a function later.
- */
- if (accept_fn == NULL) {
- k5printf(("krb5: no accept_fn so leaving packet queued.\n"));
- return;
- }
-
- kh = alloc(SIZEOF(*kh));
- security_handleinit(&kh->sech, &krb5_security_driver);
- kh->hostname = stralloc(kc->hostname);
- kh->ks = krb5_stream_client(kh, kf->handle);
- kh->ev_wait = NULL;
- kh->ev_timeout = NULL;
-
- TAILQ_REMOVE(&kc->frameq, kf, tq);
- k5printf(("krb5: new connection\n"));
-#ifdef AMANDA_KRB5_ENCRYPT
- dectok = &tok;
- rc = kdecrypt(kh->ks, &kf->tok, dectok);
-#else
- dectok = &kf->tok;
-#endif
-
-#ifdef AMANDA_KRB5_ENCRYPT
- if (rc < 0) {
- security_seterror(&kh->sech, security_geterror(&kh->ks->secstr));
- (*accept_fn)(&kh->sech, NULL);
- } else
-#endif
- {
- parse_pkt(&pkt, dectok->value, dectok->length);
-#ifdef AMANDA_KRB5_ENCRYPT
- gss_release_buffer(&min_stat, dectok);
-#endif
- (*accept_fn)(&kh->sech, &pkt);
- }
- amfree(kf->tok.value);
- amfree(kf);
-
- /*
- * We can only accept one connection per process, since we're tcp
- * based and run out of inetd. So, delete our accept reference once
- * we've gotten the first connection.
- */
-
- /*
- * [XXX] actually, the protocol has been changed to have multiple
- * requests in one session be possible. By not resetting accept_fn,
- * this will caused them to be properly processed. this needs to be
- * addressed in a much cleaner way.
- */
- if (accept_fn != NULL)
- conn_put(kc);
- /* accept_fn = NULL; */
-}