srvd_boolean_t srvd_server_unsock_initialize(srvd_server_unsock_t *server, const srvd_server_unsock_conf_t *conf) { SRVD_RETURN_FALSE_UNLESS(server); SRVD_RETURN_FALSE_UNLESS(conf); SRVD_RETURN_FALSE_UNLESS(conf->path); if(!srvd_server_initialize(&server->monitor)) { SRVD_LOG_ERROR("srvd_server_unsock_initialize: Unable to initialize server monitor"); return SRVD_FALSE; } /* Copy the configuration. */ server->conf = *conf; /* Set up the address. */ server->endpoint.sun_family = AF_UNIX; strncpy(server->endpoint.sun_path, server->conf.path, _SUN_PATH_LENGTH); server->endpoint.sun_path[_SUN_PATH_LENGTH - 1] = '\0'; /* Set up the socket. */ server->socket = socket(PF_UNIX, SOCK_STREAM, 0); if(server->socket == -1) { SRVD_LOG_ERROR("srvd_server_unsock_initialize: Error creating socket"); return SRVD_FALSE; } return SRVD_TRUE; }
srvd_boolean_t srvd_service_nss_passwd_request_name_get(const srvd_service_request_t *request, char **name) { srvd_protocol_packet_field_t *field = NULL; srvd_protocol_packet_field_entry_t *entry = NULL; SRVD_RETURN_FALSE_UNLESS(request); SRVD_RETURN_FALSE_UNLESS(request->packet.field_count > 0); SRVD_RETURN_FALSE_UNLESS(name); SRVD_RETURN_FALSE_UNLESS(*name == NULL); srvd_protocol_packet_field_get_first(&request->packet, &field); if(field->type != SRVD_SERVICE_NSS_PASSWD_REQUEST_NAME) { SRVD_LOG_ERROR("srvd_service_nss_passwd_request_name_get: Invalid packet type"); return SRVD_FALSE; } SRVD_RETURN_FALSE_UNLESS(field->entry_count == 1); srvd_protocol_packet_field_entry_get_first(field, &entry); *name = malloc(entry->size); if(*name == NULL) { SRVD_LOG_ERROR("srvd_service_nss_passwd_request_name_get: Unable to allocate memory for name"); return SRVD_FALSE; } strncpy(*name, entry->data, entry->size); (*name)[entry->size - 1] = '\0'; return SRVD_TRUE; }
srvd_boolean_t srvd_service_nss_passwd_response_gecos_set(srvd_service_response_t *response, const char *gecos, size_t length) { SRVD_RETURN_FALSE_UNLESS(response); SRVD_RETURN_FALSE_UNLESS(gecos); return srvd_protocol_packet_field_append(&response->packet, SRVD_SERVICE_NSS_PASSWD_RESPONSE_GECOS, length, gecos); }
srvd_boolean_t srvd_service_nss_passwd_response_shell_set(srvd_service_response_t *response, const char *shell, size_t length) { SRVD_RETURN_FALSE_UNLESS(response); SRVD_RETURN_FALSE_UNLESS(shell); return srvd_protocol_packet_field_append(&response->packet, SRVD_SERVICE_NSS_PASSWD_RESPONSE_SHELL, length, shell); }
srvd_boolean_t srvd_service_nss_passwd_request_name_free(const srvd_service_request_t *request, char **name) { SRVD_RETURN_FALSE_UNLESS(request); SRVD_RETURN_FALSE_UNLESS(name); SRVD_RETURN_FALSE_UNLESS(*name); free(*name); *name = NULL; return SRVD_TRUE; }
srvd_boolean_t srvd_server_service_get(srvd_server_t *server, srvd_protocol_type_t type, srvd_server_service_handler_pt *handler) { SRVD_RETURN_FALSE_UNLESS(server); SRVD_RETURN_FALSE_UNLESS(handler); srvd_server_service_t *i = server->services; for(; i != NULL; i = i->next) { if(i->type == type) { *handler = i->handler; return SRVD_TRUE; } } return SRVD_FALSE; }
srvd_boolean_t srvd_server_initialize(srvd_server_t *server) { SRVD_RETURN_FALSE_UNLESS(server); server->executing = SRVD_FALSE; server->services = NULL; return SRVD_TRUE; }
srvd_boolean_t srvd_service_nss_passwd_response_gid_set(srvd_service_response_t *response, gid_t gid) { SRVD_RETURN_FALSE_UNLESS(response); return srvd_protocol_packet_field_append_uint32(&response->packet, SRVD_SERVICE_NSS_PASSWD_RESPONSE_GID, (uint32_t)gid); }
srvd_boolean_t srvd_protocol_serial_packet_initialize(srvd_protocol_serial_packet_t *serial) { SRVD_RETURN_FALSE_UNLESS(serial); serial->size = 0; serial->body_size = 0; serial->data = NULL; return SRVD_TRUE; }
srvd_boolean_t srvd_protocol_serial_packet_finalize(srvd_protocol_serial_packet_t *serial) { SRVD_RETURN_FALSE_UNLESS(serial); if(serial->data) free(serial->data); serial->size = 0; serial->body_size = 0; return SRVD_TRUE; }
srvd_boolean_t srvd_server_service_has(srvd_server_t *server, srvd_protocol_type_t type) { SRVD_RETURN_FALSE_UNLESS(server); srvd_server_service_t *i = server->services; for(; i != NULL; i = i->next) { if(i->type == type) return SRVD_TRUE; } return SRVD_FALSE; }
srvd_boolean_t srvd_service_nss_passwd_request_entities_get(const srvd_service_request_t *request, int32_t *offset) { srvd_protocol_packet_field_t *field = NULL; srvd_protocol_packet_field_entry_t *entry = NULL; SRVD_RETURN_FALSE_UNLESS(request); SRVD_RETURN_FALSE_UNLESS(request->packet.field_count > 0); SRVD_RETURN_FALSE_UNLESS(offset); srvd_protocol_packet_field_get_first(&request->packet, &field); if(field->type != SRVD_SERVICE_NSS_PASSWD_REQUEST_ENTITIES) { SRVD_LOG_ERROR("srvd_service_nss_passwd_request_entites_get: Invalid packet type"); return SRVD_FALSE; } SRVD_RETURN_FALSE_UNLESS(field->entry_count == 1); srvd_protocol_packet_field_entry_get_first(field, &entry); return srvd_protocol_packet_field_entry_get_uint32(entry, (uint32_t *)offset); }
srvd_boolean_t srvd_server_finalize(srvd_server_t *server) { SRVD_RETURN_FALSE_UNLESS(server); server->executing = SRVD_FALSE; srvd_server_service_t *i, *ni; for(i = server->services, ni = i ? i->next : NULL; i != NULL; i = ni, ni = i ? i->next : NULL) { free(i); } server->services = NULL; return SRVD_TRUE; }
srvd_boolean_t srvd_server_unsock_finalize(srvd_server_unsock_t *server) { SRVD_RETURN_FALSE_UNLESS(server); if(!server->monitor.executing) { SRVD_LOG_ERROR("srvd_server_unsock_finalize: Cannot finalize: Server is still executing"); return SRVD_FALSE; } if(!srvd_server_finalize(&server->monitor)) { SRVD_LOG_ERROR("srvd_server_unsock_finalize: Unable to finalize server monitor"); return SRVD_FALSE; } return SRVD_TRUE; }
srvd_boolean_t srvd_server_service_remove(srvd_server_t *server, srvd_protocol_type_t type) { SRVD_RETURN_FALSE_UNLESS(server); srvd_server_service_t *pi, *i; for(pi = NULL, i = server->services; i != NULL; pi = i, i = i->next) { if(i->type == type) { if(pi == NULL) server->services = i->next; else pi->next = i->next; free(i); return SRVD_TRUE; } } return SRVD_FALSE; }
srvd_boolean_t srvd_server_service_add(srvd_server_t *server, srvd_protocol_type_t type, srvd_server_service_handler_pt handler) { SRVD_RETURN_FALSE_UNLESS(server); if(!srvd_server_service_has(server, type)) { srvd_server_service_t *node = malloc(sizeof(srvd_server_service_t)); if(node == NULL) { SRVD_LOG_ERROR("srvd_server_service_add: Unable to allocate memory for node"); return SRVD_FALSE; } node->type = type; node->handler = handler; node->next = server->services; server->services = node; return SRVD_TRUE; } else return SRVD_FALSE; }
srvd_boolean_t srvd_server_unsock_execute(srvd_server_unsock_t *server) { srvd_boolean_t status = SRVD_TRUE; SRVD_RETURN_FALSE_UNLESS(server); server->monitor.executing = SRVD_TRUE; if(bind(server->socket, (struct sockaddr *)&server->endpoint, sizeof(struct sockaddr_un)) == -1) { SRVD_LOG_ERROR("srvd_server_unsock_execute: Unable to bind to socket at \"%s\"", server->endpoint.sun_path); return SRVD_FALSE; } if(listen(server->socket, server->conf.queue_size) == -1) { SRVD_LOG_ERROR("srvd_server_unsock_execute: Unable to listen on bound socket"); return SRVD_FALSE; } for(;;) { int client = accept(server->socket, NULL, 0); if(client == -1) { SRVD_LOG_WARNING("srvd_server_unsock_execute: Error accept()ing client"); continue; } srvd_service_request_t request; srvd_service_response_t response; srvd_service_request_initialize(&request); srvd_service_response_initialize(&response); if(!_srvd_server_unsock_read(client, &request.packet)) { SRVD_LOG_WARNING("srvd_server_unsock_execute: Could not read data from client"); goto _srvd_server_unsock_execute_client_error; } srvd_protocol_packet_field_t *field = NULL; if(!srvd_protocol_packet_field_get_first(&request.packet, &field)) { /* Nothing valid? */ SRVD_LOG_WARNING("srvd_server_unsock_execute: Invalid packet"); goto _srvd_server_unsock_execute_client_error; } /* Okay, let's see if we have a matching handler for the request. */ srvd_server_service_handler_pt handler = NULL; if(srvd_server_service_get(&server->monitor, field->type, &handler)) { handler(&request, &response); /* Get the response status and inject it into the list of fields. */ srvd_protocol_packet_field_insert_uint16(&response.packet, SRVD_PROTOCOL_STATUS, response.status); } else /* Nope -- unavailable. */ srvd_protocol_packet_field_insert_uint16(&response.packet, SRVD_PROTOCOL_STATUS, SRVD_SERVICE_RESPONSE_UNAVAIL); if(!_srvd_server_unsock_write(client, &response.packet)) { SRVD_LOG_WARNING("srvd_server_unsock_execute: Could not write data to client"); goto _srvd_server_unsock_execute_client_error; } _srvd_server_unsock_execute_client_error: srvd_service_request_finalize(&request); srvd_service_response_finalize(&response); if(client >= 0) close(client); } close(server->socket); server->monitor.executing = SRVD_FALSE; return status; }