X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=afs.c;h=071f657ce69c79812d29a982f69cc5c0bbf8f8b7;hp=fa750d21c2424e1beb3e08a42226e54c5feff40d;hb=0b6e7a20c19d642f9d8e65683e1525c91dd3de39;hpb=e469622d99718d49158d5da649eb02180269b4c8 diff --git a/afs.c b/afs.c index fa750d21..071f657c 100644 --- a/afs.c +++ b/afs.c @@ -97,10 +97,11 @@ static char *current_mop; /* mode or playlist specifier. NULL means dummy mood * /** * A random number used to "authenticate" the connection. * - * para_server picks this number by random before forking the afs process. The - * command handlers write this number together with the id of the shared memory - * area containing the query. This way, a malicious local user has to know this - * number to be able to cause the afs process to crash by sending fake queries. + * para_server picks this number by random before it forks the afs process. The + * command handlers know this number as well and write it to the afs socket, + * together with the id of the shared memory area which contains the payload of + * the afs command. A local process has to know this number to abuse the afs + * service provided by the local socket. */ extern uint32_t afs_socket_cookie; @@ -423,7 +424,7 @@ static int pass_afd(int fd, char *buf, size_t size) { struct msghdr msg = {.msg_iov = NULL}; struct cmsghdr *cmsg; - char control[255]; + char control[255] __a_aligned(8); int ret; struct iovec iov; @@ -496,12 +497,11 @@ no_admissible_files: } /* Never fails if arg == NULL */ -static int activate_mood_or_playlist(char *arg, int *num_admissible) +static int activate_mood_or_playlist(const char *arg, int *num_admissible) { enum play_mode mode; int ret; - PARA_INFO_LOG("new playlist: %s\n", arg); if (!arg) { ret = change_current_mood(NULL); /* always successful */ mode = PLAY_MODE_MOOD; @@ -574,7 +574,7 @@ int afs_cb_result_handler(struct osl_object *result, uint8_t band, } } -void flush_and_free_pb(struct para_buffer *pb) +static void flush_and_free_pb(struct para_buffer *pb) { int ret; struct afs_max_size_handler_data *amshd = pb->private_data; @@ -588,22 +588,14 @@ void flush_and_free_pb(struct para_buffer *pb) free(pb->buf); } -static int com_select_callback(int fd, const struct osl_object *query) +static int com_select_callback(struct afs_callback_arg *aca) { - struct para_buffer pb = { - .max_size = shm_get_shmmax(), - .private_data = &(struct afs_max_size_handler_data) { - .fd = fd, - .band = SBD_OUTPUT - }, - .max_size_handler = afs_max_size_handler, - }; - char *arg = query->data; + const char *arg = aca->query.data; int num_admissible, ret; ret = clear_score_table(); if (ret < 0) { - para_printf(&pb, "could not clear score table: %s\n", + para_printf(&aca->pbout, "could not clear score table: %s\n", para_strerror(-ret)); return ret; } @@ -614,20 +606,22 @@ static int com_select_callback(int fd, const struct osl_object *query) ret = activate_mood_or_playlist(arg, &num_admissible); if (ret >= 0) goto out; - para_printf(&pb, "could not activate %s: %s\n" - "switching back to %s\n", - arg, para_strerror(-ret), current_mop? current_mop : "dummy"); /* ignore subsequent errors (but log them) */ - ret = activate_mood_or_playlist(current_mop, &num_admissible); - if (ret >= 0) - goto out; - para_printf(&pb, "could not activate %s: %s\nswitching to dummy\n", - current_mop, para_strerror(-ret)); + para_printf(&aca->pbout, "could not activate %s\n", arg); + if (current_mop) { + int ret2; + para_printf(&aca->pbout, "switching back to %s\n", current_mop); + ret2 = activate_mood_or_playlist(current_mop, &num_admissible); + if (ret2 >= 0) + goto out; + para_printf(&aca->pbout, "could not reactivate %s: %s\n", + current_mop, para_strerror(-ret2)); + } + para_printf(&aca->pbout, "activating dummy mood\n"); activate_mood_or_playlist(NULL, &num_admissible); out: - para_printf(&pb, "activated %s (%d admissible files)\n", + para_printf(&aca->pbout, "activated %s (%d admissible files)\n", current_mop? current_mop : "dummy mood", num_admissible); - flush_and_free_pb(&pb); return ret; } @@ -658,7 +652,7 @@ static int setup_command_socket_or_die(void) ret = create_local_socket(socket_name, 0); if (ret < 0) { ret = create_local_socket(socket_name, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IWOTH); + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IROTH); if (ret < 0) { PARA_EMERG_LOG("%s: %s\n", para_strerror(-ret), socket_name); @@ -702,7 +696,7 @@ static int make_database_dir(void) get_database_dir(); ret = para_mkdir(database_dir, 0777); - if (ret >= 0 || is_errno(-ret, EEXIST)) + if (ret >= 0 || ret == -ERRNO_TO_PARA_ERROR(EEXIST)) return 1; return ret; } @@ -849,16 +843,22 @@ static int call_callback(int fd, int query_shmid) { void *query_shm; struct callback_query *cq; - struct osl_object query; int ret, ret2; + struct afs_callback_arg aca = {.fd = fd}; ret = shm_attach(query_shmid, ATTACH_RW, &query_shm); if (ret < 0) return ret; cq = query_shm; - query.data = (char *)query_shm + sizeof(*cq); - query.size = cq->query_size; - ret = cq->handler(fd, &query); + aca.query.data = (char *)query_shm + sizeof(*cq); + aca.query.size = cq->query_size; + aca.pbout.max_size = shm_get_shmmax(); + aca.pbout.max_size_handler = afs_max_size_handler; + aca.pbout.private_data = &(struct afs_max_size_handler_data) { + .fd = fd, + .band = SBD_OUTPUT + }; + ret = cq->handler(&aca); ret2 = shm_detach(query_shm); if (ret2 < 0) { if (ret < 0) /* ignore (but log) detach error */ @@ -867,6 +867,7 @@ static int call_callback(int fd, int query_shmid) else ret = ret2; } + flush_and_free_pb(&aca.pbout); if (ret < 0) { ret2 = pass_buffer_as_shm(fd, SBD_AFS_CB_FAILURE, (const char *)&ret, sizeof(ret)); @@ -1023,6 +1024,13 @@ __noreturn void afs_init(uint32_t cookie, int socket_fd) register_command_task(cookie, &s); s.default_timeout.tv_sec = 0; s.default_timeout.tv_usec = 999 * 1000; + ret = write(socket_fd, "\0", 1); + if (ret != 1) { + if (ret == 0) + errno = EINVAL; + ret = -ERRNO_TO_PARA_ERROR(errno); + goto out_close; + } ret = schedule(&s); sched_shutdown(&s); out_close: @@ -1033,17 +1041,10 @@ out: exit(EXIT_FAILURE); } -static int com_init_callback(int fd, const struct osl_object *query) +static int com_init_callback(struct afs_callback_arg *aca) { - uint32_t table_mask = *(uint32_t *)query->data; + uint32_t table_mask = *(uint32_t *)aca->query.data; int i, ret; - struct para_buffer pb = { - .max_size = shm_get_shmmax(), - .private_data = &(struct afs_max_size_handler_data) { - .fd = fd, - .band = SBD_OUTPUT - } - }; close_afs_tables(); for (i = 0; i < NUM_AFS_TABLES; i++) { @@ -1055,16 +1056,17 @@ static int com_init_callback(int fd, const struct osl_object *query) continue; ret = t->create(database_dir); if (ret < 0) { - para_printf(&pb, "cannot create table %s\n", t->name); + para_printf(&aca->pbout, "cannot create table %s\n", + t->name); goto out; } - para_printf(&pb, "successfully created %s table\n", t->name); + para_printf(&aca->pbout, "successfully created %s table\n", + t->name); } ret = open_afs_tables(); if (ret < 0) - para_printf(&pb, "cannot open afs tables\n"); + para_printf(&aca->pbout, "cannot open afs tables\n"); out: - flush_and_free_pb(&pb); return ret; }