📄 security-util.c
字号:
}/* * Transmit a packet. Add security information first. */ssize_tudpbsd_sendpkt( void * cookie, pkt_t * pkt){ struct sec_handle *rh = cookie; struct passwd *pwd; assert(rh != NULL); assert(pkt != NULL); auth_debug(1, _("udpbsd_sendpkt: enter\n")); /* * Initialize this datagram, and add the header */ dgram_zero(&rh->udp->dgram); dgram_cat(&rh->udp->dgram, pkthdr2str(rh, pkt)); /* * Add the security info. This depends on which kind of packet we're * sending. */ switch (pkt->type) { case P_REQ: /* * Requests get sent with our username in the body */ if ((pwd = getpwuid(geteuid())) == NULL) { security_seterror(&rh->sech, _("can't get login name for my uid %ld"), (long)getuid()); return (-1); } dgram_cat(&rh->udp->dgram, _("SECURITY USER %s\n"), pwd->pw_name); break; default: break; } /* * Add the body, and send it */ dgram_cat(&rh->udp->dgram, pkt->body); auth_debug(1, _("sec: udpbsd_sendpkt: %s (%d) pkt_t (len %zu) contains:\n\n\"%s\"\n\n"), pkt_type2str(pkt->type), pkt->type, strlen(pkt->body), pkt->body); if (dgram_send_addr(&rh->peer, &rh->udp->dgram) != 0) { security_seterror(&rh->sech, _("send %s to %s failed: %s"), pkt_type2str(pkt->type), rh->hostname, strerror(errno)); return (-1); } return (0);}voidudp_close( void * cookie){ struct sec_handle *rh = cookie; if (rh->proto_handle == NULL) { return; } auth_debug(1, _("udp: close handle '%s'\n"), rh->proto_handle); udp_recvpkt_cancel(rh); if (rh->next) { rh->next->prev = rh->prev; } else { rh->udp->bh_last = rh->prev; } if (rh->prev) { rh->prev->next = rh->next; } else { rh->udp->bh_first = rh->next; } amfree(rh->proto_handle); amfree(rh->hostname); amfree(rh);}/* * Set up to receive a packet asynchronously, and call back when it has * been read. */voidudp_recvpkt( void * cookie, void (*fn)(void *, pkt_t *, security_status_t), void * arg, int timeout){ struct sec_handle *rh = cookie; auth_debug(1, _("udp_recvpkt(cookie=%p, fn=%p, arg=%p, timeout=%u)\n"), cookie, fn, arg, timeout); assert(rh != NULL); assert(fn != NULL); /* * Subsequent recvpkt calls override previous ones */ if (rh->ev_read == NULL) { udp_addref(rh->udp, &udp_netfd_read_callback); rh->ev_read = event_register(rh->event_id, EV_WAIT, udp_recvpkt_callback, rh); } if (rh->ev_timeout != NULL) event_release(rh->ev_timeout); if (timeout < 0) rh->ev_timeout = NULL; else rh->ev_timeout = event_register((event_id_t)timeout, EV_TIME, udp_recvpkt_timeout, rh); rh->fn.recvpkt = fn; rh->arg = arg;}/* * Remove a async receive request on this handle from the queue. * If it is the last one to be removed, then remove the event * handler for our network fd */voidudp_recvpkt_cancel( void * cookie){ struct sec_handle *rh = cookie; assert(rh != NULL); if (rh->ev_read != NULL) { udp_delref(rh->udp); event_release(rh->ev_read); rh->ev_read = NULL; } if (rh->ev_timeout != NULL) { event_release(rh->ev_timeout); rh->ev_timeout = NULL; }}/* * This is called when a handle is woken up because data read off of the * net is for it. */voidudp_recvpkt_callback( void * cookie){ struct sec_handle *rh = cookie; void (*fn)(void *, pkt_t *, security_status_t); void *arg; auth_debug(1, _("udp: receive handle '%s' netfd '%s'\n"), rh->proto_handle, rh->udp->handle); assert(rh != NULL); /* if it doesn't correspond to this handle, something is wrong */ assert(strcmp(rh->proto_handle, rh->udp->handle) == 0); /* if it didn't come from the same host/port, forget it */ if (cmp_sockaddr(&rh->peer, &rh->udp->peer, 0) != 0) { amfree(rh->udp->handle); dbprintf(_("not from same host\n")); dump_sockaddr(&rh->peer); dump_sockaddr(&rh->udp->peer); return; } /* * We need to cancel the recvpkt request before calling the callback * because the callback may reschedule us. */ fn = rh->fn.recvpkt; arg = rh->arg; udp_recvpkt_cancel(rh); /* * Check the security of the packet. If it is bad, then pass NULL * to the packet handling function instead of a packet. */ if (rh->udp->recv_security_ok && rh->udp->recv_security_ok(rh, &rh->udp->pkt) < 0) { (*fn)(arg, NULL, S_ERROR); } else { (*fn)(arg, &rh->udp->pkt, S_OK); }}/* * This is called when a handle times out before receiving a packet. */voidudp_recvpkt_timeout( void * cookie){ struct sec_handle *rh = cookie; void (*fn)(void *, pkt_t *, security_status_t); void *arg; assert(rh != NULL); assert(rh->ev_timeout != NULL); fn = rh->fn.recvpkt; arg = rh->arg; udp_recvpkt_cancel(rh); (*fn)(arg, NULL, S_TIMEOUT);}/* * Given a hostname and a port, setup a udp_handle */intudp_inithandle( udp_handle_t * udp, struct sec_handle * rh, char * hostname, struct sockaddr_storage *addr, in_port_t port, char * handle, int sequence){ /* * Save the hostname and port info */ auth_debug(1, _("udp_inithandle port %u handle %s sequence %d\n"), (unsigned int)ntohs(port), handle, sequence); assert(addr != NULL); rh->hostname = stralloc(hostname); copy_sockaddr(&rh->peer, addr); SS_SET_PORT(&rh->peer, port); rh->prev = udp->bh_last; if (udp->bh_last) { rh->prev->next = rh; } if (!udp->bh_first) { udp->bh_first = rh; } rh->next = NULL; udp->bh_last = rh; rh->sequence = sequence; rh->event_id = (event_id_t)newevent++; amfree(rh->proto_handle); rh->proto_handle = stralloc(handle); rh->fn.connect = NULL; rh->arg = NULL; rh->ev_read = NULL; rh->ev_timeout = NULL; auth_debug(1, _("udp: adding handle '%s'\n"), rh->proto_handle); return(0);}/* * Callback for received packets. This is the function bsd_recvpkt * registers with the event handler. It is called when the event handler * realizes that data is waiting to be read on the network socket. */voidudp_netfd_read_callback( void * cookie){ struct udp_handle *udp = cookie; struct sec_handle *rh; int a; char hostname[NI_MAXHOST]; in_port_t port; char *errmsg = NULL; int result; auth_debug(1, _("udp_netfd_read_callback(cookie=%p)\n"), cookie); assert(udp != NULL); #ifndef TEST /* { */ /* * Receive the packet. */ dgram_zero(&udp->dgram); if (dgram_recv(&udp->dgram, 0, &udp->peer) < 0) return;#endif /* !TEST */ /* } */ /* * Parse the packet. */ if (str2pkthdr(udp) < 0) return; /* * If there are events waiting on this handle, we're done */ rh = udp->bh_first; while(rh != NULL && (strcmp(rh->proto_handle, udp->handle) != 0 || rh->sequence != udp->sequence || cmp_sockaddr(&rh->peer, &udp->peer, 0) != 0)) { rh = rh->next; } if (rh && event_wakeup(rh->event_id) > 0) return; /* * If we didn't find a handle, then check for a new incoming packet. * If no accept handler was setup, then just return. */ if (udp->accept_fn == NULL) { dbprintf(_("Receive packet from unknown source")); return; } rh = alloc(SIZEOF(*rh)); rh->proto_handle=NULL; rh->udp = udp; rh->rc = NULL; security_handleinit(&rh->sech, udp->driver); result = getnameinfo((struct sockaddr *)&udp->peer, SS_LEN(&udp->peer), hostname, sizeof(hostname), NULL, 0, 0); if (result != 0) { dbprintf("getnameinfo failed: %s\n", gai_strerror(result)); security_seterror(&rh->sech, "getnameinfo failed: %s", gai_strerror(result)); return; } if (check_name_give_sockaddr(hostname, (struct sockaddr *)&udp->peer, &errmsg) < 0) { security_seterror(&rh->sech, "%s",errmsg); amfree(errmsg); amfree(rh); return; } port = SS_GET_PORT(&udp->peer); a = udp_inithandle(udp, rh, hostname, &udp->peer, port, udp->handle, udp->sequence); if (a < 0) { auth_debug(1, _("bsd: closeX handle '%s'\n"), rh->proto_handle); amfree(rh); return; } /* * Check the security of the packet. If it is bad, then pass NULL * to the accept function instead of a packet. */ if (rh->udp->recv_security_ok(rh, &udp->pkt) < 0) (*udp->accept_fn)(&rh->sech, NULL); else (*udp->accept_fn)(&rh->sech, &udp->pkt);}/* * Locate an existing connection to the given host, or create a new, * unconnected entry if none exists. The caller is expected to check * for the lack of a connection (rc->read == -1) and set one up. */struct tcp_conn *sec_tcp_conn_get( const char *hostname, int want_new){ struct tcp_conn *rc; auth_debug(1, _("sec_tcp_conn_get: %s\n"), hostname); if (want_new == 0) { for (rc = connq_first(); rc != NULL; rc = connq_next(rc)) { if (strcasecmp(hostname, rc->hostname) == 0) break; } if (rc != NULL) { rc->refcnt++; auth_debug(1, _("sec_tcp_conn_get: exists, refcnt to %s is now %d\n"), rc->hostname, rc->refcnt); return (rc); } } auth_debug(1, _("sec_tcp_conn_get: creating new handle\n")); /* * We can't be creating a new handle if we are the client */ rc = alloc(SIZEOF(*rc)); rc->read = rc->write = -1; rc->driver = NULL; rc->pid = -1; rc->ev_read = NULL; rc->toclose = 0; rc->donotclose = 0; strncpy(rc->hostname, hostname, SIZEOF(rc->hostname) - 1); rc->hostname[SIZEOF(rc->hostname) - 1] = '\0'; rc->errmsg = NULL; rc->refcnt = 1; rc->handle = -1; rc->pkt = NULL; rc->accept_fn = NULL; rc->recv_security_ok = NULL; rc->prefix_packet = NULL; rc->auth = 0; rc->conf_fn = NULL; rc->datap = NULL; connq_append(rc); return (rc);}/* * Delete a reference to a connection, and close it if it is the last * reference. */voidsec_tcp_conn_put( struct tcp_conn * rc){ amwait_t status; assert(rc->refcnt > 0); --rc->refcnt; auth_debug(1, _("sec_tcp_conn_put: decrementing refcnt for %s to %d\n"), rc->hostname, rc->refcnt); if (rc->refcnt > 0) { return; } auth_debug(1, _("sec_tcp_conn_put: closing connection to %s\n"), rc->hostname); if (rc->read != -1) aclose(rc->read); if (rc->write != -1) aclose(rc->write); if (rc->pid != -1) { waitpid(rc->pid, &status, WNOHANG); } if (rc->ev_read != NULL) event_release(rc->ev_read); if (rc->errmsg != NULL) amfree(rc->errmsg); connq_remove(rc); amfree(rc->pkt); if(!rc->donotclose) amfree(rc); /* someone might still use it */ /* eg. in sec_tcp_conn_read_callback if */ /* event_wakeup call us. */}/* * Turn on read events for a conn. Or, increase a ev_read_refcnt if we are * already receiving read events. */voidsec_tcp_conn_read( struct tcp_conn * rc){ assert (rc != NULL); if (rc->ev_read != NULL) { rc->ev_read_refcnt++; auth_debug(1, _("sec: conn_read: incremented ev_read_refcnt to %d for %s\n"), rc->ev_read_refcnt, rc->hostname); return; } auth_debug(1, _("sec: conn_read registering event handler for %s\n"), rc->hostname); rc->ev_read = event_register((event_id_t)rc->read, EV_READFD, sec_tcp_conn_read_callback, rc); rc->ev_read_refcnt = 1;}static voidsec_tcp_conn_read_cancel( struct tcp_conn * rc){ --rc->ev_read_refcnt; auth_debug(1, _("sec: conn_read_cancel: decremented ev_read_refcnt to %d for %s\n"), rc->ev_read_refcnt, rc->hostname); if (rc->ev_read_refcnt > 0) { return; } auth_debug(1, _("sec: conn_read_cancel: releasing event handler for %s\n"), rc->hostname); event_release(rc->ev_read); rc->ev_read = NULL;}/* * This is called when a handle is woken up because data read off of the * net is for it. */static voidrecvpkt_callback( void * cookie, void * buf, ssize_t bufsize){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -