/*! * Return the internal statistics collected by rx * * @return * A statistics structure which must be freed using rx_FreeStatistics * @notes * Takes, and releases rx_stats_mutex */ struct rx_statistics * rx_GetStatistics(void) { struct rx_statistics *stats = rxi_Alloc(sizeof(struct rx_statistics)); MUTEX_ENTER(&rx_stats_mutex); memcpy(stats, &rx_stats, sizeof(struct rx_statistics)); MUTEX_EXIT(&rx_stats_mutex); return stats; }
struct rx_securityClass * rxkad_NewClientSecurityObject(rxkad_level level, struct ktc_encryptionKey *sessionkey, afs_int32 kvno, int ticketLen, char *ticket) { struct rx_securityClass *tsc; struct rxkad_cprivate *tcp; int code; int size, psize; rxkad_Init(); size = sizeof(struct rx_securityClass); tsc = rxi_Alloc(size); memset((void *)tsc, 0, size); tsc->refCount = 1; /* caller gets one for free */ tsc->ops = &rxkad_client_ops; psize = PDATA_SIZE(ticketLen); tcp = rxi_Alloc(psize); memset((void *)tcp, 0, psize); tsc->privateData = (char *)tcp; tcp->type |= rxkad_client; tcp->level = level; code = fc_keysched(sessionkey, tcp->keysched); if (code) { rxi_Free(tcp, psize); rxi_Free(tsc, sizeof(struct rx_securityClass)); return 0; /* bad key */ } memcpy((void *)tcp->ivec, (void *)sessionkey, sizeof(tcp->ivec)); tcp->kvno = kvno; /* key version number */ tcp->ticketLen = ticketLen; /* length of ticket */ if (tcp->ticketLen > MAXKTCTICKETLEN) { rxi_Free(tcp, psize); rxi_Free(tsc, sizeof(struct rx_securityClass)); return 0; /* bad key */ } memcpy(tcp->ticket, ticket, ticketLen); INC_RXKAD_STATS(clientObjects); return tsc; }
struct rx_identity * rx_identity_new(rx_identity_kind kind, char *displayName, void *enameData, size_t enameLength) { struct rx_identity *identity; identity = rxi_Alloc(sizeof(struct rx_identity)); rx_identity_populate(identity, kind, displayName, enameData, enameLength); return identity; }
void handle_socket_error(osi_socket so) { struct msghdr msg; struct cmsghdr *cmsg; struct sock_extended_err *err; struct sockaddr_in addr; struct sockaddr *offender; char *controlmsgbuf; int code; struct socket *sop = (struct socket *)so; if (!(controlmsgbuf=rxi_Alloc(256))) return; msg.msg_name = &addr; msg.msg_namelen = sizeof(addr); msg.msg_control = controlmsgbuf; msg.msg_controllen = 256; msg.msg_flags = 0; code = kernel_recvmsg(sop, &msg, NULL, 0, 0, MSG_ERRQUEUE|MSG_DONTWAIT|MSG_TRUNC); if (code < 0 || !(msg.msg_flags & MSG_ERRQUEUE)) goto out; for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (CMSG_OK(&msg, cmsg) && cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) break; } if (!cmsg) goto out; err = CMSG_DATA(cmsg); offender = SO_EE_OFFENDER(err); if (offender->sa_family != AF_INET) goto out; memcpy(&addr, offender, sizeof(addr)); if (err->ee_origin == SO_EE_ORIGIN_ICMP && err->ee_type == ICMP_DEST_UNREACH && err->ee_code == ICMP_FRAG_NEEDED) { rxi_SetPeerMtu(NULL, ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port), err->ee_info); } /* other DEST_UNREACH's and TIME_EXCEEDED should be dealt with too */ out: rxi_Free(controlmsgbuf, 256); return; }
void rx_identity_populate(struct rx_identity *identity, rx_identity_kind kind, char *displayName, void *enameData, size_t enameLength) { memset(identity, 0, sizeof(struct rx_identity)); identity->kind = kind; identity->displayName = rxi_Alloc(strlen(displayName)+1); memcpy(identity->displayName, displayName, strlen(displayName)+1); rx_opaque_populate(&identity->exportedName, enameData, enameLength); }
struct rx_securityClass * rxkad_NewServerSecurityObject(rxkad_level level, void *get_key_rock, int (*get_key) (void *get_key_rock, int kvno, struct ktc_encryptionKey * serverKey), int (*user_ok) (char *name, char *instance, char *cell, afs_int32 kvno)) { struct rx_securityClass *tsc; struct rxkad_sprivate *tsp; int size; rxkad_Init(); if (!get_key) return 0; size = sizeof(struct rx_securityClass); tsc = rxi_Alloc(size); memset(tsc, 0, size); tsc->refCount = 1; /* caller has one reference */ tsc->ops = &rxkad_server_ops; size = sizeof(struct rxkad_sprivate); tsp = rxi_Alloc(size); memset(tsp, 0, size); tsc->privateData = (char *)tsp; tsp->type |= rxkad_server; /* so can identify later */ tsp->level = level; /* level of encryption */ tsp->get_key_rock = get_key_rock; tsp->get_key = get_key; /* to get server ticket */ tsp->user_ok = user_ok; /* to inform server of client id. */ init_random_int32(); INC_RXKAD_STATS(serverObjects); return tsc; }
static void do_handlesocketerror(osi_socket so) { #ifdef AFS_RXERRQ_ENV char *cmsgbuf; size_t cmsgbuf_len; cmsgbuf_len = 256; cmsgbuf = rxi_Alloc(cmsgbuf_len); if (!cmsgbuf) { return; } while (osi_HandleSocketError(so, cmsgbuf, cmsgbuf_len)) ; rxi_Free(cmsgbuf, cmsgbuf_len); #endif }
/* XXX this does some copying of data in and out of the packet, but I'll bet it * could just do it in place, especially if I used rx_Pullup... */ int rxkad_CheckResponse(struct rx_securityClass *aobj, struct rx_connection *aconn, struct rx_packet *apacket) { struct rxkad_sconn *sconn; struct rxkad_sprivate *tsp; struct ktc_encryptionKey serverKey; struct rxkad_oldChallengeResponse oldr; /* response format */ struct rxkad_v2ChallengeResponse v2r; afs_int32 tlen; /* ticket len */ afs_int32 kvno; /* key version of ticket */ char tix[MAXKTCTICKETLEN]; afs_int32 incChallengeID; rxkad_level level; int code; /* ticket contents */ struct ktc_principal client; struct ktc_encryptionKey sessionkey; afs_int32 host; afs_uint32 start; afs_uint32 end; unsigned int pos; struct rxkad_serverinfo *rock; sconn = rx_GetSecurityData(aconn); tsp = (struct rxkad_sprivate *)aobj->privateData; if (sconn->cksumSeen) { /* expect v2 response, leave fields in v2r in network order for cksum * computation which follows decryption. */ if (rx_GetDataSize(apacket) < sizeof(v2r)) return RXKADPACKETSHORT; rx_packetread(apacket, 0, sizeof(v2r), &v2r); pos = sizeof(v2r); /* version == 2 */ /* ignore spare */ kvno = ntohl(v2r.kvno); tlen = ntohl(v2r.ticketLen); if (rx_GetDataSize(apacket) < sizeof(v2r) + tlen) return RXKADPACKETSHORT; } else { /* expect old format response */ if (rx_GetDataSize(apacket) < sizeof(oldr)) return RXKADPACKETSHORT; rx_packetread(apacket, 0, sizeof(oldr), &oldr); pos = sizeof(oldr); kvno = ntohl(oldr.kvno); tlen = ntohl(oldr.ticketLen); if (rx_GetDataSize(apacket) != sizeof(oldr) + tlen) return RXKADPACKETSHORT; } if ((tlen < MINKTCTICKETLEN) || (tlen > MAXKTCTICKETLEN)) return RXKADTICKETLEN; rx_packetread(apacket, pos, tlen, tix); /* get ticket */ /* * We allow the ticket to be optionally decoded by an alternate * ticket decoder, if the function variable * rxkad_AlternateTicketDecoder is set. That function should * return a code of -1 if it wants the ticket to be decoded by * the standard decoder. */ if (rxkad_AlternateTicketDecoder) { code = rxkad_AlternateTicketDecoder(kvno, tix, tlen, client.name, client.instance, client.cell, &sessionkey, &host, &start, &end); if (code && code != -1) { return code; } } else { code = -1; /* No alternate ticket decoder present */ } /* * If the alternate decoder is not present, or returns -1, then * assume the ticket is of the default style. */ if (code == -1 && ((kvno == RXKAD_TKT_TYPE_KERBEROS_V5) || (kvno == RXKAD_TKT_TYPE_KERBEROS_V5_ENCPART_ONLY))) { code = tkt_DecodeTicket5(tix, tlen, tsp->get_key, tsp->get_key_enctype, tsp->get_key_rock, kvno, client.name, client.instance, client.cell, &sessionkey, &host, &start, &end, tsp->flags & RXS_CONFIG_FLAGS_DISABLE_DOTCHECK); if (code) return code; } /* * If the alternate decoder/kerberos 5 decoder is not present, or * returns -1, then assume the ticket is of the default style. */ if (code == -1) { /* get ticket's key */ code = (*tsp->get_key) (tsp->get_key_rock, kvno, &serverKey); if (code) return RXKADUNKNOWNKEY; /* invalid kvno */ code = tkt_DecodeTicket(tix, tlen, &serverKey, client.name, client.instance, client.cell, &sessionkey, &host, &start, &end); if (code) return code; } code = tkt_CheckTimes(start, end, time(0)); if (code == 0) return RXKADNOAUTH; else if (code == -1) return RXKADEXPIRED; else if (code < -1) return RXKADBADTICKET; code = fc_keysched(&sessionkey, sconn->keysched); if (code) return RXKADBADKEY; memcpy(sconn->ivec, &sessionkey, sizeof(sconn->ivec)); if (sconn->cksumSeen) { /* using v2 response */ afs_uint32 cksum; /* observed cksum */ struct rxkad_endpoint endpoint; /* connections endpoint */ int i; afs_uint32 xor[2]; memcpy(xor, sconn->ivec, 2 * sizeof(afs_int32)); fc_cbc_encrypt(&v2r.encrypted, &v2r.encrypted, sizeof(v2r.encrypted), sconn->keysched, xor, DECRYPT); cksum = rxkad_CksumChallengeResponse(&v2r); if (cksum != v2r.encrypted.endpoint.cksum) return RXKADSEALEDINCON; (void)rxkad_SetupEndpoint(aconn, &endpoint); v2r.encrypted.endpoint.cksum = 0; if (memcmp(&endpoint, &v2r.encrypted.endpoint, sizeof(endpoint)) != 0) return RXKADSEALEDINCON; for (i = 0; i < RX_MAXCALLS; i++) { v2r.encrypted.callNumbers[i] = ntohl(v2r.encrypted.callNumbers[i]); if (v2r.encrypted.callNumbers[i] < 0) return RXKADSEALEDINCON; } (void)rxi_SetCallNumberVector(aconn, v2r.encrypted.callNumbers); incChallengeID = ntohl(v2r.encrypted.incChallengeID); level = ntohl(v2r.encrypted.level); } else { /* expect old format response */ fc_ecb_encrypt(&oldr.encrypted, &oldr.encrypted, sconn->keysched, DECRYPT); incChallengeID = ntohl(oldr.encrypted.incChallengeID); level = ntohl(oldr.encrypted.level); } if (incChallengeID != sconn->challengeID + 1) return RXKADOUTOFSEQUENCE; /* replay attempt */ if ((level < sconn->level) || (level > rxkad_crypt)) return RXKADLEVELFAIL; sconn->level = level; rxkad_SetLevel(aconn, sconn->level); INC_RXKAD_STATS(responses[rxkad_LevelIndex(sconn->level)]); /* now compute endpoint-specific info used for computing 16 bit checksum */ rxkad_DeriveXORInfo(aconn, &sconn->keysched, (char *)sconn->ivec, (char *)sconn->preSeq); /* otherwise things are ok */ sconn->expirationTime = end; sconn->authenticated = 1; if (tsp->user_ok) { code = tsp->user_ok(client.name, client.instance, client.cell, kvno); if (code) return RXKADNOAUTH; } else { /* save the info for later retreival */ int size = sizeof(struct rxkad_serverinfo); rock = rxi_Alloc(size); memset(rock, 0, size); rock->kvno = kvno; memcpy(&rock->client, &client, sizeof(rock->client)); sconn->rock = rock; } return 0; }
/* Add the indicated event (function, arg) at the specified clock time */ struct rxevent * rxevent_Post(struct clock * when, void (*func)(), void *arg, void *arg1) /* when - When event should happen, in clock (clock.h) units */ { struct rxevent *ev, *qe, *qpr; #ifdef RXDEBUG if (Log) { struct clock now; clock_GetTime(&now); fprintf(Log, "%ld.%ld: rxevent_Post(%ld.%ld, %p, %p)\n", now.sec, now.usec, when->sec, when->usec, func, arg); } #endif #if defined(AFS_SGIMP_ENV) ASSERT(osi_rxislocked()); #endif /* * If we're short on free event entries, create a block of new ones and * add them to the free queue */ if (queue_IsEmpty(&rxevent_free)) { int i; #if defined(AFS_AIX32_ENV) && defined(KERNEL) ev = (struct rxevent *) rxi_Alloc(sizeof(struct rxevent)); queue_Append(&rxevent_free, &ev[0]), rxevent_nFree++; #else ev = (struct rxevent *) osi_Alloc(sizeof(struct rxevent) * rxevent_allocUnit); xsp = xfreemallocs; xfreemallocs = (struct xfreelist *) ev; xfreemallocs->next = xsp; for (i = 0; i < rxevent_allocUnit; i++) queue_Append(&rxevent_free, &ev[i]), rxevent_nFree++; #endif } /* Grab and initialize a new rxevent structure */ ev = queue_First(&rxevent_free, rxevent); queue_Remove(ev); rxevent_nFree--; /* Record user defined event state */ ev->eventTime = *when; ev->func = func; ev->arg = arg; ev->arg1 = arg1; rxevent_nPosted += 1; /* Rather than ++, to shut high-C up * regarding never-set variables */ /* * Locate a slot for the new entry. The queue is ordered by time, and we * assume that a new entry is likely to be greater than a majority of the * entries already on the queue (unless there's very few entries on the * queue), so we scan it backwards */ for (queue_ScanBackwards(&rxevent_queue, qe, qpr, rxevent)) { if (clock_Ge(when, &qe->eventTime)) { queue_InsertAfter(qe, ev); return ev; } } /* The event is to expire earlier than any existing events */ queue_Prepend(&rxevent_queue, ev); if (rxevent_ScheduledEarlierEvent) (*rxevent_ScheduledEarlierEvent) (); /* Notify our external * scheduler */ return ev; }