Exemple #1
0
/* return list of current uids of local active sessions */
static GSList *uids_with_local_active_session(const char *own_id)
{
	GSList *list = NULL;
	GKeyFile *keyfile;

	keyfile = g_key_file_new();
	if (g_key_file_load_from_file(keyfile, "/var/run/ConsoleKit/database", 0, NULL)) {
		gchar **groups;

		groups = g_key_file_get_groups(keyfile, NULL);
		if (groups != NULL) {
			int i;

			for (i = 0; groups[i] != NULL; i++) {
				uid_t u;

				if (!g_str_has_prefix(groups[i], "Session "))
					continue;
				if (own_id != NULL &&g_str_has_suffix(groups[i], own_id))
					continue;
				if (!g_key_file_get_boolean(keyfile, groups[i], "is_local", NULL))
					continue;
				if (!g_key_file_get_boolean(keyfile, groups[i], "is_active", NULL))
					continue;
				u = g_key_file_get_integer(keyfile, groups[i], "uid", NULL);
				if (u > 0 && !uid_in_list(list, u))
					list = g_slist_prepend(list, GUINT_TO_POINTER(u));
			}
			g_strfreev(groups);
		}
	}
	g_key_file_free(keyfile);

	return list;
}
Exemple #2
0
/**
 * Processes an incoming REG_CONF message.
 * Expected in response to a REGISTER when encryption is disabled.
 */
void handle_regconf(struct group_list_t *group, const unsigned char *message,
                    unsigned meslen)
{
    const struct regconf_h *regconf;
    const uint32_t *addrlist;
    int addrcnt;

    regconf = (const struct regconf_h *)message;
    addrlist = (const uint32_t *)(message + (regconf->hlen * 4));

    if ((meslen < (regconf->hlen * 4U)) ||
            ((regconf->hlen * 4U) < sizeof(struct regconf_h))) {
        glog1(group, "Rejecting REG_CONF from server: invalid message size");
        return;
    }

    addrcnt = (meslen - (regconf->hlen * 4)) / 4;
    if (uid_in_list(addrlist, addrcnt)) {
        glog2(group, "Registration confirmed");
        group->phase = PHASE_MIDGROUP;
        set_timeout(group, 0);
    }
    if (group->restart) {
        read_restart_file(group);
    }
}
Exemple #3
0
static void
remove_uid (uid_t uid, const char *remove_session_id)
{
	/*
	 * Remove ACL for given uid from all matching devices
	 * when there is currently no local active session.
	 */
	GSList *list;

	list = uids_with_local_active_session(remove_session_id);
	if (!uid_in_list(list, uid))
		apply_acl_to_devices(uid, 0);
	g_slist_free(list);
}
Exemple #4
0
/**
 * Read in the contents of a FILEINFO message
 * Returns 1 on success, 0 on error or ignore
 */
int read_fileinfo(struct group_list_t *group, const unsigned char *message,
                  int meslen, struct timeval rxtime)
{
    const struct fileinfo_h *fileinfo;
    const uint32_t *addrlist;
    int listlen, maxsecsize;
    const char *name, *flink, *p;

    fileinfo = (const struct fileinfo_h *)message;
    addrlist = (const uint32_t *)(message + (fileinfo->hlen * 4));
    name = (const char *)message + sizeof(struct fileinfo_h);
    flink = name + (fileinfo->namelen * 4);
    listlen = (meslen - (fileinfo->hlen * 4)) / 4;

    if ((meslen < (fileinfo->hlen * 4)) ||
            ((fileinfo->hlen * 4) < sizeof(struct fileinfo_h)) ||
            ((fileinfo->namelen * 4) > MAXPATHNAME) ||
            ((fileinfo->linklen * 4) > MAXPATHNAME) ||
            ((fileinfo->hlen * 4) != sizeof(struct fileinfo_h) +
                (fileinfo->namelen * 4) + (fileinfo->linklen * 4))) {
        glog1(group, "Rejecting FILEINFO from server: invalid message size");
        send_abort(group, "Rejecting FILEINFO: invalid message size");
        return 0;
    }
    if (!uid_in_list(addrlist, listlen)) {
        set_timeout(group, 0);
        return 0;
    }

    if (group->phase == PHASE_RECEIVING) {
        // We already got the FILEINFO, so no need to reprocess.
        // Just resend the INFO_ACK and reset the timeout
        send_fileinfo_ack(group, group->fileinfo.restart);
        set_timeout(group, 0);
        return 0;
    }
    if ((group->phase == PHASE_MIDGROUP) &&
            (group->file_id == ntohs(fileinfo->file_id))) {
        // We already got the FILEINFO, and it's for a completed file.
        // So resend the COMPLETE and reset the timeout
        send_complete(group, (fileinfo->ftype == FTYPE_FREESPACE));
        set_timeout(group, 0);
        return 0;
    }

    // Load fileinfo params into list
    memset(&group->fileinfo, 0, sizeof(struct file_t));
    group->fileinfo.ftype = fileinfo->ftype;
    group->file_id = ntohs(fileinfo->file_id);
    strncpy(group->fileinfo.name, name, fileinfo->namelen * 4);
    strncpy(group->fileinfo.linkname, flink, fileinfo->linklen * 4);
    group->fileinfo.size = (f_offset_t)ntohs(fileinfo->hifsize) << 32;
    group->fileinfo.size |= ntohl(fileinfo->lofsize);

    if (group->fileinfo.size) {
        maxsecsize = (group->blocksize * 8 > MAXSECTION ?
                MAXSECTION : group->blocksize * 8);
        group->fileinfo.blocks =
                (int32_t)((group->fileinfo.size / group->blocksize) +
                (group->fileinfo.size % group->blocksize ? 1 : 0));
        group->fileinfo.sections = (group->fileinfo.blocks / maxsecsize) +
                (group->fileinfo.blocks % maxsecsize ? 1 : 0);
        group->fileinfo.secsize_small =
                group->fileinfo.blocks / group->fileinfo.sections;
        group->fileinfo.secsize_big = group->fileinfo.secsize_small +
                (group->fileinfo.blocks % group->fileinfo.sections ? 1 : 0);
        group->fileinfo.big_sections = group->fileinfo.blocks -
                (group->fileinfo.secsize_small * group->fileinfo.sections);
    } else {
        group->fileinfo.blocks = 0;
        group->fileinfo.sections = 0;
        group->fileinfo.secsize_small = 0;
        group->fileinfo.secsize_big = 0;
        group->fileinfo.big_sections = 0;
    }

    group->fileinfo.tstamp = ntohl(fileinfo->ftstamp);
    group->last_server_ts.tv_sec = ntohl(fileinfo->tstamp_sec);
    group->last_server_ts.tv_usec = ntohl(fileinfo->tstamp_usec);
    group->last_server_rx_ts = rxtime;
    group->fileinfo.fd = -1;

    // Run some checks on the filename
    if (strlen(group->fileinfo.name) == 0) {
        glog1(group, "Rejecting FILEINFO from server: blank file name");
        early_complete(group, COMP_STAT_REJECTED, 0);
        return 0;
    }
    p = strstr(group->fileinfo.name, "..");
    if ((p != NULL) && ((p[2] == '\x0') || (p[2] == '/') || (p[2] == '\\')) &&
           ((p == group->fileinfo.name) || (p[-1] == '/') || (p[-1] == '\\'))) {
        glog1(group, "Rejecting FILEINFO from server: filename contains ..");
        early_complete(group, COMP_STAT_REJECTED, 0);
        return 0;
    }
    if (fileinfo->ftype == FTYPE_LINK) {
        if (strlen(group->fileinfo.linkname) == 0) {
            glog1(group, "Rejecting FILEINFO from server: blank link name");
            early_complete(group, COMP_STAT_REJECTED, 0);
            return 0;
        }
    }

    return 1;
}
Exemple #5
0
int main (int argc, char* argv[])
{
	static const struct option options[] = {
		{ "action", required_argument, NULL, 'a' },
		{ "device", required_argument, NULL, 'D' },
		{ "user", required_argument, NULL, 'u' },
		{ "debug", no_argument, NULL, 'd' },
		{ "help", no_argument, NULL, 'h' },
		{}
	};
	int action = -1;
	const char *device = NULL;
	bool uid_given = false;
	uid_t uid = 0;
	uid_t uid2 = 0;
	const char* remove_session_id = NULL;
	int rc = 0;

	/* valgrind is more important to us than a slice allocator */
	g_slice_set_config (G_SLICE_CONFIG_ALWAYS_MALLOC, 1);

	while (1) {
		int option;

		option = getopt_long(argc, argv, "+a:D:u:dh", options, NULL);
		if (option == -1)
			break;

		switch (option) {
		case 'a':
			if (strcmp(optarg, "remove") == 0)
				action = ACTION_REMOVE;
			else
				action = ACTION_ADD;
			break;
		case 'D':
			device = optarg;
			break;
		case 'u':
			uid_given = true;
			uid = strtoul(optarg, NULL, 10);
			break;
		case 'd':
			debug = 1;
			break;
		case 'h':
			printf("Usage: udev-acl --action=ACTION [--device=DEVICEFILE] [--user=UID]\n\n");
			goto out;
		}
	}

	if (action < 0 && device == NULL && !uid_given)
		if (!consolekit_called(argv[optind], &uid, &uid2, &remove_session_id, &action))
			uid_given = true;

	if (action < 0) {
		fprintf(stderr, "missing action\n\n");
		rc = 2;
		goto out;
	}

	if (device != NULL && uid_given) {
		fprintf(stderr, "only one option, --device=DEVICEFILE or --user=UID expected\n\n");
		rc = 3;
		goto out;
	}

	if (uid_given) {
		switch (action) {
		case ACTION_ADD:
			/* Add ACL for given uid to all matching devices. */
			apply_acl_to_devices(uid, 1);
			break;
		case ACTION_REMOVE:
			remove_uid(uid, remove_session_id);
			break;
		case ACTION_CHANGE:
			remove_uid(uid, remove_session_id);
			apply_acl_to_devices(uid2, 1);
			break;
		case ACTION_NONE:
			goto out;
			break;
		default:
			g_assert_not_reached();
			break;
		}
	} else if (device != NULL) {
		/*
		 * Add ACLs for all current session uids to a given device.
		 *
		 * Or remove ACLs for uids which do not have any current local
		 * active session. Remove is not really interesting, because in
		 * most cases the device node is removed anyway.
		 */
		GSList *list;
		GSList *l;

		list = uids_with_local_active_session(NULL);
		for (l = list; l != NULL; l = g_slist_next(l)) {
			uid_t u;

			u = GPOINTER_TO_UINT(l->data);
			if (action == ACTION_ADD || !uid_in_list(list, u))
				set_facl(device, u, action == ACTION_ADD);
		}
		g_slist_free(list);
	} else {
		fprintf(stderr, "--device=DEVICEFILE or --user=UID expected\n\n");
		rc = 3;
	}
out:
	return rc;
}
Exemple #6
0
/**
 * Processes a new incoming ANNOUNCE
 */
void handle_announce(union sockaddr_u *src, unsigned char *packet,
                     unsigned packetlen, struct timeval rxtime)
{
    struct uftp_h *header;
    struct announce_h *announce;
    uint32_t *addrlist;
    int addrlen, rval;
    struct group_list_t *group;
    time_t t;
    struct tm *start_time;
    char privname[INET6_ADDRSTRLEN], srcname[INET6_ADDRSTRLEN];
    char srcfqdn[DESTNAME_LEN];

    header = (struct uftp_h *)packet;
    announce = (struct announce_h *)(packet + sizeof(struct uftp_h));
    addrlist = (uint32_t *)((unsigned char *)announce + (announce->hlen * 4));
    addrlen = (packetlen - sizeof(struct uftp_h) - (announce->hlen * 4)) / 4;

    if ((packetlen < sizeof(struct uftp_h) + (announce->hlen * 4U)) ||
            ((announce->hlen * 4U) < sizeof(struct announce_h))) {
        log1(ntohl(header->group_id), header->group_inst, 0, 
                "Rejecting ANNOUNCE from %08X: invalid message size",
                ntohl(header->src_id));
        return;
    }

    if ((addrlen != 0) && (!uid_in_list(addrlist, addrlen))) {
        log1(ntohl(header->group_id), header->group_inst, 0,
                "Name not in host list");
        return;
    }

    if ((group = find_open_slot()) == NULL ) {
        log0(ntohl(header->group_id), header->group_inst, 0,
             "Error: maximum number of incoming files exceeded: %d\n", MAXLIST);
        return;
    }

    t = time(NULL);
    start_time = localtime(&t);
    snprintf(group->start_date, sizeof(group->start_date), "%04d%02d%02d",
            start_time->tm_year + 1900,
            start_time->tm_mon + 1, start_time->tm_mday);
    snprintf(group->start_time, sizeof(group->start_time), "%02d%02d%02d",
            start_time->tm_hour, start_time->tm_min, start_time->tm_sec);

    if (!read_announce(group, packet, src, rxtime, packetlen)) {
        return;
    }

    if ((rval = getnameinfo((struct sockaddr *)src, family_len(*src),
            srcname, sizeof(srcname), NULL, 0, NI_NUMERICHOST)) != 0) {
        glog1(group, "getnameinfo failed: %s", gai_strerror(rval));
    }
    if (!noname) {
        if ((rval = getnameinfo((struct sockaddr *)src, family_len(*src),
                srcfqdn, sizeof(srcfqdn), NULL, 0, 0)) != 0) {
            glog1(group, "getnameinfo failed: %s", gai_strerror(rval));
        }
    } else {
        strncpy(srcfqdn, srcname, sizeof(srcfqdn) - 1);
    }
    if ((rval = getnameinfo((struct sockaddr *)&group->multi,
            family_len(group->multi), privname, sizeof(privname),
            NULL, 0, NI_NUMERICHOST)) != 0) {
        glog1(group, "getnameinfo failed: %s", gai_strerror(rval));
    }

    glog2(group, "Received request from %08X at %s (%s)",
                             ntohl(group->src_id), srcfqdn, srcname);
    glog2(group, "Using private multicast address %s", privname);
    glog3(group, "grtt = %.6f", group->grtt);
    glog3(group, "send time: %d.%06d", group->last_server_ts.tv_sec,
                 group->last_server_ts.tv_usec);
    glog3(group, "receive time: %d.%06d", group->last_server_rx_ts.tv_sec,
                 group->last_server_rx_ts.tv_usec);

    if (status_file) {
        fprintf(status_file,
                "CONNECT;%04d/%02d/%02d-%02d:%02d:%02d;%08X;%08X;%s;%s\n",
                start_time->tm_year + 1900, start_time->tm_mon + 1,
                start_time->tm_mday, start_time->tm_hour,
                start_time->tm_min, start_time->tm_sec,
                ntohl(group->src_id), group->group_id, srcname, srcfqdn);
        fflush(status_file);
    }

    if (group->restart) {
        if (group->sync_mode) {
            glog1(group, "Sync mode and restart mode incompatible");
            send_abort(group, "Sync mode and restart mode incompatible");
            return;
        }
    }

    if (!addr_blank(&group->multi)) {
        if (server_count > 0) {
            if (!is_multicast(&group->multi, 1)) {
                glog1(group, "Invalid source specific multicast address: %s",
                             privname);
                send_abort(group, "Invalid source specific multicast address");
                return;
            }
            if (!other_mcast_users(group)) {
                if (!multicast_join(listener, group->group_id, &group->multi,
                        m_interface, interface_count,
                        server_keys, server_count)) {
                    send_abort(group, "Error joining multicast group");
                    return;
                }
                if (has_proxy) {
                    if (!multicast_join(listener,group->group_id, &group->multi,
                            m_interface, interface_count, &proxy_info, 1)) {
                        send_abort(group, "Error joining multicast group");
                        return;
                    }
                }
            }
        } else {
            if (!is_multicast(&group->multi, 0)) {
                glog1(group, "Invalid multicast address: %s", privname);
                send_abort(group, "Invalid multicast address");
                return;
            }
            if (!other_mcast_users(group)) {
                if (!multicast_join(listener, group->group_id,
                        &group->multi, m_interface, interface_count, NULL, 0)) {
                    send_abort(group, "Error joining multicast group");
                    return;
                }
            }
        }
        group->multi_join = 1;
    }

    send_register(group);
}