int do_krb5_comm(krb5_context context, krb5_keytab keytab, krb5_principal server, char *cmddir) { struct sockaddr_in c_saddr, s_saddr; socklen_t namelen; int sock = 0; int len; char buff[BUFFSIZE]; char *cname = NULL; krb5_error_code retval; krb5_data kdata, message; krb5_auth_context auth_context = NULL; krb5_ticket *ticket; krb5_address ckaddr, skaddr; krb5_rcache rcache; krb5_data rcache_name; long srand, rrand; int fd[2]; char rcname_piece[RC_PIECE_MAXLEN]; namelen = sizeof(c_saddr); if (getpeername(sock, (struct sockaddr *)&c_saddr, &namelen) < 0) { syslog(LOG_ERR, "getpeername: %m"); return 1; } namelen = sizeof(s_saddr); if (getsockname(sock, (struct sockaddr *)&s_saddr, &namelen) < 0) { syslog(LOG_ERR, "getsockname: %m"); return 1; } /* INIT MSG = random number */ srand = random(); /* Send it */ if (send(sock, &srand, sizeof(srand), 0) < 0) { syslog(LOG_ERR, "%m while sending init message"); return 1; } if (recv(sock, &rrand, sizeof(rrand), 0) < 0) { syslog(LOG_ERR, "%m while receiving init reply"); return 1; } /* Reply should contain the same message (number) */ if (srand != rrand) { syslog(LOG_ERR, "Bad init reply"); return 1; } /* Do authentication */ if (retval = krb5_recvauth(context, &auth_context, (krb5_pointer)&sock, AFSADM_VERSION, server, 0, keytab, &ticket)) { syslog(LOG_ERR, "recvauth failed: %s", error_message(retval)); exit(1); } /* Get client name */ if (retval = krb5_unparse_name(context, ticket->enc_part2->client, &cname)) { syslog(LOG_ERR, "unparse failed: %s", error_message(retval)); return 1; } if (ticket) krb5_free_ticket(context, ticket); if (debug) syslog(LOG_DEBUG, "Principal %s", cname); /*******************************************************************/ ckaddr.addrtype = ADDRTYPE_IPPORT; ckaddr.length = sizeof(c_saddr.sin_port); ckaddr.contents = (krb5_octet *)&c_saddr.sin_port; skaddr.addrtype = ADDRTYPE_IPPORT; skaddr.length = sizeof(s_saddr.sin_port); skaddr.contents = (krb5_octet *)&s_saddr.sin_port; if ((retval = krb5_auth_con_setports(context, auth_context, &skaddr, &ckaddr))) { syslog(LOG_ERR, "%s while setting ports", error_message(retval)); return 1; } /* Set foreign_addr for rd_priv() */ ckaddr.addrtype = ADDRTYPE_INET; ckaddr.length = sizeof(c_saddr.sin_addr); ckaddr.contents = (krb5_octet *)&c_saddr.sin_addr; /* Set local_addr */ skaddr.addrtype = ADDRTYPE_INET; skaddr.length = sizeof(s_saddr.sin_addr); skaddr.contents = (krb5_octet *)&s_saddr.sin_addr; if ((retval = krb5_auth_con_setaddrs(context, auth_context, &skaddr, &ckaddr))) { syslog(LOG_ERR, "%s while setting addrs", error_message(retval)); return 1; } /* Receive a request */ if ((len = recv(sock, (char *)buff, sizeof(buff), 0)) < 0) { syslog(LOG_ERR, "%m while receiving datagram"); return 1; } kdata.length = len; kdata.data = buff; if (debug) syslog(LOG_DEBUG, "Received %d bytes", len); /* Decrypt it */ if ((retval = krb5_rd_priv(context, auth_context, &kdata, &message, NULL))) { syslog(LOG_ERR, "%s while verifying PRIV message", error_message(retval)); return 1; } if (message.length > 0) { #ifdef __osf__ sprintf(rcname_piece, "afsadmd_%d", getpid()); #else snprintf(rcname_piece, RC_PIECE_MAXLEN, "afsadmd_%d", getpid()); #endif rcache_name.data = rcname_piece; rcache_name.length = strlen(rcache_name.data); if ((retval = krb5_get_server_rcache(context, &rcache_name, &rcache))) { syslog(LOG_ERR, "%s while getting server rcache", error_message(retval)); return 1; } /* set auth_context rcache */ if (retval = krb5_auth_con_setrcache(context, auth_context, rcache)) { syslog(LOG_ERR, "%s while setting rcache", error_message(retval)); return 1; } /********************************************************************* * Call the desired command, read stdout/stderr, send it *********************************************************************/ /* create fork */ if (pipe(fd) == -1) printf("Failed create fork with pipe().\n"); if (fork() == 0) { close(fd[0]); close(1); close(2); dup2(fd[1], 1); dup2(fd[1], 2); /* Call required command */ do_command(context, keytab, server, cname, message.data, cmddir ); krb5_xfree(message.data); exit(0); } else { /* Read stdout/stderr from pipe, store it to the buffer, encrypt it a send to the client */ krb5_data message, kdata; char buff[PIPEBUFF]; int n = 0; int len = 0; int sent = 0; int counter = 0; int end = 0; short netlen; time_t starttime, oldtime, newtime; FILE *pipedes; close(fd[1]); pipedes = fdopen(fd[0], "r"); starttime = oldtime = time(NULL); for (n = 0; end == 0; ) { /* Read line from pipe */ if (fgets(buff + n, PIPEBUFF - n, pipedes) == NULL) end++; else n = strlen(buff); /* Get time */ newtime = time(NULL); /* Send buffer when * a) buffer is full * b) buffer contains data and * 1) end-of-file encountered (end flag) * 2) buffer sent before 1s */ if ((n == PIPEBUFF) || (((newtime > oldtime) || end ) && (n != 0))) { /* Prepare data for sending */ message.data = buff; message.length = n; kdata.data = NULL; /* Make the encrypted message */ if ((retval = krb5_mk_priv(context, auth_context, &message, &kdata, NULL))) { syslog(LOG_ERR, "%s while making KRB_PRIV message", error_message(retval)); return 1; } /* Convert byte order */ netlen = htons((short)kdata.length); /* Send len of encrypted data */ if ((len = send(sock, (char *)&netlen, sizeof(netlen), 0)) != sizeof(netlen)) { krb5_xfree(kdata.data); syslog(LOG_ERR, "%m while sending len of PRIV message"); return 1; } /* Send it */ if ((len = send(sock, (char *)kdata.data, kdata.length, 0)) != kdata.length) { syslog(LOG_ERR, "%m while sending PRIV message"); krb5_xfree(kdata.data); return 1; } /* Statistics */ sent += len; counter++; /* Timestanmp */ oldtime = newtime; n = 0; krb5_xfree(kdata.data); } } newtime = time(NULL); if (debug) syslog(LOG_DEBUG, "Sent %d bytes in %ds [%d fragment(s)]", sent, (int)(newtime - starttime), counter); } } //FIXME: There is no way to close or destroy rcache declared in krb5 headers //krb5_rc_destroy(context, rcache); /* set auth_context rcache */ if (retval = krb5_auth_con_setrcache(context, auth_context, rcache)) { syslog(LOG_ERR, "%s while setting rcache to NULL", error_message(retval)); return 1; } free(cname); krb5_auth_con_free(context, auth_context); return 0; }
/* * Serialize krb5_auth_context. */ static krb5_error_code ser_acontext_test(krb5_context kcontext, int verbose) { krb5_error_code kret; krb5_auth_context actx; krb5_address local_address; krb5_address remote_address; krb5_octet laddr_bytes[16]; krb5_octet raddr_bytes[16]; krb5_keyblock ukeyblock; krb5_octet keydata[8]; krb5_authenticator aent; char clname[128]; krb5_authdata *adatalist[3]; krb5_authdata adataent; actx = (krb5_auth_context) NULL; if (!(kret = krb5_auth_con_init(kcontext, &actx)) && !(kret = ser_data(verbose, "> Vanilla auth context", (krb5_pointer) actx, KV5M_AUTH_CONTEXT))) { memset(&local_address, 0, sizeof(local_address)); memset(&remote_address, 0, sizeof(remote_address)); memset(laddr_bytes, 0, sizeof(laddr_bytes)); memset(raddr_bytes, 0, sizeof(raddr_bytes)); local_address.addrtype = ADDRTYPE_INET; local_address.length = sizeof(laddr_bytes); local_address.contents = laddr_bytes; laddr_bytes[0] = 6; laddr_bytes[1] = 2; laddr_bytes[2] = 69; laddr_bytes[3] = 16; laddr_bytes[4] = 1; laddr_bytes[5] = 0; laddr_bytes[6] = 0; laddr_bytes[7] = 127; remote_address.addrtype = ADDRTYPE_INET; remote_address.length = sizeof(raddr_bytes); remote_address.contents = raddr_bytes; raddr_bytes[0] = 6; raddr_bytes[1] = 2; raddr_bytes[2] = 70; raddr_bytes[3] = 16; raddr_bytes[4] = 1; raddr_bytes[5] = 0; raddr_bytes[6] = 0; raddr_bytes[7] = 127; if (!(kret = krb5_auth_con_setaddrs(kcontext, actx, &local_address, &remote_address)) && !(kret = krb5_auth_con_setports(kcontext, actx, &local_address, &remote_address)) && !(kret = ser_data(verbose, "> Auth context with addrs/ports", (krb5_pointer) actx, KV5M_AUTH_CONTEXT))) { memset(&ukeyblock, 0, sizeof(ukeyblock)); memset(keydata, 0, sizeof(keydata)); ukeyblock.enctype = ENCTYPE_DES_CBC_MD5; ukeyblock.length = sizeof(keydata); ukeyblock.contents = keydata; keydata[0] = 0xde; keydata[1] = 0xad; keydata[2] = 0xbe; keydata[3] = 0xef; keydata[4] = 0xfe; keydata[5] = 0xed; keydata[6] = 0xf0; keydata[7] = 0xd; if (!(kret = krb5_auth_con_setuseruserkey(kcontext, actx, &ukeyblock)) && !(kret = ser_data(verbose, "> Auth context with user key", (krb5_pointer) actx, KV5M_AUTH_CONTEXT)) && !(kret = krb5_auth_con_initivector(kcontext, actx)) && !(kret = ser_data(verbose, "> Auth context with new vector", (krb5_pointer) actx, KV5M_AUTH_CONTEXT)) && (krb5_xfree(actx->i_vector), actx->i_vector) && !(kret = krb5_auth_con_setivector(kcontext, actx, (krb5_pointer) print_erep) ) && !(kret = ser_data(verbose, "> Auth context with set vector", (krb5_pointer) actx, KV5M_AUTH_CONTEXT))) { /* * Finally, add an authenticator. */ memset(&aent, 0, sizeof(aent)); aent.magic = KV5M_AUTHENTICATOR; snprintf(clname, sizeof(clname), "help/me/%[email protected]", (int) getpid()); actx->authentp = &aent; if (!(kret = krb5_parse_name(kcontext, clname, &aent.client)) && !(kret = ser_data(verbose, "> Auth context with authenticator", (krb5_pointer) actx, KV5M_AUTH_CONTEXT))) { adataent.magic = KV5M_AUTHDATA; adataent.ad_type = 123; adataent.length = 128; adataent.contents = (krb5_octet *) stuff; adatalist[0] = &adataent; adatalist[1] = &adataent; adatalist[2] = (krb5_authdata *) NULL; aent.authorization_data = adatalist; if (!(kret = ser_data(verbose, "> Auth context with full auth", (krb5_pointer) actx, KV5M_AUTH_CONTEXT))) { if (verbose) printf("* krb5_auth_context test succeeded\n"); } krb5_free_principal(kcontext, aent.client); } actx->authentp = (krb5_authenticator *) NULL; } } } if (actx) krb5_auth_con_free(kcontext, actx); if (kret) printf("* krb5_auth_context test failed\n"); return(kret); }
/* XXX - check for cleanup */ krb5_error_code setup_auth_context(krb5_context context, krb5_auth_context auth_context, struct sockaddr_in *localaddr, struct sockaddr_in *remoteaddr, char *uniq) { krb5_address laddr, raddr, *portlocal_addr; krb5_rcache rcache; krb5_data rcache_name; char *outaddr; krb5_error_code retval; #ifndef HEIMDAL /* Setting ports isn't compatible with Heimdal, if this code is enabled, it's not possible to have an interoperable setup */ #if 0 laddr.addrtype = ADDRTYPE_IPPORT; laddr.length = sizeof(localaddr->sin_port); laddr.contents = (krb5_octet *)&(localaddr->sin_port); raddr.addrtype = ADDRTYPE_IPPORT; raddr.length = sizeof(remoteaddr->sin_port); raddr.contents = (krb5_octet *)&(remoteaddr->sin_port); if (retval = krb5_auth_con_setports(context, auth_context, &laddr, &raddr)) { sprintf(auth_con_error, "%s while setting auth_con ports\n", error_message(retval)); return retval; } #endif #endif #ifdef HEIMDAL laddr.addr_type = KRB5_ADDRESS_INET; laddr.address.length = sizeof(localaddr->sin_addr); laddr.address.data = (void *)&(localaddr->sin_addr); raddr.addr_type = KRB5_ADDRESS_INET; raddr.address.length = sizeof(remoteaddr->sin_addr); raddr.address.data = (void *)&(remoteaddr->sin_addr); #else laddr.addrtype = ADDRTYPE_INET; laddr.length = sizeof(localaddr->sin_addr); laddr.contents = (krb5_octet *)&(localaddr->sin_addr); raddr.addrtype = ADDRTYPE_INET; raddr.length = sizeof(remoteaddr->sin_addr); raddr.contents = (krb5_octet *)&(remoteaddr->sin_addr); #endif if (retval = krb5_auth_con_setaddrs(context, auth_context, &laddr, &raddr)) { sprintf(auth_con_error, "%s while setting auth_con addresses\n", error_message(retval)); return retval; } #ifdef HEIMDAL #else /* Set up replay cache */ if ((retval = krb5_gen_portaddr(context, &laddr, (krb5_pointer) &(localaddr->sin_port), &portlocal_addr))) { sprintf(auth_con_error, "%s while generating port address", error_message(retval)); return retval; } if ((retval = krb5_gen_replay_name(context, portlocal_addr, uniq, &outaddr))) { sprintf(auth_con_error, "%s while generating replay cache name", error_message(retval)); return retval; } rcache_name.length = strlen(outaddr); rcache_name.data = outaddr; if ((retval = krb5_get_server_rcache(context, &rcache_name, &rcache))) { sprintf(auth_con_error, "%s while getting server rcache", error_message(retval)); return retval; } if (retval = krb5_auth_con_setrcache(context, auth_context, rcache)) { sprintf(auth_con_error, "%s setting rcache", error_message(retval)); return retval; } #endif return retval; }
krb5_error_code KRB5_CALLCONV krb5_auth_con_genaddrs(krb5_context context, krb5_auth_context auth_context, int infd, int flags) { krb5_error_code retval; krb5_address * laddr; krb5_address * lport; krb5_address * raddr; krb5_address * rport; SOCKET fd = (SOCKET) infd; struct addrpair laddrs, raddrs; #ifdef HAVE_NETINET_IN_H struct sockaddr_storage lsaddr, rsaddr; GETSOCKNAME_ARG3_TYPE ssize; ssize = sizeof(struct sockaddr_storage); if ((flags & KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR) || (flags & KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR)) { retval = getsockname(fd, ss2sa(&lsaddr), &ssize); if (retval) return retval; if (cvtaddr (&lsaddr, &laddrs)) { laddr = &laddrs.addr; if (flags & KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR) lport = &laddrs.port; else lport = 0; } else return KRB5_PROG_ATYPE_NOSUPP; } else { laddr = NULL; lport = NULL; } ssize = sizeof(struct sockaddr_storage); if ((flags & KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR) || (flags & KRB5_AUTH_CONTEXT_GENERATE_REMOTE_ADDR)) { retval = getpeername(fd, ss2sa(&rsaddr), &ssize); if (retval) return errno; if (cvtaddr (&rsaddr, &raddrs)) { raddr = &raddrs.addr; if (flags & KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR) rport = &raddrs.port; else rport = 0; } else return KRB5_PROG_ATYPE_NOSUPP; } else { raddr = NULL; rport = NULL; } if (!(retval = krb5_auth_con_setaddrs(context, auth_context, laddr, raddr))) return (krb5_auth_con_setports(context, auth_context, lport, rport)); return retval; #else return KRB5_PROG_ATYPE_NOSUPP; #endif }