master-auth.c revision 6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbe
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen/* Copyright (C) 2005 Timo Sirainen */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "lib.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "ioloop.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "fdpass.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "buffer.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "hash.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "master-service-private.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "master-auth.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <stdlib.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <unistd.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <sys/stat.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstruct master_auth {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct master_service *service;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen pool_t pool;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int fd;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct io *io;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int tag_counter;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct hash_table *requests;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen char buf[sizeof(struct master_auth_reply)];
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int buf_pos;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* linked list, node->context is the next pointer */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct master_auth_request_node *free_nodes;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen};
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstruct master_auth_request_node {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_auth_callback_t *callback;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen void *context;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen};
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic struct master_auth_request_node aborted_node;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenunsigned int master_auth_request(struct master_service *service, int fd,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct master_auth_request *request,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const unsigned char *data,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_auth_callback_t *callback,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen void *context)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct master_auth *auth = service->auth;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct master_auth_request_node *node;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct master_auth_request req;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_t *buf;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct stat st;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ssize_t ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(request->auth_pid != 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen req = *request;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen req.tag = ++auth->tag_counter;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (req.tag == 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen req.tag = ++auth->tag_counter;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (fstat(fd, &st) < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal("fstat(auth dest fd) failed: %m");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen req.ino = st.st_ino;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buf = buffer_create_dynamic(pool_datastack_create(),
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen sizeof(req) + req.data_size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_append(buf, &req, sizeof(req));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_append(buf, data, req.data_size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = fd_send(auth->fd, fd, buf->data, buf->used);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ret < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal("fd_send(%d) failed: %m", fd);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((size_t)ret != buf->used) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal("fd_send() sent only %d of %d bytes",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (int)ret, (int)buf->used);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (auth->free_nodes == NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen node = p_new(auth->pool, struct master_auth_request_node, 1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen node = auth->free_nodes;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen auth->free_nodes = node->context;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen node->callback = callback;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen node->context = context;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hash_table_insert(auth->requests, POINTER_CAST(req.tag), node);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return req.tag;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_auth_request_abort(struct master_service *service, unsigned int tag)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct master_auth *auth = service->auth;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct master_auth_request_node *node;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen node = hash_table_lookup(auth->requests, POINTER_CAST(tag));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (node == NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_panic("master_auth_request_abort(): tag %u not found", tag);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(node != &aborted_node);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hash_table_update(auth->requests, POINTER_CAST(tag), &aborted_node);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen node->callback = NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen node->context = auth->free_nodes;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen auth->free_nodes = node;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainenstatic void
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainenmaster_notify_have_more_avail_processes(struct master_service *service,
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen bool have_more)
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen{
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (!have_more) {
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen /* make sure we're listening for more connections */
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen master_service_io_listeners_add(service);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen }
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen service->call_avail_overflow = !have_more;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen}
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void request_handle(struct master_auth *auth,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct master_auth_reply *reply)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct master_auth_request_node *node;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (reply->tag == 0) {
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen /* notification from master */
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen master_notify_have_more_avail_processes(auth->service,
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen reply->status == 0);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen return;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen }
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen node = hash_table_lookup(auth->requests, POINTER_CAST(reply->tag));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (node == NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("Master sent reply with unknown tag %u", reply->tag);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (node != &aborted_node) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen node->callback(reply, node->context);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* the callback may have called master_auth_request_abort(),
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen which would have put the node to free_nodes list already */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (node->callback != NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen node->callback = NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen node->context = auth->free_nodes;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen auth->free_nodes = node;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hash_table_remove(auth->requests, POINTER_CAST(reply->tag));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void master_auth_input(void *context)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct master_auth *auth = context;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = net_receive(auth->fd, auth->buf + auth->buf_pos,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen sizeof(auth->buf) - auth->buf_pos);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ret < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* master died, kill all clients logging in */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_service_stop(auth->service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen auth->buf_pos += ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (auth->buf_pos < sizeof(auth->buf))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* reply is now read */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen request_handle(auth, (struct master_auth_reply *) auth->buf);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen auth->buf_pos = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_auth_init(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct master_auth *auth;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct ip_addr ip;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen pool_t pool;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(service->auth == NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (getenv("MASTER_AUTH_FD") == NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal("auth_dest_service setting not set");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (net_getsockname(MASTER_AUTH_FD, &ip, NULL) < 0 ||
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ip.family != AF_UNIX)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal("MASTER_AUTH_FD not given");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen pool = pool_alloconly_create("master auth", 1024);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen auth = p_new(pool, struct master_auth, 1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen auth->pool = pool;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen auth->service = service;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen auth->fd = MASTER_AUTH_FD;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen auth->requests = hash_table_create(default_pool, pool, 0, NULL, NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen auth->io = io_add(auth->fd, IO_READ, master_auth_input, auth);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->auth = auth;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_auth_deinit(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct master_auth *auth = service->auth;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(service->auth != NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hash_table_destroy(&auth->requests);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (auth->io != NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen io_remove(&auth->io);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (close(auth->fd) < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal("close(master auth) failed: %m");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen pool_unref(&auth->pool);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->auth = NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}