jpayne@69: /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ jpayne@69: /* jpayne@69: * Copyright 2013 Red Hat, Inc. All rights reserved. jpayne@69: * jpayne@69: * Redistribution and use in source and binary forms, with or without jpayne@69: * modification, are permitted provided that the following conditions are met: jpayne@69: * jpayne@69: * 1. Redistributions of source code must retain the above copyright jpayne@69: * notice, this list of conditions and the following disclaimer. jpayne@69: * jpayne@69: * 2. Redistributions in binary form must reproduce the above copyright jpayne@69: * notice, this list of conditions and the following disclaimer in jpayne@69: * the documentation and/or other materials provided with the jpayne@69: * distribution. jpayne@69: * jpayne@69: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS jpayne@69: * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED jpayne@69: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A jpayne@69: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER jpayne@69: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, jpayne@69: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, jpayne@69: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR jpayne@69: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF jpayne@69: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING jpayne@69: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS jpayne@69: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. jpayne@69: */ jpayne@69: jpayne@69: /* jpayne@69: * This API is not considered as stable as the main krb5 API. jpayne@69: * jpayne@69: * - We may make arbitrary incompatible changes between feature releases jpayne@69: * (e.g. from 1.12 to 1.13). jpayne@69: * - We will make some effort to avoid making incompatible changes for jpayne@69: * bugfix releases, but will make them if necessary. jpayne@69: */ jpayne@69: jpayne@69: #ifndef KRAD_H_ jpayne@69: #define KRAD_H_ jpayne@69: jpayne@69: #include jpayne@69: #include jpayne@69: #include jpayne@69: #include jpayne@69: jpayne@69: #define KRAD_PACKET_SIZE_MAX 4096 jpayne@69: jpayne@69: #define KRAD_SERVICE_TYPE_LOGIN 1 jpayne@69: #define KRAD_SERVICE_TYPE_FRAMED 2 jpayne@69: #define KRAD_SERVICE_TYPE_CALLBACK_LOGIN 3 jpayne@69: #define KRAD_SERVICE_TYPE_CALLBACK_FRAMED 4 jpayne@69: #define KRAD_SERVICE_TYPE_OUTBOUND 5 jpayne@69: #define KRAD_SERVICE_TYPE_ADMINISTRATIVE 6 jpayne@69: #define KRAD_SERVICE_TYPE_NAS_PROMPT 7 jpayne@69: #define KRAD_SERVICE_TYPE_AUTHENTICATE_ONLY 8 jpayne@69: #define KRAD_SERVICE_TYPE_CALLBACK_NAS_PROMPT 9 jpayne@69: #define KRAD_SERVICE_TYPE_CALL_CHECK 10 jpayne@69: #define KRAD_SERVICE_TYPE_CALLBACK_ADMINISTRATIVE 11 jpayne@69: jpayne@69: typedef struct krad_attrset_st krad_attrset; jpayne@69: typedef struct krad_packet_st krad_packet; jpayne@69: typedef struct krad_client_st krad_client; jpayne@69: typedef unsigned char krad_code; jpayne@69: typedef unsigned char krad_attr; jpayne@69: jpayne@69: /* Called when a response is received or the request times out. */ jpayne@69: typedef void jpayne@69: (*krad_cb)(krb5_error_code retval, const krad_packet *request, jpayne@69: const krad_packet *response, void *data); jpayne@69: jpayne@69: /* jpayne@69: * Called to iterate over a set of requests. Either the callback will be jpayne@69: * called until it returns NULL, or it will be called with cancel = TRUE to jpayne@69: * terminate in the middle of an iteration. jpayne@69: */ jpayne@69: typedef const krad_packet * jpayne@69: (*krad_packet_iter_cb)(void *data, krb5_boolean cancel); jpayne@69: jpayne@69: /* jpayne@69: * Code jpayne@69: */ jpayne@69: jpayne@69: /* Convert a code name to its number. Only works for codes defined jpayne@69: * by RFC 2875 or 2882. Returns 0 if the name was not found. */ jpayne@69: krad_code jpayne@69: krad_code_name2num(const char *name); jpayne@69: jpayne@69: /* Convert a code number to its name. Only works for attributes defined jpayne@69: * by RFC 2865 or 2882. Returns NULL if the name was not found. */ jpayne@69: const char * jpayne@69: krad_code_num2name(krad_code code); jpayne@69: jpayne@69: /* jpayne@69: * Attribute jpayne@69: */ jpayne@69: jpayne@69: /* Convert an attribute name to its number. Only works for attributes defined jpayne@69: * by RFC 2865. Returns 0 if the name was not found. */ jpayne@69: krad_attr jpayne@69: krad_attr_name2num(const char *name); jpayne@69: jpayne@69: /* Convert an attribute number to its name. Only works for attributes defined jpayne@69: * by RFC 2865. Returns NULL if the name was not found. */ jpayne@69: const char * jpayne@69: krad_attr_num2name(krad_attr type); jpayne@69: jpayne@69: /* jpayne@69: * Attribute set jpayne@69: */ jpayne@69: jpayne@69: /* Create a new attribute set. */ jpayne@69: krb5_error_code jpayne@69: krad_attrset_new(krb5_context ctx, krad_attrset **set); jpayne@69: jpayne@69: /* Create a deep copy of an attribute set. */ jpayne@69: krb5_error_code jpayne@69: krad_attrset_copy(const krad_attrset *set, krad_attrset **copy); jpayne@69: jpayne@69: /* Free an attribute set. */ jpayne@69: void jpayne@69: krad_attrset_free(krad_attrset *set); jpayne@69: jpayne@69: /* Add an attribute to a set. */ jpayne@69: krb5_error_code jpayne@69: krad_attrset_add(krad_attrset *set, krad_attr type, const krb5_data *data); jpayne@69: jpayne@69: /* Add a four-octet unsigned number attribute to the given set. */ jpayne@69: krb5_error_code jpayne@69: krad_attrset_add_number(krad_attrset *set, krad_attr type, krb5_ui_4 num); jpayne@69: jpayne@69: /* Delete the specified attribute. */ jpayne@69: void jpayne@69: krad_attrset_del(krad_attrset *set, krad_attr type, size_t indx); jpayne@69: jpayne@69: /* Get the specified attribute. */ jpayne@69: const krb5_data * jpayne@69: krad_attrset_get(const krad_attrset *set, krad_attr type, size_t indx); jpayne@69: jpayne@69: /* jpayne@69: * Packet jpayne@69: */ jpayne@69: jpayne@69: /* Determine the bytes needed from the socket to get the whole packet. Don't jpayne@69: * cache the return value as it can change! Returns -1 on EBADMSG. */ jpayne@69: ssize_t jpayne@69: krad_packet_bytes_needed(const krb5_data *buffer); jpayne@69: jpayne@69: /* Free a packet. */ jpayne@69: void jpayne@69: krad_packet_free(krad_packet *pkt); jpayne@69: jpayne@69: /* jpayne@69: * Create a new request packet. jpayne@69: * jpayne@69: * This function takes the attributes specified in set and converts them into a jpayne@69: * radius packet. The packet will have a randomized id. If cb is not NULL, it jpayne@69: * will be called passing data as the argument to iterate over a set of jpayne@69: * outstanding requests. In this case, the id will be both random and unique jpayne@69: * across the set of requests. jpayne@69: */ jpayne@69: krb5_error_code jpayne@69: krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code, jpayne@69: const krad_attrset *set, krad_packet_iter_cb cb, jpayne@69: void *data, krad_packet **request); jpayne@69: jpayne@69: /* jpayne@69: * Create a new response packet. jpayne@69: * jpayne@69: * This function is similar to krad_packet_new_requst() except that it crafts a jpayne@69: * packet in response to a request packet. This new packet will borrow values jpayne@69: * from the request such as the id and the authenticator. jpayne@69: */ jpayne@69: krb5_error_code jpayne@69: krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code, jpayne@69: const krad_attrset *set, const krad_packet *request, jpayne@69: krad_packet **response); jpayne@69: jpayne@69: /* jpayne@69: * Decode a request radius packet from krb5_data. jpayne@69: * jpayne@69: * The resulting decoded packet will be a request packet stored in *reqpkt. jpayne@69: * jpayne@69: * If cb is NULL, *duppkt will always be NULL. jpayne@69: * jpayne@69: * If cb is not NULL, it will be called (with the data argument) to iterate jpayne@69: * over a set of requests currently being processed. In this case, if the jpayne@69: * packet is a duplicate of an already received request, the original request jpayne@69: * will be set in *duppkt. jpayne@69: */ jpayne@69: krb5_error_code jpayne@69: krad_packet_decode_request(krb5_context ctx, const char *secret, jpayne@69: const krb5_data *buffer, krad_packet_iter_cb cb, jpayne@69: void *data, const krad_packet **duppkt, jpayne@69: krad_packet **reqpkt); jpayne@69: jpayne@69: /* jpayne@69: * Decode a response radius packet from krb5_data. jpayne@69: * jpayne@69: * The resulting decoded packet will be a response packet stored in *rsppkt. jpayne@69: * jpayne@69: * If cb is NULL, *reqpkt will always be NULL. jpayne@69: * jpayne@69: * If cb is not NULL, it will be called (with the data argument) to iterate jpayne@69: * over a set of requests awaiting responses. In this case, if the response jpayne@69: * packet matches one of these requests, the original request will be set in jpayne@69: * *reqpkt. jpayne@69: */ jpayne@69: krb5_error_code jpayne@69: krad_packet_decode_response(krb5_context ctx, const char *secret, jpayne@69: const krb5_data *buffer, krad_packet_iter_cb cb, jpayne@69: void *data, const krad_packet **reqpkt, jpayne@69: krad_packet **rsppkt); jpayne@69: jpayne@69: /* Encode packet. */ jpayne@69: const krb5_data * jpayne@69: krad_packet_encode(const krad_packet *pkt); jpayne@69: jpayne@69: /* Get the code for the given packet. */ jpayne@69: krad_code jpayne@69: krad_packet_get_code(const krad_packet *pkt); jpayne@69: jpayne@69: /* Get the specified attribute. */ jpayne@69: const krb5_data * jpayne@69: krad_packet_get_attr(const krad_packet *pkt, krad_attr type, size_t indx); jpayne@69: jpayne@69: /* jpayne@69: * Client jpayne@69: */ jpayne@69: jpayne@69: /* Create a new client. */ jpayne@69: krb5_error_code jpayne@69: krad_client_new(krb5_context kctx, verto_ctx *vctx, krad_client **client); jpayne@69: jpayne@69: /* Free the client. */ jpayne@69: void jpayne@69: krad_client_free(krad_client *client); jpayne@69: jpayne@69: /* jpayne@69: * Send a request to a radius server. jpayne@69: * jpayne@69: * The remote host may be specified by one of the following formats: jpayne@69: * - /path/to/unix.socket jpayne@69: * - IPv4 jpayne@69: * - IPv4:port jpayne@69: * - IPv4:service jpayne@69: * - [IPv6] jpayne@69: * - [IPv6]:port jpayne@69: * - [IPv6]:service jpayne@69: * - hostname jpayne@69: * - hostname:port jpayne@69: * - hostname:service jpayne@69: * jpayne@69: * The timeout parameter (milliseconds) is the total timeout across all remote jpayne@69: * hosts (when DNS returns multiple entries) and all retries. For stream jpayne@69: * sockets, the retries parameter is ignored and no retries are performed. jpayne@69: * jpayne@69: * The cb function will be called with the data argument when either a response jpayne@69: * is received or the request times out on all possible remote hosts. jpayne@69: */ jpayne@69: krb5_error_code jpayne@69: krad_client_send(krad_client *rc, krad_code code, const krad_attrset *attrs, jpayne@69: const char *remote, const char *secret, int timeout, jpayne@69: size_t retries, krad_cb cb, void *data); jpayne@69: jpayne@69: #endif /* KRAD_H_ */