krb5_error_code KRB5_CALLCONV krb5_mkt_get_name(krb5_context context, krb5_keytab id, char *name, unsigned int len) { int result; memset(name, 0, len); result = snprintf(name, len, "%s:%s", id->ops->prefix, KTNAME(id)); if (SNPRINTF_OVERFLOW(result, len)) return(KRB5_KT_NAME_TOOLONG); return(0); }
asn1_error_code asn1_encode_generaltime(asn1buf *buf, time_t val, unsigned int *retlen) { struct tm *gtime, gtimebuf; char s[16], *sp; time_t gmt_time = val; /* * Time encoding: YYYYMMDDhhmmssZ */ if (gmt_time == 0) { sp = "19700101000000Z"; } else { int len; /* * Sanity check this just to be paranoid, as gmtime can return NULL, * and some bogus implementations might overrun on the sprintf. */ #ifdef HAVE_GMTIME_R # ifdef GMTIME_R_RETURNS_INT if (gmtime_r(&gmt_time, >imebuf) != 0) return ASN1_BAD_GMTIME; # else if (gmtime_r(&gmt_time, >imebuf) == NULL) return ASN1_BAD_GMTIME; # endif #else gtime = gmtime(&gmt_time); if (gtime == NULL) return ASN1_BAD_GMTIME; memcpy(>imebuf, gtime, sizeof(gtimebuf)); #endif gtime = >imebuf; if (gtime->tm_year > 8099 || gtime->tm_mon > 11 || gtime->tm_mday > 31 || gtime->tm_hour > 23 || gtime->tm_min > 59 || gtime->tm_sec > 59) return ASN1_BAD_GMTIME; len = snprintf(s, sizeof(s), "%04d%02d%02d%02d%02d%02dZ", 1900+gtime->tm_year, gtime->tm_mon+1, gtime->tm_mday, gtime->tm_hour, gtime->tm_min, gtime->tm_sec); if (SNPRINTF_OVERFLOW(len, sizeof(s))) /* Shouldn't be possible given above tests. */ return ASN1_BAD_GMTIME; sp = s; } return encode_bytestring_with_tag(buf, 15, sp, ASN1_GENERALTIME, retlen); }
/* * Resolve the entry in servers with index ind, adding connections to the list * *conns. Connections are added for each of socktype1 and (if not zero) * socktype2. message and udpbufp are used to initialize the connections; see * add_connection above. If no addresses are available for an entry but no * internal name resolution failure occurs, return 0 without adding any new * connections. */ static krb5_error_code resolve_server(krb5_context context, const struct serverlist *servers, size_t ind, int socktype1, int socktype2, const krb5_data *message, char **udpbufp, struct conn_state **conns) { krb5_error_code retval; struct server_entry *entry = &servers->servers[ind]; struct addrinfo *addrs, *a, hint, ai; int err, result; char portbuf[64]; /* Skip any stray entries of socktypes we don't want. */ if (entry->socktype != 0 && entry->socktype != socktype1 && entry->socktype != socktype2) return 0; if (entry->hostname == NULL) { ai.ai_socktype = entry->socktype; ai.ai_family = entry->family; ai.ai_addrlen = entry->addrlen; ai.ai_addr = (struct sockaddr *)&entry->addr; return add_connection(conns, &ai, ind, message, udpbufp); } memset(&hint, 0, sizeof(hint)); hint.ai_family = entry->family; hint.ai_socktype = (entry->socktype != 0) ? entry->socktype : socktype1; #ifdef AI_NUMERICSERV hint.ai_flags = AI_NUMERICSERV; #endif result = snprintf(portbuf, sizeof(portbuf), "%d", ntohs(entry->port)); if (SNPRINTF_OVERFLOW(result, sizeof(portbuf))) return EINVAL; TRACE_SENDTO_KDC_RESOLVING(context, entry->hostname); err = getaddrinfo(entry->hostname, portbuf, &hint, &addrs); if (err) return translate_ai_error(err); /* Add each address with the preferred socktype. */ retval = 0; for (a = addrs; a != 0 && retval == 0; a = a->ai_next) retval = add_connection(conns, a, ind, message, udpbufp); if (retval == 0 && entry->socktype == 0 && socktype2 != 0) { /* Add each address again with the non-preferred socktype. */ for (a = addrs; a != 0 && retval == 0; a = a->ai_next) { a->ai_socktype = socktype2; retval = add_connection(conns, a, ind, message, udpbufp); } } freeaddrinfo(addrs); return retval; }
krb5_error_code KRB5_CALLCONV krb5_ktsrvtab_get_name(krb5_context context, krb5_keytab id, char *name, unsigned int len) /* * This routine returns the name of the name of the file associated with * this srvtab-based keytab. The name is prefixed with PREFIX:, so that * trt will happen if the name is passed back to resolve. */ { int result; memset(name, 0, len); result = snprintf(name, len, "%s:%s", id->ops->prefix, KTFILENAME(id)); if (SNPRINTF_OVERFLOW(result, len)) return(KRB5_KT_NAME_TOOLONG); return(0); }
/* * Resolve the entry in servers with index ind, adding connections to the list * *conns. Connections are added for each of socktype1 and (if not zero) * socktype2. message and udpbufp are used to initialize the connections; see * add_connection above. If no addresses are available for an entry but no * internal name resolution failure occurs, return 0 without adding any new * connections. */ static krb5_error_code resolve_server(krb5_context context, const krb5_data *realm, const struct serverlist *servers, size_t ind, k5_transport_strategy strategy, const krb5_data *message, char **udpbufp, struct conn_state **conns) { krb5_error_code retval; struct server_entry *entry = &servers->servers[ind]; k5_transport transport; struct addrinfo *addrs, *a, hint, ai; krb5_boolean defer; int err, result; char portbuf[64]; /* Skip UDP entries if we don't want UDP. */ if (strategy == NO_UDP && entry->transport == UDP) return 0; transport = (strategy == UDP_FIRST) ? UDP : TCP; if (entry->hostname == NULL) { /* Added by a module, so transport is either TCP or UDP. */ ai.ai_socktype = socktype_for_transport(entry->transport); ai.ai_family = entry->family; ai.ai_addrlen = entry->addrlen; ai.ai_addr = (struct sockaddr *)&entry->addr; defer = (entry->transport != transport); return add_connection(conns, entry->transport, defer, &ai, ind, realm, NULL, entry->uri_path, udpbufp); } /* If the entry has a specified transport, use it. */ if (entry->transport != TCP_OR_UDP) transport = entry->transport; memset(&hint, 0, sizeof(hint)); hint.ai_family = entry->family; hint.ai_socktype = socktype_for_transport(transport); hint.ai_flags = AI_ADDRCONFIG; #ifdef AI_NUMERICSERV hint.ai_flags |= AI_NUMERICSERV; #endif result = snprintf(portbuf, sizeof(portbuf), "%d", ntohs(entry->port)); if (SNPRINTF_OVERFLOW(result, sizeof(portbuf))) return EINVAL; TRACE_SENDTO_KDC_RESOLVING(context, entry->hostname); err = getaddrinfo(entry->hostname, portbuf, &hint, &addrs); if (err) return translate_ai_error(err); /* Add each address with the specified or preferred transport. */ retval = 0; for (a = addrs; a != 0 && retval == 0; a = a->ai_next) { retval = add_connection(conns, transport, FALSE, a, ind, realm, entry->hostname, entry->uri_path, udpbufp); } /* For TCP_OR_UDP entries, add each address again with the non-preferred * transport, unless we are avoiding UDP. Flag these as deferred. */ if (retval == 0 && entry->transport == TCP_OR_UDP && strategy != NO_UDP) { transport = (strategy == UDP_FIRST) ? TCP : UDP; for (a = addrs; a != 0 && retval == 0; a = a->ai_next) { a->ai_socktype = socktype_for_transport(transport); retval = add_connection(conns, transport, TRUE, a, ind, realm, entry->hostname, entry->uri_path, udpbufp); } } freeaddrinfo(addrs); return retval; }
void k5_buf_add_fmt(struct k5buf *buf, const char *fmt, ...) { va_list ap; int r; size_t remaining; char *tmp; if (buf->buftype == BUFTYPE_ERROR) return; remaining = buf->space - buf->len; if (buf->buftype == BUFTYPE_FIXED) { /* Format the data directly into the fixed buffer. */ va_start(ap, fmt); r = vsnprintf(buf->data + buf->len, remaining, fmt, ap); va_end(ap); if (SNPRINTF_OVERFLOW(r, remaining)) buf->buftype = BUFTYPE_ERROR; else buf->len += (unsigned int) r; return; } /* Optimistically format the data directly into the dynamic buffer. */ assert(buf->buftype == BUFTYPE_DYNAMIC); va_start(ap, fmt); r = vsnprintf(buf->data + buf->len, remaining, fmt, ap); va_end(ap); if (!SNPRINTF_OVERFLOW(r, remaining)) { buf->len += (unsigned int) r; return; } if (r >= 0) { /* snprintf correctly told us how much space is required. */ if (!ensure_space(buf, r)) return; remaining = buf->space - buf->len; va_start(ap, fmt); r = vsnprintf(buf->data + buf->len, remaining, fmt, ap); va_end(ap); if (SNPRINTF_OVERFLOW(r, remaining)) /* Shouldn't ever happen. */ buf->buftype = BUFTYPE_ERROR; else buf->len += (unsigned int) r; return; } /* It's a pre-C99 snprintf implementation, or something else went wrong. * Fall back to asprintf. */ va_start(ap, fmt); r = vasprintf(&tmp, fmt, ap); va_end(ap); if (r < 0) { buf->buftype = BUFTYPE_ERROR; return; } if (ensure_space(buf, r)) { /* Copy the temporary string into buf, including terminator. */ memcpy(buf->data + buf->len, tmp, r + 1); buf->len += r; } free(tmp); }
void k5_buf_add_vfmt(struct k5buf *buf, const char *fmt, va_list ap) { va_list apcopy; int r; size_t remaining; char *tmp; if (buf->buftype == K5BUF_ERROR) return; remaining = buf->space - buf->len; if (buf->buftype == K5BUF_FIXED) { /* Format the data directly into the fixed buffer. */ r = vsnprintf(endptr(buf), remaining, fmt, ap); if (SNPRINTF_OVERFLOW(r, remaining)) set_error(buf); else buf->len += (unsigned int) r; return; } /* Optimistically format the data directly into the dynamic buffer. */ assert(buf->buftype == K5BUF_DYNAMIC || buf->buftype == K5BUF_DYNAMIC_ZAP); va_copy(apcopy, ap); r = vsnprintf(endptr(buf), remaining, fmt, apcopy); va_end(apcopy); if (!SNPRINTF_OVERFLOW(r, remaining)) { buf->len += (unsigned int) r; return; } if (r >= 0) { /* snprintf correctly told us how much space is required. */ if (!ensure_space(buf, r)) return; remaining = buf->space - buf->len; r = vsnprintf(endptr(buf), remaining, fmt, ap); if (SNPRINTF_OVERFLOW(r, remaining)) /* Shouldn't ever happen. */ k5_buf_free(buf); else buf->len += (unsigned int) r; return; } /* It's a pre-C99 snprintf implementation, or something else went wrong. * Fall back to asprintf. */ r = vasprintf(&tmp, fmt, ap); if (r < 0) { k5_buf_free(buf); return; } if (ensure_space(buf, r)) { /* Copy the temporary string into buf, including terminator. */ memcpy(endptr(buf), tmp, r + 1); buf->len += r; } if (buf->buftype == K5BUF_DYNAMIC_ZAP) zap(tmp, strlen(tmp)); free(tmp); }