| /* Tests for name switch cache daemon (nscd) door wrapper. */ |
| |
| #include "config.h" |
| |
| #include <assert.h> |
| #include <ctype.h> |
| #include <door.h> |
| #include <fcntl.h> |
| #include <inttypes.h> |
| #include <nss_dbdefs.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <strings.h> |
| #include <unistd.h> |
| #include <sys/mman.h> |
| |
| #if defined(SOLARIS_NSCD_DOOR_SYSTEM_VOLATILE) |
| #define DOOR_FILE "/system/volatile/name_service_door" |
| #else |
| #define DOOR_FILE "/var/run/name_service_door" |
| #endif |
| |
| #define HEADER(file, test_name) \ |
| fprintf(file, "---------------------------------------------------------\n" \ |
| "%s\n" \ |
| "---------------------------------------------------------\n", \ |
| test_name); |
| |
| |
| static long x0; |
| |
| /* It's possible that the system allocated a new memory for rbuf. |
| Unmap it if it is the case. */ |
| static int handle_rbuf(door_arg_t *params, void *buf) |
| { |
| if (params->rbuf != buf) { |
| if (munmap(params->rbuf, params->rsize) != 0) { |
| perror("munmap"); |
| return EINVAL; |
| } |
| } |
| |
| return 0; |
| } |
| |
| __attribute__((noinline)) |
| static int test_app_small_request(int did) |
| { |
| /* Set call parameters. */ |
| size_t buf_size = sizeof(uint32_t); |
| char *buf = malloc(buf_size); |
| assert(buf != NULL); |
| |
| nss_pheader_t *header = (nss_pheader_t *) buf; |
| header->nsc_callnumber = x0 + NSCD_GETENT; |
| |
| door_arg_t params; |
| params.data_ptr = buf; |
| params.data_size = buf_size; |
| params.desc_ptr = NULL; |
| params.desc_num = 0; |
| params.rbuf = buf; |
| params.rsize = buf_size; |
| |
| /* Make the call. */ |
| if (door_call(did, ¶ms) != 0) { |
| return errno; |
| } |
| |
| return handle_rbuf(¶ms, buf); |
| } |
| |
| __attribute__((noinline)) |
| static int test_app_uninitialized_request(int did) |
| { |
| /* Set call parameters. */ |
| size_t buf_size = sizeof(nss_pheader_t) + sizeof(nss_dbd_t); |
| char *buf = malloc(buf_size); |
| assert(buf != NULL); |
| |
| nss_pheader_t *header = (nss_pheader_t *) buf; |
| header->nsc_callnumber = x0 + NSCD_GETENT; |
| header->dbd_off = x0 + sizeof(nss_pheader_t); |
| header->dbd_len = x0 + sizeof(nss_dbd_t); |
| nss_dbd_t *dbd = (nss_dbd_t *) (buf + sizeof(nss_pheader_t)); |
| dbd->flags = x0; |
| dbd->o_name = x0 + 100; |
| dbd->o_config_name = x0 + 100; |
| dbd->o_default_config = x0 + 100; |
| header->key_off = x0 + sizeof(nss_pheader_t) + sizeof(nss_dbd_t); |
| header->key_len = x0 + 1; // one byte past the end of 'buf' |
| header->pbufsiz = x0 + 10000000; |
| |
| door_arg_t params; |
| params.data_ptr = buf; |
| params.data_size = buf_size; |
| params.desc_ptr = NULL; |
| params.desc_num = 0; |
| params.rbuf = buf; |
| params.rsize = buf_size; |
| |
| /* Make the call. */ |
| if (door_call(did, ¶ms) != 0) { |
| return errno; |
| } |
| |
| /* Check definedness of response attributes ... */ |
| int x = 0; |
| if (header->p_status != NSS_SUCCESS) x = -1; else x = -2; |
| if (header->p_herrno != 0) x = -2; else x = -3; |
| if (header->key_off != 0) x = -4; else x = -5; |
| if (header->key_len != 0) x = -6; else x = -7; |
| if (header->data_off != 0) x = -8; else x = -9; |
| if (header->data_len != 0) x = -10; else x = -11; |
| /* ... and now one which is not defined. */ |
| if (header->reserved1 != 0) x = -12; else x = -13; |
| |
| handle_rbuf(¶ms, buf); |
| return x; |
| } |
| |
| __attribute__((noinline)) |
| static int test_app_proto_icmp(int did) |
| { |
| door_arg_t params; |
| char buf[16384]; |
| |
| /* Set call parameters. */ |
| nss_pheader_t *header = (nss_pheader_t *) buf; |
| header->nsc_callnumber = NSCD_SEARCH; |
| header->p_ruid = getuid(); |
| header->p_euid = geteuid(); |
| header->p_version = NSCD_HEADER_REV; |
| header->p_status = 0; |
| header->p_errno = 0; |
| header->p_herrno = 0; |
| header->libpriv = 0; |
| header->nss_dbop = NSS_DBOP_PROTOCOLS_BYNAME; |
| |
| size_t name_len = strlen(NSS_DBNAM_PROTOCOLS); |
| size_t default_config_len = strlen(NSS_FILES_ONLY); |
| header->dbd_off = sizeof(nss_pheader_t); |
| header->dbd_len = sizeof(nss_dbd_t) + name_len + 1 + default_config_len + 1; |
| nss_dbd_t *dbd = (nss_dbd_t *) (buf + sizeof(nss_pheader_t)); |
| dbd->o_name = sizeof(nss_dbd_t); |
| dbd->o_config_name = 0; |
| dbd->o_default_config = dbd->o_name + name_len + 1; |
| dbd->flags = 0; |
| strcpy(buf + header->dbd_off + dbd->o_name, NSS_DBNAM_PROTOCOLS); |
| strcpy(buf + header->dbd_off + dbd->o_default_config, |
| NSS_DEFCONF_PROTOCOLS); |
| |
| name_len = strlen("icmp"); |
| header->key_off = header->dbd_off + ROUND_UP(header->dbd_len, sizeof(nssuint_t)); |
| header->key_len = name_len + 1; |
| strcpy(buf + header->key_off, "icmp"); |
| |
| header->data_off = header->key_off + ROUND_UP(header->key_len, sizeof(nssuint_t)); |
| header->data_len = 0; |
| header->pbufsiz = header->data_off + header->data_len; |
| |
| params.data_ptr = buf; |
| params.data_size = header->pbufsiz; |
| params.desc_ptr = NULL; |
| params.desc_num = 0; |
| params.rbuf = buf; |
| params.rsize = sizeof(buf); |
| |
| /* Sanity checks on the nss_pheader_t header. */ |
| assert(header->p_version == NSCD_HEADER_REV); |
| assert(header->dbd_off == sizeof(nss_pheader_t)); |
| assert((params.data_size & 3) == 0); |
| assert((header->dbd_off & 3) == 0); |
| assert((header->key_off & 3) == 0); |
| assert((header->data_off & 3) == 0); |
| assert(header->data_off == params.data_size); |
| nssuint_t l1 = header->key_off - header-> dbd_off; |
| assert(l1 >= header->dbd_len); |
| nssuint_t l2 = header->data_off - header->key_off; |
| assert(l2 >= header->key_len); |
| assert(sizeof(nss_pheader_t) + l1 + l2 == header->data_off); |
| assert(header->data_off + header->data_len == header->pbufsiz); |
| |
| /* Make the call. */ |
| if (door_call(did, ¶ms) != 0) { |
| return errno; |
| } |
| |
| /* Print response attributes. */ |
| HEADER(stdout, "app_proto_icmp"); |
| printf("status=%u\n", header->p_status); |
| printf("errno=%u\n", header->p_errno); |
| printf("herrno=%u\n", header->p_herrno); |
| printf("bufsiz=%" PRIu64 "\n", header->pbufsiz); |
| printf("dbd_off=%" PRIu64 " dbd_len=%" PRIu64 "\n", |
| header->dbd_off, header->dbd_len); |
| printf("key_off=%" PRIu64 " key_len=%" PRIu64 "\n", |
| header->key_off, header->key_len); |
| printf("data_off=%" PRIu64 " data_len=%" PRIu64 "\n", |
| header->data_off, header->data_len); |
| printf("ext_off=%" PRIu64 " ext_len=%" PRIu64 "\n", |
| header->ext_off, header->ext_len); |
| printf("key=%s\n", buf + header->key_off); |
| |
| /* Parse response proto data. */ |
| char *p = buf + header->data_off; |
| char *limit = p + header->data_len; |
| |
| while ((p < limit) && isspace(*p)) |
| p++; |
| char *name_start = p; |
| while ((p < limit) && !isspace(*p)) |
| p++; // skip over the name |
| name_len = p - name_start; |
| |
| while ((p < limit) && isspace(*p)) |
| p++; |
| char *number_start = p; |
| do { |
| p++; // skip over the proto number |
| } while ((p < limit) && !isspace(*p)); |
| size_t number_len = p - number_start; |
| |
| while ((p < limit) && isspace(*p)) |
| p++; |
| char *aliases_start = p; |
| while ((p < limit) && !isspace(*p)) |
| p++; // skip over the aliases |
| size_t aliases_len = p - aliases_start; |
| |
| printf("data: name=%.*s number=%.*s aliases=%.*s\n", |
| (int) name_len, name_start, (int) number_len, number_start, |
| (int) aliases_len, aliases_start); |
| |
| return handle_rbuf(¶ms, buf); |
| } |
| |
| int main(int argc, const char *argv[]) |
| { |
| /* Uninitialised, but we know px[0] is 0x0. */ |
| long *px = malloc(sizeof(long)); |
| x0 = px[0]; |
| |
| int did = open(DOOR_FILE, O_RDONLY); |
| if (did < 0) { |
| perror("open " DOOR_FILE); |
| fprintf(stderr, "Make sure the name service switch daemon (nscd) " |
| "is running.\n"); |
| return 1; |
| } |
| |
| struct door_info info; |
| if (door_info(did, &info) != 0) { |
| perror("door_info " DOOR_FILE); |
| close(did); |
| return 1; |
| } |
| |
| HEADER(stderr, "app_small_request"); |
| test_app_small_request(did); |
| |
| HEADER(stderr, "app_uninitialized_request"); |
| test_app_uninitialized_request(did); |
| |
| HEADER(stderr, "app_proto_icmp"); |
| test_app_proto_icmp(did); |
| |
| close(did); |
| |
| return 0; |
| } |
| |