/* * Write a field of bytes from krb5_data as a hexadecimal string. Write empty * strings as "-1" unless requested. */ static int write_data(struct rec_args *args, krb5_data *data) { int ret; char *p; size_t i; struct k5buf buf; struct rechandle *h = args->rh; struct tdopts *opts = args->opts; if (data->length == 0 && !opts->emptyhex_empty) { if (writefield(h, "-1") < 0) return -1; return 0; } k5_buf_init_dynamic(&buf); p = data->data; for (i = 0; i < data->length; i++) k5_buf_add_fmt(&buf, "%02x", (unsigned char)p[i]); if (buf.data == NULL) { errno = ENOMEM; return -1; } ret = writefield(h, "%s", (char *)buf.data); k5_buf_free(&buf); return ret; }
krb5_error_code krb5_ldap_parse_principal_name(char *i_princ_name, char **o_princ_name) { const char *at_rlm_name, *p; struct k5buf buf; at_rlm_name = strrchr(i_princ_name, '@'); if (!at_rlm_name) { *o_princ_name = strdup(i_princ_name); if (!*o_princ_name) return ENOMEM; } else { k5_buf_init_dynamic(&buf); for (p = i_princ_name; p < at_rlm_name; p++) { if (*p == '@') k5_buf_add(&buf, "\\"); k5_buf_add_len(&buf, p, 1); } k5_buf_add(&buf, at_rlm_name); *o_princ_name = k5_buf_data(&buf); if (!*o_princ_name) return ENOMEM; } return 0; }
void k5_buf_init_dynamic_zap(struct k5buf *buf) { k5_buf_init_dynamic(buf); if (buf->buftype == K5BUF_DYNAMIC) buf->buftype = K5BUF_DYNAMIC_ZAP; }
static krb5_error_code read_principal(krb5_context context, krb5_ccache id, krb5_principal *princ) { krb5_error_code ret; struct k5buf buf; size_t maxsize; unsigned char *bytes; *princ = NULL; k5_cc_mutex_assert_locked(context, &((fcc_data *)id->data)->lock); k5_buf_init_dynamic(&buf); /* Read the principal representation into memory. */ ret = get_size(context, id, &maxsize); if (ret) goto cleanup; ret = load_principal(context, id, maxsize, &buf); if (ret) goto cleanup; bytes = (unsigned char *)k5_buf_data(&buf); if (bytes == NULL) { ret = ENOMEM; goto cleanup; } /* Unmarshal it from buf into princ. */ ret = k5_unmarshal_princ(bytes, k5_buf_len(&buf), version(id), princ); cleanup: k5_free_buf(&buf); return ret; }
static krb5_error_code make_proxy_request(struct conn_state *state, const krb5_data *realm, const krb5_data *message, char **req_out, size_t *len_out) { krb5_kkdcp_message pm; krb5_data *encoded_pm = NULL; struct k5buf buf; const char *uri_path; krb5_error_code ret; *req_out = NULL; *len_out = 0; /* * Stuff the message length in at the front of the kerb_message field * before encoding. The proxied messages are actually the payload we'd * be sending and receiving if we were using plain TCP. */ memset(&pm, 0, sizeof(pm)); ret = alloc_data(&pm.kerb_message, message->length + 4); if (ret != 0) goto cleanup; store_32_be(message->length, pm.kerb_message.data); memcpy(pm.kerb_message.data + 4, message->data, message->length); pm.target_domain = *realm; ret = encode_krb5_kkdcp_message(&pm, &encoded_pm); if (ret != 0) goto cleanup; /* Build the request to transmit: the headers + the proxy message. */ k5_buf_init_dynamic(&buf); uri_path = (state->http.uri_path != NULL) ? state->http.uri_path : ""; k5_buf_add_fmt(&buf, "POST /%s HTTP/1.0\r\n", uri_path); k5_buf_add(&buf, "Cache-Control: no-cache\r\n"); k5_buf_add(&buf, "Pragma: no-cache\r\n"); k5_buf_add(&buf, "User-Agent: kerberos/1.0\r\n"); k5_buf_add(&buf, "Content-type: application/kerberos\r\n"); k5_buf_add_fmt(&buf, "Content-Length: %d\r\n\r\n", encoded_pm->length); k5_buf_add_len(&buf, encoded_pm->data, encoded_pm->length); if (k5_buf_status(&buf) != 0) { ret = ENOMEM; goto cleanup; } *req_out = buf.data; *len_out = buf.len; cleanup: krb5_free_data_contents(NULL, &pm.kerb_message); krb5_free_data(NULL, encoded_pm); return ret; }
/* * Get a line from the ACL file. Lines ending with \ are continued on the next * line. The caller should set *lineno to 1 and *incr to 0 before the first * call. On successful return, *lineno will be the line number of the line * read. Return a pointer to the line on success, or NULL on end of file or * read failure. */ static char * get_line(FILE *fp, const char *fname, int *lineno, int *incr) { const int chunksize = 128; struct k5buf buf; size_t old_len; char *p; /* Increment *lineno by the number of newlines from the last line. */ *lineno += *incr; *incr = 0; k5_buf_init_dynamic(&buf); for (;;) { /* Read at least part of a line into the buffer. */ old_len = buf.len; p = k5_buf_get_space(&buf, chunksize); if (p == NULL) return NULL; if (fgets(p, chunksize, fp) == NULL) { /* We reached the end. Return a final unterminated line, if there * is one and it's not a comment. */ k5_buf_truncate(&buf, old_len); if (buf.len > 0 && *(char *)buf.data != '#') return buf.data; k5_buf_free(&buf); return NULL; } /* Set the buffer length based on the actual amount read. */ k5_buf_truncate(&buf, old_len + strlen(p)); p = buf.data; if (buf.len > 0 && p[buf.len - 1] == '\n') { /* We have a complete raw line in the buffer. */ (*incr)++; k5_buf_truncate(&buf, buf.len - 1); if (buf.len > 0 && p[buf.len - 1] == '\\') { /* This line has a continuation marker; keep reading. */ k5_buf_truncate(&buf, buf.len - 1); } else if (buf.len == 0 || *p == '#') { /* This line is empty or a comment. Start over. */ *lineno += *incr; *incr = 0; k5_buf_truncate(&buf, 0); } else { return buf.data; } } } }
/* * Double any quote characters present in a quoted field. */ static char * qquote(struct flavor *fl, const char *s) { const char *sp; struct k5buf buf; k5_buf_init_dynamic(&buf); for (sp = s; *sp != '\0'; sp++) { k5_buf_add_len(&buf, sp, 1); if (*sp == fl->quotechar) k5_buf_add_len(&buf, sp, 1); } return buf.data; }
/* Return a copy of in, quoting all characters which are special in an LDAP * filter (RFC 4515) or DN string (RFC 4514). Return NULL on failure. */ char * ldap_filter_correct (char *in) { size_t count; const char special[] = "*()\\ #\"+,;<>"; struct k5buf buf; k5_buf_init_dynamic(&buf); while (TRUE) { count = strcspn(in, special); k5_buf_add_len(&buf, in, count); in += count; if (*in == '\0') break; k5_buf_add_fmt(&buf, "\\%2x", (unsigned char)*in++); } return buf.data; }
/* Get the next credential from the cache file. */ static krb5_error_code KRB5_CALLCONV fcc_next_cred(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor, krb5_creds *creds) { krb5_error_code ret; krb5_fcc_cursor *fcursor = *cursor; fcc_data *data = id->data; struct k5buf buf; size_t maxsize; unsigned char *bytes; memset(creds, 0, sizeof(*creds)); k5_cc_mutex_lock(context, &data->lock); MAYBE_OPEN(context, id, FCC_OPEN_RDONLY); k5_buf_init_dynamic(&buf); if (fcc_lseek(data, fcursor->pos, SEEK_SET) == -1) { ret = interpret_errno(context, errno); goto cleanup; } /* Load a marshalled cred into memory. */ ret = get_size(context, id, &maxsize); if (ret) return ret; ret = load_cred(context, id, maxsize, &buf); if (ret) goto cleanup; bytes = (unsigned char *)k5_buf_data(&buf); if (bytes == NULL) { ret = ENOMEM; goto cleanup; } /* Unmarshal it from buf into creds. */ fcursor->pos = fcc_lseek(data, 0, SEEK_CUR); ret = k5_unmarshal_cred(bytes, k5_buf_len(&buf), version(id), creds); cleanup: k5_free_buf(&buf); MAYBE_CLOSE(context, id, ret); k5_cc_mutex_unlock(context, &data->lock); return ret; }
static char * trace_format(krb5_context context, const char *fmt, va_list ap) { struct k5buf buf; krb5_error_code kerr; size_t len, i; int err; struct conn_state *cs; const krb5_data *d; krb5_data data; char addrbuf[NI_MAXHOST], portbuf[NI_MAXSERV], tmpbuf[200], *str; const char *p; krb5_const_principal princ; const krb5_keyblock *keyblock; krb5_key key; const krb5_checksum *cksum; krb5_pa_data **padata; krb5_ccache ccache; krb5_keytab keytab; krb5_creds *creds; krb5_enctype *etypes, etype; k5_buf_init_dynamic(&buf); while (TRUE) { /* Advance to the next word in braces. */ len = strcspn(fmt, "{"); k5_buf_add_len(&buf, fmt, len); if (fmt[len] == '\0') break; fmt += len + 1; len = strcspn(fmt, "}"); if (fmt[len] == '\0' || len > sizeof(tmpbuf) - 1) break; memcpy(tmpbuf, fmt, len); tmpbuf[len] = '\0'; fmt += len + 1; /* Process the format word. */ if (strcmp(tmpbuf, "int") == 0) { k5_buf_add_fmt(&buf, "%d", va_arg(ap, int)); } else if (strcmp(tmpbuf, "long") == 0) {
/* * Expand tokens in path_in to produce *path_out. Arguments after path_out are * pairs of extra token names and replacement values, terminated by a NULL. * The caller should free *path_out with free(). */ krb5_error_code k5_expand_path_tokens_extra(krb5_context context, const char *path_in, char **path_out, ...) { krb5_error_code ret; struct k5buf buf; char *tok_begin, *tok_end, *tok_val, **extra_tokens = NULL; const char *path_left; size_t nargs = 0, i; va_list ap; *path_out = NULL; k5_buf_init_dynamic(&buf); /* Count extra tokens. */ va_start(ap, path_out); while (va_arg(ap, const char *) != NULL) nargs++; va_end(ap); if (nargs % 2 != 0) return EINVAL; /* Get extra tokens. */ if (nargs > 0) { extra_tokens = k5calloc(nargs + 1, sizeof(char *), &ret); if (extra_tokens == NULL) goto cleanup; va_start(ap, path_out); for (i = 0; i < nargs; i++) { extra_tokens[i] = strdup(va_arg(ap, const char *)); if (extra_tokens[i] == NULL) { ret = ENOMEM; va_end(ap); goto cleanup; } } va_end(ap); }
/* Get any auth indicator values from LDAP and update the "require_auth" * string. */ static krb5_error_code get_ldap_auth_ind(krb5_context context, LDAP *ld, LDAPMessage *ldap_ent, krb5_db_entry *entry, unsigned int *mask) { krb5_error_code ret; int i; char **auth_inds = NULL; struct k5buf buf = EMPTY_K5BUF; auth_inds = ldap_get_values(ld, ldap_ent, "krbPrincipalAuthInd"); if (auth_inds == NULL) return 0; k5_buf_init_dynamic(&buf); /* Make a space seperated list of indicators. */ for (i = 0; auth_inds[i] != NULL; i++) { k5_buf_add(&buf, auth_inds[i]); if (auth_inds[i + 1] != NULL) k5_buf_add(&buf, " "); } ret = k5_buf_status(&buf); if (ret) goto cleanup; ret = krb5_dbe_set_string(context, entry, KRB5_KDB_SK_REQUIRE_AUTH, buf.data); if (!ret) *mask |= KDB_AUTH_IND_ATTR; cleanup: k5_buf_free(&buf); ldap_value_free(auth_inds); return ret; }
static krb5_error_code krb5_rc_io_store(krb5_context context, struct dfl_data *t, krb5_donot_replay *rep) { size_t clientlen, serverlen; unsigned int len; krb5_error_code ret; struct k5buf buf, extbuf; char *extstr; clientlen = strlen(rep->client); serverlen = strlen(rep->server); if (rep->msghash) { /* * Write a hash extension record, to be followed by a record * in regular format (without the message hash) for the * benefit of old implementations. */ /* Format the extension value so we know its length. */ k5_buf_init_dynamic(&extbuf); k5_buf_add_fmt(&extbuf, "HASH:%s %lu:%s %lu:%s", rep->msghash, (unsigned long)clientlen, rep->client, (unsigned long)serverlen, rep->server); if (k5_buf_status(&extbuf) != 0) return KRB5_RC_MALLOC; extstr = extbuf.data; /* * Put the extension value into the server field of a * regular-format record, with an empty client field. */ k5_buf_init_dynamic(&buf); len = 1; k5_buf_add_len(&buf, (char *)&len, sizeof(len)); k5_buf_add_len(&buf, "", 1); len = strlen(extstr) + 1; k5_buf_add_len(&buf, (char *)&len, sizeof(len)); k5_buf_add_len(&buf, extstr, len); k5_buf_add_len(&buf, (char *)&rep->cusec, sizeof(rep->cusec)); k5_buf_add_len(&buf, (char *)&rep->ctime, sizeof(rep->ctime)); free(extstr); } else /* No extension record needed. */ k5_buf_init_dynamic(&buf); len = clientlen + 1; k5_buf_add_len(&buf, (char *)&len, sizeof(len)); k5_buf_add_len(&buf, rep->client, len); len = serverlen + 1; k5_buf_add_len(&buf, (char *)&len, sizeof(len)); k5_buf_add_len(&buf, rep->server, len); k5_buf_add_len(&buf, (char *)&rep->cusec, sizeof(rep->cusec)); k5_buf_add_len(&buf, (char *)&rep->ctime, sizeof(rep->ctime)); if (k5_buf_status(&buf) != 0) return KRB5_RC_MALLOC; ret = krb5_rc_io_write(context, &t->d, buf.data, buf.len); k5_buf_free(&buf); return ret; }
static krb5_error_code decode_ad_policy_info(const krb5_data *data, char **msg_out) { struct ad_policy_info policy; uint64_t password_days; const char *p; struct k5buf buf; *msg_out = NULL; if (data->length != AD_POLICY_INFO_LENGTH) return 0; p = data->data; policy.zero_bytes = load_16_be(p); p += 2; /* first two bytes are zeros */ if (policy.zero_bytes != 0) return 0; /* Read in the rest of structure */ policy.min_length_password = load_32_be(p); p += 4; policy.password_history = load_32_be(p); p += 4; policy.password_properties = load_32_be(p); p += 4; policy.expire = load_64_be(p); p += 8; policy.min_passwordage = load_64_be(p); p += 8; /* Check that we processed exactly the expected number of bytes. */ assert(p == data->data + AD_POLICY_INFO_LENGTH); k5_buf_init_dynamic(&buf); /* * Update src/tests/misc/test_chpw_message.c if changing these strings! */ if (policy.password_properties & AD_POLICY_COMPLEX) { k5_buf_add(&buf, _("The password must include numbers or symbols. " "Don't include any part of your name in the " "password.")); } if (policy.min_length_password > 0) { add_spaces(&buf); k5_buf_add_fmt(&buf, ngettext("The password must contain at least %d " "character.", "The password must contain at least %d " "characters.", policy.min_length_password), policy.min_length_password); } if (policy.password_history) { add_spaces(&buf); k5_buf_add_fmt(&buf, ngettext("The password must be different from " "the previous password.", "The password must be different from " "the previous %d passwords.", policy.password_history), policy.password_history); } if (policy.min_passwordage) { password_days = policy.min_passwordage / AD_POLICY_TIME_TO_DAYS; if (password_days == 0) password_days = 1; add_spaces(&buf); k5_buf_add_fmt(&buf, ngettext("The password can only be changed once " "a day.", "The password can only be changed every " "%d days.", (int)password_days), (int)password_days); } if (k5_buf_status(&buf) != 0) return ENOMEM; if (buf.len > 0) *msg_out = buf.data; else k5_buf_free(&buf); return 0; }