/* * Kerberized NNTP connection forwarder; client side. * * $Id: client.c,v 1.1 1999/12/12 08:36:52 kolya Exp $ * * kolya@MIT.EDU, 11 December 1999 */ #include "krb5.h" #include "com_err.h" #include #include #include #include #include #include #include #include #include #include #include "knntp.h" int main(int argc, char *argv[]) { struct hostent *hp; struct sockaddr_in server_sin, server_lsin, sin, lsin; int sock, namelen; krb5_data cksum_data; krb5_error_code retval; krb5_ccache ccdef; krb5_principal client, server; krb5_error *err_ret; krb5_ap_rep_enc_part *rep_ret; char *service = KNNTP_SERVICE; int listen_sock = 0; int client_sock = 0; int on = 1; fd_set all_fds; char read_buf[BUFSIZ]; krb5_context context; krb5_auth_context auth_context = NULL; if (argc != 2 && argc != 3) { fprintf(stderr, "usage: %s [port]\n",argv[0]); exit(1); } listen_sock = socket(AF_INET, SOCK_STREAM, 0); if(listen_sock < 0) { perror("creating socket"); exit(1); } setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); server_sin.sin_port = htons(LISTEN_PORT); server_sin.sin_family = AF_INET; server_sin.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(listen_sock, (struct sockaddr *)&server_sin, sizeof(server_sin))) { perror("binding to socket"); exit(1); } if(listen(listen_sock, 5) < 0) { perror("listening on socket"); exit(1); } namelen = sizeof(server_lsin); while((client_sock = accept(listen_sock, (struct sockaddr *)&server_lsin, &namelen)) >= 0) { if(!fork()) break; else close(client_sock); } if(client_sock < 0) { perror("accepting connection"); exit(1); } if(ntohl(server_lsin.sin_addr.s_addr) == INADDR_LOOPBACK) { printf("Forwarding KNNTP connection from %s..\n", inet_ntoa(server_lsin.sin_addr)); } else { char *msg = "502 KNNTP only forwards connections from localhost.\n"; printf("Connection from %s refused.\n", inet_ntoa(server_lsin.sin_addr)); write(client_sock, msg, strlen(msg)); exit(1); } retval = krb5_init_context(&context); if (retval) { com_err(argv[0], retval, "while initializing krb5"); exit(1); } (void) signal(SIGPIPE, SIG_IGN); if (!valid_cksumtype(CKSUMTYPE_CRC32)) { com_err(argv[0], KRB5_PROG_SUMTYPE_NOSUPP, "while using CRC-32"); exit(1); } /* clear out the structure first */ (void) memset((char *)&sin, 0, sizeof(sin)); if (argc > 2) { sin.sin_family = AF_INET; sin.sin_port = htons(atoi(argv[2])); } else { /* copy the port number */ sin.sin_port = htons(KNNTP_PORT); sin.sin_family = AF_INET; } /* look up the server host */ hp = gethostbyname(argv[1]); if (!hp) { fprintf(stderr, "unknown host %s\n",argv[1]); exit(1); } if (retval = krb5_sname_to_principal(context, argv[1], service, KRB5_NT_SRV_HST, &server)) { com_err(argv[0], retval, "while creating server name for %s/%s", argv[1], service); exit(1); } /* set up the address of the foreign socket for connect() */ sin.sin_family = hp->h_addrtype; (void) memcpy((char *)&sin.sin_addr, (char *)hp->h_addr, sizeof(hp->h_addr)); /* open a TCP socket */ sock = socket(PF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("socket"); exit(1); } /* connect to the server */ if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) { perror("connect"); close(sock); exit(1); } /* find out who I am, now that we are connected and therefore bound */ namelen = sizeof(lsin); if (getsockname(sock, (struct sockaddr *) &lsin, &namelen) < 0) { perror("getsockname"); close(sock); exit(1); } cksum_data.data = argv[1]; cksum_data.length = strlen(argv[1]); if (retval = krb5_cc_default(context, &ccdef)) { com_err(argv[0], retval, "while getting default ccache"); exit(1); } if (retval = krb5_cc_get_principal(context, ccdef, &client)) { com_err(argv[0], retval, "while getting client principal name"); exit(1); } retval = krb5_sendauth(context, &auth_context, (krb5_pointer) &sock, KNNTP_VERSION, client, server, AP_OPTS_MUTUAL_REQUIRED, &cksum_data, 0, /* no creds, use ccache instead */ ccdef, &err_ret, &rep_ret, NULL); krb5_free_principal(context, server); /* finished using it */ if (retval && retval != KRB5_SENDAUTH_REJECTED) { com_err(argv[0], retval, "while using sendauth"); exit(1); } if (retval == KRB5_SENDAUTH_REJECTED) { /* got an error */ printf("*** sendauth rejected, error reply is:\n\t\"%*s\"\n", err_ret->text.length, err_ret->text.data); } else if (rep_ret) { /* got a reply */ FD_ZERO(&all_fds); FD_SET(client_sock, &all_fds); FD_SET(sock, &all_fds); while(1) { fd_set rfds = all_fds; int maxFds = MAX(sock, client_sock) + 1; retval = select(maxFds, &rfds, NULL, NULL, NULL); if(retval < 0) perror("selecting fds"); if(FD_ISSET(sock, &rfds)) { retval = read(sock, read_buf, sizeof(read_buf)); if(retval < 0) { perror("receiving from socket"); exit(1); } if(retval == 0) { exit(0); } write(client_sock, read_buf, retval); } if(FD_ISSET(client_sock, &rfds)) { retval = read(client_sock, read_buf, sizeof(read_buf)); if(retval < 0) { perror("receiving from client"); exit(1); } if(retval == 0) { exit(0); } write(sock, read_buf, retval); } } } else { com_err(argv[0], 0, "no error or reply from sendauth!"); exit(1); } exit(0); }