Esempio n. 1
0
/* Dispatch routine for set/change password */
void
dispatch(void *handle, struct sockaddr *local_saddr,
         const krb5_fulladdr *remote_faddr, krb5_data *request, int is_tcp,
         verto_ctx *vctx, loop_respond_fn respond, void *arg)
{
    krb5_error_code ret;
    krb5_keytab kt = NULL;
    kadm5_server_handle_t server_handle = (kadm5_server_handle_t)handle;
    krb5_fulladdr local_faddr;
    krb5_address **local_kaddrs = NULL, local_kaddr_buf;
    krb5_data *response = NULL;

    if (local_saddr == NULL) {
        ret = krb5_os_localaddr(server_handle->context, &local_kaddrs);
        if (ret != 0)
            goto egress;

        local_faddr.address = local_kaddrs[0];
        local_faddr.port = 0;
    } else {
        local_faddr.address = &local_kaddr_buf;
        init_addr(&local_faddr, local_saddr);
    }

    ret = krb5_kt_resolve(server_handle->context, "KDB:", &kt);
    if (ret != 0) {
        krb5_klog_syslog(LOG_ERR, _("chpw: Couldn't open admin keytab %s"),
                         krb5_get_error_message(server_handle->context, ret));
        goto egress;
    }

    response = k5alloc(sizeof(krb5_data), &ret);
    if (response == NULL)
        goto egress;

    ret = process_chpw_request(server_handle->context,
                               handle,
                               server_handle->params.realm,
                               kt,
                               &local_faddr,
                               remote_faddr,
                               request,
                               response);
egress:
    if (ret)
        krb5_free_data(server_handle->context, response);
    krb5_free_addresses(server_handle->context, local_kaddrs);
    krb5_kt_close(server_handle->context, kt);
    (*respond)(arg, ret, ret == 0 ? response : NULL);
}
Esempio n. 2
0
/*
 * This routine is used to handle password-change requests received
 * on kpasswd-port 464 from MIT/M$ clients.
 */
void
handle_chpw(krb5_context context, int s1,
		void *serverhandle, kadm5_config_params *params)
{
	krb5_error_code ret;
	char req[MAXAPREQ];
	int len;
	struct sockaddr_in from;
	int fromlen;
	krb5_keytab kt;
	krb5_data reqdata, repdata;
	int s2 = -1;

	reqdata.length = 0;
	reqdata.data = NULL;
	repdata.length = 0;
	repdata.data = NULL;

	fromlen = sizeof (from);

	if ((len = recvfrom(s1, req, sizeof (req), 0, (struct sockaddr *)&from,
			    &fromlen)) < 0) {
		krb5_klog_syslog(LOG_ERR, gettext("chpw: Couldn't receive "
				"request: %s"), error_message(errno));
		return;
	}

	if ((ret = krb5_kt_resolve(context, params->admin_keytab, &kt))) {
		krb5_klog_syslog(LOG_ERR, gettext("chpw: Couldn't open "
				"admin keytab %s"), error_message(ret));
		return;
	}

	reqdata.length = len;
	reqdata.data = req;

	/*
	 * This is really obscure.  s1 is used for all communications.  it
	 * is left unconnected in case the server is multihomed and routes
	 * are asymmetric.  s2 is connected to resolve routes and get
	 * addresses.  this is the *only* way to get proper addresses for
	 * multihomed hosts if routing is asymmetric.
	 *
	 * A related problem in the server, but not the client, is that
	 * many os's have no way to disconnect a connected udp socket, so
	 * the s2 socket needs to be closed and recreated for each
	 * request.  The s1 socket must not be closed, or else queued
	 * requests will be lost.
	 *
	 * A "naive" client implementation (one socket, no connect,
	 * hostname resolution to get the local ip addr) will work and
	 * interoperate if the client is single-homed.
	 */

	if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		krb5_klog_syslog(LOG_ERR, gettext("chpw: Cannot create "
				"connecting socket: %s"), error_message(errno));
		goto cleanup;
	}

	if (connect(s2, (struct sockaddr *)&from, sizeof (from)) < 0) {
		krb5_klog_syslog(LOG_ERR, gettext("chpw: Couldn't connect "
				"to client: %s"), error_message(errno));
		if (s2 > 0)
			(void) close(s2);
		goto cleanup;
	}

	if ((ret = process_chpw_request(context, serverhandle,
					params->realm, s2, kt, &from,
					&reqdata, &repdata))) {
		krb5_klog_syslog(LOG_ERR, gettext("chpw: Error processing "
				"request: %s"), error_message(ret));
	}

	if (s2 > 0)
		(void) close(s2);

	if (repdata.length == 0 || repdata.data == NULL) {
		/*
		 * Just return.  This means something really bad happened
		 */
		goto cleanup;
	}

	len = sendto(s1, repdata.data, repdata.length, 0,
		    (struct sockaddr *)&from, sizeof (from));

	if (len < repdata.length) {
		krb5_xfree(repdata.data);

		krb5_klog_syslog(LOG_ERR, gettext("chpw: Error sending reply:"
				" %s"), error_message(errno));
		goto cleanup;
	}

	if (repdata.data != NULL)
		krb5_xfree(repdata.data);
cleanup:
	krb5_kt_close(context, kt);
}