aboutsummaryrefslogblamecommitdiff
path: root/src/npassd/session.c
blob: 52f8476af020e2f5079e0993f6f54a51479810d0 (plain) (tree)
1
2
3
4
5
6




                         
                   







                                                                                


                                                                   







                                                    

















                                                                   
                                    
                              
 


                 
                                                        

                                                                        

                                       

                






                                                                      

                                    
 
                                                   

 
                                       
 




                                                                           

         

















                                                  

 
                                                                   
 

                                

                



















                                                                            



                                                                 




                                                 

         

                                                                               
                      
                                      
                                                                          

                           
 



                                                                      




                                                


                   
#include <errno.h>
#include <linux/limits.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <systemd/sd-bus.h>

#include "npassd/common.h"
#include "npassd/session.h"
#include "util.h"

static int handle_close(__attribute__((unused)) sd_bus_message *msg, void *data,
			__attribute__((unused)) sd_bus_error *ret_error);
static int handle_nameownerchanged(sd_bus_message *msg, void *data,
				   __attribute__((unused))
				   sd_bus_error *ret_error);

static const sd_bus_vtable session_vtable[] = {
	SD_BUS_VTABLE_START(0),
	SD_BUS_METHOD("Close", "", "", handle_close,
		      SD_BUS_VTABLE_UNPRIVILEGED),
	SD_BUS_VTABLE_END,
};

static int handle_nameownerchanged(sd_bus_message *msg, void *data,
				   __attribute__((unused))
				   sd_bus_error *ret_error)
{
	struct session *session = data;
	const char *name;
	int ret;

	ret = sd_bus_message_read(msg, "ss", NULL, &name);
	if (ret < 0) {
		print_err("%s", strerror(-ret));
		return ret;
	}

	ret = strcmp(session->owner, name);
	if (ret)
		return 0;

	LIST_REMOVE(session, dlist);
	session_free(session);

	return 0;
}

static int handle_close(sd_bus_message *msg, void *data,
			__attribute__((unused)) sd_bus_error *ret_error)
{
	struct session *session = data;
	const char *sender;
	int ret;

	sender = sd_bus_message_get_sender(msg);
	ret = strcmp(sender, session->owner);
	if (ret) {
		print_err("Unauthorized session close by %s", sender);
		return -EPERM;
	}

	LIST_REMOVE(session, dlist);
	session_free(session);

	return sd_bus_reply_method_return(msg, "");
}

static int session_id_get(uint64_t *id)
{
	static uint64_t count = 0;

	if (count == UINT64_MAX) {
		print_err("%s", "Congratulations, we ran out of uint64_t");
		return -ERANGE;
	}

	*id = count++;
	return 0;
}

void session_free(struct session *s)
{
	if (s == NULL)
		return;

	if (s->slot_singal != NULL)
		sd_bus_slot_unref(s->slot_singal);
	if (s->slot != NULL)
		sd_bus_slot_unref(s->slot);
	if (s->owner != NULL)
		free(s->owner);
	if (s->path != NULL)
		free(s->path);
	free(s);
}

int session_new(sd_bus *bus, struct session **p, const char *owner)
{
	struct session *session;
	uint64_t id;
	int ret;

	*p = malloc(sizeof(**p));
	if (*p == NULL) {
		print_err("Failed to make session: %s", strerror(errno));
		return -errno;
	}
	session = *p;
	session->slot_singal = NULL;
	session->slot = NULL;
	session->owner = NULL;
	session->path = NULL;

	ret = session_id_get(&id);
	if (ret < 0) {
		session_free(session);
		return ret;
	}

	ret = asprintf(&session->path, DBUS_OBJECT_PATH "/session/%lu", id);
	if (ret < 0) {
		session_free(session);
		print_err("%s", "Failed to create session path");
		return -ENOMEM;
	}

	session->owner = strdup(owner);
	if (session->owner == NULL) {
		session_free(session);
		print_err("%s", strerror(errno));
		return -errno;
	}

	ret = sd_bus_add_object_vtable(bus, &session->slot, session->path,
				       SESSION_IFACE, session_vtable, session);
	if (ret < 0) {
		session_free(session);
		print_err("Failed to create session: %s", strerror(-ret));
		return ret;
	}

	ret = sd_bus_match_signal(
		bus, &session->slot_singal, "org.freedesktop.DBus",
		"/org/freedesktop/DBus", "org.freedesktop.DBus",
		"NameOwnerChanged", handle_nameownerchanged, session);
	if (ret < 0) {
		session_free(session);
		print_err("%s", strerror(-ret));
		return ret;
	}

	return ret;
}