static void one_addr(krb5_address *a) { struct sockaddr_storage ss; struct sockaddr_in *sinp; struct sockaddr_in6 *sin6p; int err; char namebuf[NI_MAXHOST]; memset(&ss, 0, sizeof(ss)); switch (a->addrtype) { case ADDRTYPE_INET: if (a->length != 4) { printf(_("broken address (type %d length %d)"), a->addrtype, a->length); return; } sinp = ss2sin(&ss); sinp->sin_family = AF_INET; memcpy(&sinp->sin_addr, a->contents, 4); break; case ADDRTYPE_INET6: if (a->length != 16) { printf(_("broken address (type %d length %d)"), a->addrtype, a->length); return; } sin6p = ss2sin6(&ss); sin6p->sin6_family = AF_INET6; memcpy(&sin6p->sin6_addr, a->contents, 16); break; default: printf(_("unknown addrtype %d"), a->addrtype); return; } namebuf[0] = 0; err = getnameinfo(ss2sa(&ss), sa_socklen(ss2sa(&ss)), namebuf, sizeof(namebuf), 0, 0, no_resolve ? NI_NUMERICHOST : 0U); if (err) { printf(_("unprintable address (type %d, error %d %s)"), a->addrtype, err, gai_strerror(err)); return; } printf("%s", namebuf); }
static void *cvtaddr (struct sockaddr_storage *a, struct addrpair *ap) { switch (ss2sa(a)->sa_family) { case AF_INET: SET (ap->port, ss2sin(a)->sin_port, ADDRTYPE_IPPORT); SET (ap->addr, ss2sin(a)->sin_addr, ADDRTYPE_INET); return a; case AF_INET6: SET (ap->port, ss2sin6(a)->sin6_port, ADDRTYPE_IPPORT); if (IN6_IS_ADDR_V4MAPPED (&ss2sin6(a)->sin6_addr)) { ap->addr.addrtype = ADDRTYPE_INET; ap->addr.contents = 12 + (krb5_octet *) &ss2sin6(a)->sin6_addr; ap->addr.length = 4; } else SET (ap->addr, ss2sin6(a)->sin6_addr, ADDRTYPE_INET6); return a; default: return 0; } }
/* * Bind a socket to a privileged IP port */ int bindresvport_sa(int sd, struct sockaddr *sa) { int res; static short port; struct sockaddr_storage myaddr; socklen_t salen; int i; #define STARTPORT 600 #define ENDPORT (IPPORT_RESERVED - 1) #define NPORTS (ENDPORT - STARTPORT + 1) if (sa == NULL) { salen = sizeof(myaddr); sa = ss2sa(&myaddr); res = getsockname(sd, sa, &salen); if (res < 0) return (-1); } if (!sa_is_inet(sa)) { errno = EPFNOSUPPORT; return (-1); } if (port == 0) { port = (getpid() % NPORTS) + STARTPORT; } res = -1; errno = EADDRINUSE; for (i = 0; i < NPORTS && res < 0 && errno == EADDRINUSE; i++) { sa_setport(sa, htons(port++)); if (port > ENDPORT) { port = STARTPORT; } res = bind(sd, sa, socklen(sa)); } return (res); }
/* ** The logic for setting and changing a password is mostly the same ** change_set_password handles both cases ** if set_password_for is NULL, then a password change is performed, ** otherwise, the password is set for the principal indicated in set_password_for */ static krb5_error_code change_set_password(krb5_context context, krb5_creds *creds, char *newpw, krb5_principal set_password_for, int *result_code, krb5_data *result_code_string, krb5_data *result_string) { krb5_data chpw_rep; krb5_address remote_kaddr; krb5_boolean use_tcp = 0; GETSOCKNAME_ARG3_TYPE addrlen; krb5_error_code code = 0; char *code_string; int local_result_code; struct sendto_callback_context callback_ctx; struct sendto_callback_info callback_info; struct sockaddr_storage remote_addr; struct serverlist sl = SERVERLIST_INIT; memset(&chpw_rep, 0, sizeof(krb5_data)); memset( &callback_ctx, 0, sizeof(struct sendto_callback_context)); callback_ctx.context = context; callback_ctx.newpw = newpw; callback_ctx.set_password_for = set_password_for; if ((code = krb5_auth_con_init(callback_ctx.context, &callback_ctx.auth_context))) goto cleanup; if ((code = krb5_mk_req_extended(callback_ctx.context, &callback_ctx.auth_context, AP_OPTS_USE_SUBKEY, NULL, creds, &callback_ctx.ap_req))) goto cleanup; callback_ctx.remote_seq_num = callback_ctx.auth_context->remote_seq_number; callback_ctx.local_seq_num = callback_ctx.auth_context->local_seq_number; do { int socktype = (use_tcp ? SOCK_STREAM : SOCK_DGRAM); code = locate_kpasswd(callback_ctx.context, &creds->server->realm, &sl, socktype); if (code) break; addrlen = sizeof(remote_addr); callback_info.data = &callback_ctx; callback_info.pfn_callback = kpasswd_sendto_msg_callback; callback_info.pfn_cleanup = kpasswd_sendto_msg_cleanup; krb5_free_data_contents(callback_ctx.context, &chpw_rep); code = k5_sendto(callback_ctx.context, NULL, &sl, socktype, 0, &callback_info, &chpw_rep, ss2sa(&remote_addr), &addrlen, NULL, NULL, NULL); if (code) { /* * Here we may want to switch to TCP on some errors. * right? */ break; } if (remote_addr.ss_family == AF_INET) { remote_kaddr.addrtype = ADDRTYPE_INET; remote_kaddr.length = sizeof(ss2sin(&remote_addr)->sin_addr); remote_kaddr.contents = (krb5_octet *) &ss2sin(&remote_addr)->sin_addr; } else if (remote_addr.ss_family == AF_INET6) { remote_kaddr.addrtype = ADDRTYPE_INET6; remote_kaddr.length = sizeof(ss2sin6(&remote_addr)->sin6_addr); remote_kaddr.contents = (krb5_octet *) &ss2sin6(&remote_addr)->sin6_addr; } else { break; } if ((code = krb5_auth_con_setaddrs(callback_ctx.context, callback_ctx.auth_context, NULL, &remote_kaddr))) break; code = krb5int_rd_chpw_rep(callback_ctx.context, callback_ctx.auth_context, &chpw_rep, &local_result_code, result_string); if (code) { if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !use_tcp) { k5_free_serverlist(&sl); use_tcp = 1; continue; } break; } if (result_code) *result_code = local_result_code; if (result_code_string) { code = krb5_chpw_result_code_string(callback_ctx.context, local_result_code, &code_string); if (code) goto cleanup; result_code_string->length = strlen(code_string); result_code_string->data = malloc(result_code_string->length); if (result_code_string->data == NULL) { code = ENOMEM; goto cleanup; } strncpy(result_code_string->data, code_string, result_code_string->length); } if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !use_tcp) { k5_free_serverlist(&sl); use_tcp = 1; } else { break; } } while (TRUE); cleanup: if (callback_ctx.auth_context != NULL) krb5_auth_con_free(callback_ctx.context, callback_ctx.auth_context); k5_free_serverlist(&sl); krb5_free_data_contents(callback_ctx.context, &callback_ctx.ap_req); krb5_free_data_contents(callback_ctx.context, &chpw_rep); return(code); }
static int kpasswd_sendto_msg_callback(SOCKET fd, void *data, krb5_data *message) { krb5_error_code code = 0; struct sockaddr_storage local_addr; krb5_address local_kaddr; struct sendto_callback_context *ctx = data; GETSOCKNAME_ARG3_TYPE addrlen; krb5_data output; memset (message, 0, sizeof(krb5_data)); /* * We need the local addr from the connection socket */ addrlen = sizeof(local_addr); if (getsockname(fd, ss2sa(&local_addr), &addrlen) < 0) { code = SOCKET_ERRNO; goto cleanup; } /* some brain-dead OS's don't return useful information from * the getsockname call. Namely, windows and solaris. */ if (local_addr.ss_family == AF_INET && ss2sin(&local_addr)->sin_addr.s_addr != 0) { local_kaddr.addrtype = ADDRTYPE_INET; local_kaddr.length = sizeof(ss2sin(&local_addr)->sin_addr); local_kaddr.contents = (krb5_octet *) &ss2sin(&local_addr)->sin_addr; } else if (local_addr.ss_family == AF_INET6 && memcmp(ss2sin6(&local_addr)->sin6_addr.s6_addr, in6addr_any.s6_addr, sizeof(in6addr_any.s6_addr)) != 0) { local_kaddr.addrtype = ADDRTYPE_INET6; local_kaddr.length = sizeof(ss2sin6(&local_addr)->sin6_addr); local_kaddr.contents = (krb5_octet *) &ss2sin6(&local_addr)->sin6_addr; } else { krb5_address **addrs; code = krb5_os_localaddr(ctx->context, &addrs); if (code) goto cleanup; local_kaddr.magic = addrs[0]->magic; local_kaddr.addrtype = addrs[0]->addrtype; local_kaddr.length = addrs[0]->length; local_kaddr.contents = k5memdup(addrs[0]->contents, addrs[0]->length, &code); krb5_free_addresses(ctx->context, addrs); if (local_kaddr.contents == NULL) goto cleanup; } /* * TBD: Does this tamper w/ the auth context in such a way * to break us? Yes - provide 1 per conn-state / host... */ if ((code = krb5_auth_con_setaddrs(ctx->context, ctx->auth_context, &local_kaddr, NULL))) goto cleanup; ctx->auth_context->remote_seq_number = ctx->remote_seq_num; ctx->auth_context->local_seq_number = ctx->local_seq_num; if (ctx->set_password_for) code = krb5int_mk_setpw_req(ctx->context, ctx->auth_context, &ctx->ap_req, ctx->set_password_for, ctx->newpw, &output); else code = krb5int_mk_chpw_req(ctx->context, ctx->auth_context, &ctx->ap_req, ctx->newpw, &output); if (code) goto cleanup; message->length = output.length; message->data = output.data; cleanup: return code; }
static krb5_error_code process_chpw_request(krb5_context context, void *server_handle, char *realm, krb5_keytab keytab, const krb5_fulladdr *local_faddr, const krb5_fulladdr *remote_faddr, krb5_data *req, krb5_data *rep) { krb5_error_code ret; char *ptr; unsigned int plen, vno; krb5_data ap_req, ap_rep = empty_data(); krb5_data cipher = empty_data(), clear = empty_data(); krb5_auth_context auth_context = NULL; krb5_principal changepw = NULL; krb5_principal client, target = NULL; krb5_ticket *ticket = NULL; krb5_replay_data replay; krb5_error krberror; int numresult; char strresult[1024]; char *clientstr = NULL, *targetstr = NULL; const char *errmsg = NULL; size_t clen; char *cdots; struct sockaddr_storage ss; socklen_t salen; char addrbuf[100]; krb5_address *addr = remote_faddr->address; *rep = empty_data(); if (req->length < 4) { /* either this, or the server is printing bad messages, or the caller passed in garbage */ ret = KRB5KRB_AP_ERR_MODIFIED; numresult = KRB5_KPASSWD_MALFORMED; strlcpy(strresult, "Request was truncated", sizeof(strresult)); goto bailout; } ptr = req->data; /* verify length */ plen = (*ptr++ & 0xff); plen = (plen<<8) | (*ptr++ & 0xff); if (plen != req->length) { ret = KRB5KRB_AP_ERR_MODIFIED; numresult = KRB5_KPASSWD_MALFORMED; strlcpy(strresult, "Request length was inconsistent", sizeof(strresult)); goto bailout; } /* verify version number */ vno = (*ptr++ & 0xff) ; vno = (vno<<8) | (*ptr++ & 0xff); if (vno != 1 && vno != RFC3244_VERSION) { ret = KRB5KDC_ERR_BAD_PVNO; numresult = KRB5_KPASSWD_BAD_VERSION; snprintf(strresult, sizeof(strresult), "Request contained unknown protocol version number %d", vno); goto bailout; } /* read, check ap-req length */ ap_req.length = (*ptr++ & 0xff); ap_req.length = (ap_req.length<<8) | (*ptr++ & 0xff); if (ptr + ap_req.length >= req->data + req->length) { ret = KRB5KRB_AP_ERR_MODIFIED; numresult = KRB5_KPASSWD_MALFORMED; strlcpy(strresult, "Request was truncated in AP-REQ", sizeof(strresult)); goto bailout; } /* verify ap_req */ ap_req.data = ptr; ptr += ap_req.length; ret = krb5_auth_con_init(context, &auth_context); if (ret) { numresult = KRB5_KPASSWD_HARDERROR; strlcpy(strresult, "Failed initializing auth context", sizeof(strresult)); goto chpwfail; } ret = krb5_auth_con_setflags(context, auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE); if (ret) { numresult = KRB5_KPASSWD_HARDERROR; strlcpy(strresult, "Failed initializing auth context", sizeof(strresult)); goto chpwfail; } ret = krb5_build_principal(context, &changepw, strlen(realm), realm, "kadmin", "changepw", NULL); if (ret) { numresult = KRB5_KPASSWD_HARDERROR; strlcpy(strresult, "Failed building kadmin/changepw principal", sizeof(strresult)); goto chpwfail; } ret = krb5_rd_req(context, &auth_context, &ap_req, changepw, keytab, NULL, &ticket); if (ret) { numresult = KRB5_KPASSWD_AUTHERROR; strlcpy(strresult, "Failed reading application request", sizeof(strresult)); goto chpwfail; } /* construct the ap-rep */ ret = krb5_mk_rep(context, auth_context, &ap_rep); if (ret) { numresult = KRB5_KPASSWD_AUTHERROR; strlcpy(strresult, "Failed replying to application request", sizeof(strresult)); goto chpwfail; } /* decrypt the ChangePasswdData */ cipher.length = (req->data + req->length) - ptr; cipher.data = ptr; /* * Don't set a remote address in auth_context before calling krb5_rd_priv, * so that we can work against clients behind a NAT. Reflection attacks * aren't a concern since we use sequence numbers and since our requests * don't look anything like our responses. Also don't set a local address, * since we don't know what interface the request was received on. */ ret = krb5_rd_priv(context, auth_context, &cipher, &clear, &replay); if (ret) { numresult = KRB5_KPASSWD_HARDERROR; strlcpy(strresult, "Failed decrypting request", sizeof(strresult)); goto chpwfail; } client = ticket->enc_part2->client; /* decode ChangePasswdData for setpw requests */ if (vno == RFC3244_VERSION) { krb5_data *clear_data; ret = decode_krb5_setpw_req(&clear, &clear_data, &target); if (ret != 0) { numresult = KRB5_KPASSWD_MALFORMED; strlcpy(strresult, "Failed decoding ChangePasswdData", sizeof(strresult)); goto chpwfail; } zapfree(clear.data, clear.length); clear = *clear_data; free(clear_data); if (target != NULL) { ret = krb5_unparse_name(context, target, &targetstr); if (ret != 0) { numresult = KRB5_KPASSWD_HARDERROR; strlcpy(strresult, "Failed unparsing target name for log", sizeof(strresult)); goto chpwfail; } } } ret = krb5_unparse_name(context, client, &clientstr); if (ret) { numresult = KRB5_KPASSWD_HARDERROR; strlcpy(strresult, "Failed unparsing client name for log", sizeof(strresult)); goto chpwfail; } /* for cpw, verify that this is an AS_REQ ticket */ if (vno == 1 && (ticket->enc_part2->flags & TKT_FLG_INITIAL) == 0) { numresult = KRB5_KPASSWD_INITIAL_FLAG_NEEDED; strlcpy(strresult, "Ticket must be derived from a password", sizeof(strresult)); goto chpwfail; } /* change the password */ ptr = k5memdup0(clear.data, clear.length, &ret); ret = schpw_util_wrapper(server_handle, client, target, (ticket->enc_part2->flags & TKT_FLG_INITIAL) != 0, ptr, NULL, strresult, sizeof(strresult)); if (ret) errmsg = krb5_get_error_message(context, ret); /* zap the password */ zapfree(clear.data, clear.length); zapfree(ptr, clear.length); clear = empty_data(); clen = strlen(clientstr); trunc_name(&clen, &cdots); switch (addr->addrtype) { case ADDRTYPE_INET: { struct sockaddr_in *sin = ss2sin(&ss); sin->sin_family = AF_INET; memcpy(&sin->sin_addr, addr->contents, addr->length); sin->sin_port = htons(remote_faddr->port); salen = sizeof(*sin); break; } case ADDRTYPE_INET6: { struct sockaddr_in6 *sin6 = ss2sin6(&ss); sin6->sin6_family = AF_INET6; memcpy(&sin6->sin6_addr, addr->contents, addr->length); sin6->sin6_port = htons(remote_faddr->port); salen = sizeof(*sin6); break; } default: { struct sockaddr *sa = ss2sa(&ss); sa->sa_family = AF_UNSPEC; salen = sizeof(*sa); break; } } if (getnameinfo(ss2sa(&ss), salen, addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV) != 0) strlcpy(addrbuf, "<unprintable>", sizeof(addrbuf)); if (vno == RFC3244_VERSION) { size_t tlen; char *tdots; const char *targetp; if (target == NULL) { tlen = clen; tdots = cdots; targetp = targetstr; } else { tlen = strlen(targetstr); trunc_name(&tlen, &tdots); targetp = clientstr; } krb5_klog_syslog(LOG_NOTICE, _("setpw request from %s by %.*s%s for " "%.*s%s: %s"), addrbuf, (int) clen, clientstr, cdots, (int) tlen, targetp, tdots, errmsg ? errmsg : "success"); } else { krb5_klog_syslog(LOG_NOTICE, _("chpw request from %s for %.*s%s: %s"), addrbuf, (int) clen, clientstr, cdots, errmsg ? errmsg : "success"); } switch (ret) { case KADM5_AUTH_CHANGEPW: numresult = KRB5_KPASSWD_ACCESSDENIED; break; case KADM5_PASS_Q_TOOSHORT: case KADM5_PASS_REUSE: case KADM5_PASS_Q_CLASS: case KADM5_PASS_Q_DICT: case KADM5_PASS_Q_GENERIC: case KADM5_PASS_TOOSOON: numresult = KRB5_KPASSWD_SOFTERROR; break; case 0: numresult = KRB5_KPASSWD_SUCCESS; strlcpy(strresult, "", sizeof(strresult)); break; default: numresult = KRB5_KPASSWD_HARDERROR; break; } chpwfail: ret = alloc_data(&clear, 2 + strlen(strresult)); if (ret) goto bailout; ptr = clear.data; *ptr++ = (numresult>>8) & 0xff; *ptr++ = numresult & 0xff; memcpy(ptr, strresult, strlen(strresult)); cipher = empty_data(); if (ap_rep.length) { ret = krb5_auth_con_setaddrs(context, auth_context, local_faddr->address, NULL); if (ret) { numresult = KRB5_KPASSWD_HARDERROR; strlcpy(strresult, "Failed storing client and server internet addresses", sizeof(strresult)); } else { ret = krb5_mk_priv(context, auth_context, &clear, &cipher, &replay); if (ret) { numresult = KRB5_KPASSWD_HARDERROR; strlcpy(strresult, "Failed encrypting reply", sizeof(strresult)); } } } /* if no KRB-PRIV was constructed, then we need a KRB-ERROR. if this fails, just bail. there's nothing else we can do. */ if (cipher.length == 0) { /* clear out ap_rep now, so that it won't be inserted in the reply */ if (ap_rep.length) { free(ap_rep.data); ap_rep = empty_data(); } krberror.ctime = 0; krberror.cusec = 0; krberror.susec = 0; ret = krb5_timeofday(context, &krberror.stime); if (ret) goto bailout; /* this is really icky. but it's what all the other callers to mk_error do. */ krberror.error = ret; krberror.error -= ERROR_TABLE_BASE_krb5; if (krberror.error < 0 || krberror.error > KRB_ERR_MAX) krberror.error = KRB_ERR_GENERIC; krberror.client = NULL; ret = krb5_build_principal(context, &krberror.server, strlen(realm), realm, "kadmin", "changepw", NULL); if (ret) goto bailout; krberror.text.length = 0; krberror.e_data = clear; ret = krb5_mk_error(context, &krberror, &cipher); krb5_free_principal(context, krberror.server); if (ret) goto bailout; } /* construct the reply */ ret = alloc_data(rep, 6 + ap_rep.length + cipher.length); if (ret) goto bailout; ptr = rep->data; /* length */ *ptr++ = (rep->length>>8) & 0xff; *ptr++ = rep->length & 0xff; /* version == 0x0001 big-endian */ *ptr++ = 0; *ptr++ = 1; /* ap_rep length, big-endian */ *ptr++ = (ap_rep.length>>8) & 0xff; *ptr++ = ap_rep.length & 0xff; /* ap-rep data */ if (ap_rep.length) { memcpy(ptr, ap_rep.data, ap_rep.length); ptr += ap_rep.length; } /* krb-priv or krb-error */ memcpy(ptr, cipher.data, cipher.length); bailout: krb5_auth_con_free(context, auth_context); krb5_free_principal(context, changepw); krb5_free_ticket(context, ticket); free(ap_rep.data); free(clear.data); free(cipher.data); krb5_free_principal(context, target); krb5_free_unparsed_name(context, targetstr); krb5_free_unparsed_name(context, clientstr); krb5_free_error_message(context, errmsg); return ret; }
int foreach_localaddr (void *data, int (*pass1fn) (void *, struct sockaddr *), int (*betweenfn) (void *), int (*pass2fn) (void *, struct sockaddr *)) { /* Okay, this is kind of odd. We have to use each of the address families we care about, because with an AF_INET socket, extra interfaces like hme0:1 that have only AF_INET6 addresses will cause errors. Similarly, if hme0 has more AF_INET addresses than AF_INET6 addresses, we won't be able to retrieve all of the AF_INET addresses if we use an AF_INET6 socket. Since neither family is guaranteed to have the greater number of addresses, we should use both. If it weren't for this little quirk, we could use one socket of any type, and ask for addresses of all types. At least, it seems to work that way. */ /* Solaris kerberos: avoid using AF_NS if no define */ #if defined (KRB5_USE_INET6) && defined (KRB5_USE_NS) static const int afs[] = { AF_INET, AF_NS, AF_INET6 }; #elif defined (KRB5_USE_INET6) static const int afs[] = { AF_INET, AF_INET6 }; #else static const int afs[] = { AF_INET }; #endif #define N_AFS (sizeof (afs) / sizeof (afs[0])) struct { int af; int sock; void *buf; size_t buf_size; struct lifnum lifnum; } afp[N_AFS]; int code, i, j; int retval = 0, afidx; krb5_error_code sock_err = 0; struct lifreq *lifr, lifreq, *lifr2; #define FOREACH_AF() for (afidx = 0; afidx < N_AFS; afidx++) #define P (afp[afidx]) KRB5_LOG0(KRB5_INFO, "foreach_localaddr() start"); /* init */ FOREACH_AF () { P.af = afs[afidx]; P.sock = -1; P.buf = 0; } /* first pass: get raw data, discard uninteresting addresses, callback */ FOREACH_AF () { KRB5_LOG (KRB5_INFO, "foreach_localaddr() trying af %d", P.af); P.sock = socket (P.af, USE_TYPE, USE_PROTO); if (P.sock < 0) { sock_err = SOCKET_ERROR; Tperror ("socket"); continue; } P.lifnum.lifn_family = P.af; P.lifnum.lifn_flags = 0; P.lifnum.lifn_count = 0; code = ioctl (P.sock, SIOCGLIFNUM, &P.lifnum); if (code) { Tperror ("ioctl(SIOCGLIFNUM)"); retval = errno; goto punt; } KRB5_LOG (KRB5_INFO, "foreach_localaddr() lifn_count %d", P.lifnum.lifn_count); P.buf_size = P.lifnum.lifn_count * sizeof (struct lifreq) * 2; P.buf = malloc (P.buf_size); if (P.buf == NULL) { retval = errno; goto punt; } code = get_lifconf (P.af, P.sock, &P.buf_size, P.buf); if (code < 0) { retval = errno; goto punt; } for (i = 0; i < P.buf_size; i+= sizeof (*lifr)) { /*LINTED*/ lifr = (struct lifreq *)((caddr_t) P.buf+i); strncpy(lifreq.lifr_name, lifr->lifr_name, sizeof (lifreq.lifr_name)); KRB5_LOG (KRB5_INFO, "foreach_localaddr() interface %s", lifreq.lifr_name); /* ioctl unknown to lclint */ if (ioctl (P.sock, SIOCGLIFFLAGS, (char *)&lifreq) < 0) { Tperror ("ioctl(SIOCGLIFFLAGS)"); skip: KRB5_LOG (KRB5_INFO, "foreach_localaddr() skipping interface %s", lifr->lifr_name); /* mark for next pass */ lifr->lifr_name[0] = '\0'; continue; } #ifdef IFF_LOOPBACK /* None of the current callers want loopback addresses. */ if (lifreq.lifr_flags & IFF_LOOPBACK) { Tprintf ((" loopback\n")); goto skip; } #endif /* Ignore interfaces that are down. */ if ((lifreq.lifr_flags & IFF_UP) == 0) { Tprintf ((" down\n")); goto skip; } /* Make sure we didn't process this address already. */ for (j = 0; j < i; j += sizeof (*lifr2)) { /*LINTED*/ lifr2 = (struct lifreq *)((caddr_t) P.buf+j); if (lifr2->lifr_name[0] == '\0') continue; if (lifr2->lifr_addr.ss_family == lifr->lifr_addr.ss_family /* Compare address info. If this isn't good enough -- i.e., if random padding bytes turn out to differ when the addresses are the same -- then we'll have to do it on a per address family basis. */ && !memcmp (&lifr2->lifr_addr, &lifr->lifr_addr, sizeof (*lifr))) { Tprintf ((" duplicate addr\n")); KRB5_LOG0 (KRB5_INFO, "foreach_localaddr() dup addr"); goto skip; } } if ((*pass1fn) (data, ss2sa (&lifr->lifr_addr))) goto punt; } } /* Did we actually get any working sockets? */ FOREACH_AF () if (P.sock != -1) goto have_working_socket; retval = sock_err; goto punt; have_working_socket: if (betweenfn != NULL && (*betweenfn)(data)) goto punt; if (pass2fn) FOREACH_AF () if (P.sock >= 0) { for (i = 0; i < P.buf_size; i+= sizeof (*lifr)) { /*LINTED*/ lifr = (struct lifreq *)((caddr_t) P.buf+i); if (lifr->lifr_name[0] == '\0') /* Marked in first pass to be ignored. */ continue; KRB5_LOG (KRB5_INFO, "foreach_localaddr() doing pass2fn i = %d", i); if ((*pass2fn) (data, ss2sa (&lifr->lifr_addr))) goto punt; } } punt: FOREACH_AF () { closesocket(P.sock); free (P.buf); } 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 }