1/* Tests for name switch cache daemon (nscd) door wrapper. */
2
3#include "config.h"
4
5#include <assert.h>
6#include <ctype.h>
7#include <door.h>
8#include <fcntl.h>
9#include <inttypes.h>
10#include <nss_dbdefs.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <strings.h>
14#include <unistd.h>
15#include <sys/mman.h>
16
17#if defined(SOLARIS_NSCD_DOOR_SYSTEM_VOLATILE)
18#define DOOR_FILE "/system/volatile/name_service_door"
19#else
20#define DOOR_FILE "/var/run/name_service_door"
21#endif
22
23#define HEADER(file, test_name) \
24   fprintf(file, "---------------------------------------------------------\n"  \
25                 "%s\n"                                                         \
26                 "---------------------------------------------------------\n", \
27                 test_name);
28
29
30static long x0;
31
32/* It's possible that the system allocated a new memory for rbuf.
33   Unmap it if it is the case. */
34static int handle_rbuf(door_arg_t *params, void *buf)
35{
36   if (params->rbuf != buf) {
37      if (munmap(params->rbuf, params->rsize) != 0) {
38         perror("munmap");
39         return EINVAL;
40      }
41   }
42
43   return 0;
44}
45
46__attribute__((noinline))
47static int test_app_small_request(int did)
48{
49   /* Set call parameters. */
50   size_t buf_size = sizeof(uint32_t);
51   char *buf = malloc(buf_size);
52   assert(buf != NULL);
53
54   nss_pheader_t *header = (nss_pheader_t *) buf;
55   header->nsc_callnumber = x0 + NSCD_GETENT;
56
57   door_arg_t params;
58   params.data_ptr = buf;
59   params.data_size = buf_size;
60   params.desc_ptr = NULL;
61   params.desc_num = 0;
62   params.rbuf = buf;
63   params.rsize = buf_size;
64
65   /* Make the call. */
66   if (door_call(did, &params) != 0) {
67      return errno;
68   }
69
70   return handle_rbuf(&params, buf);
71}
72
73__attribute__((noinline))
74static int test_app_uninitialized_request(int did)
75{
76   /* Set call parameters. */
77   size_t buf_size = sizeof(nss_pheader_t) + sizeof(nss_dbd_t);
78   char *buf = malloc(buf_size);
79   assert(buf != NULL);
80
81   nss_pheader_t *header = (nss_pheader_t *) buf;
82   header->nsc_callnumber = x0 + NSCD_GETENT;
83   header->dbd_off = x0 + sizeof(nss_pheader_t);
84   header->dbd_len = x0 + sizeof(nss_dbd_t);
85   nss_dbd_t *dbd = (nss_dbd_t *) (buf + sizeof(nss_pheader_t));
86   dbd->flags = x0;
87   dbd->o_name = x0 + 100;
88   dbd->o_config_name = x0 + 100;
89   dbd->o_default_config = x0 + 100;
90   header->key_off = x0 + sizeof(nss_pheader_t) + sizeof(nss_dbd_t);
91   header->key_len = x0 + 1; // one byte past the end of 'buf'
92   header->pbufsiz = x0 + 10000000;
93
94   door_arg_t params;
95   params.data_ptr = buf;
96   params.data_size = buf_size;
97   params.desc_ptr = NULL;
98   params.desc_num = 0;
99   params.rbuf = buf;
100   params.rsize = buf_size;
101
102   /* Make the call. */
103   if (door_call(did, &params) != 0) {
104      return errno;
105   }
106
107   /* Check definedness of response attributes ... */
108   int x = 0;
109   if (header->p_status != NSS_SUCCESS) x = -1; else x = -2;
110   if (header->p_herrno != 0) x = -2; else x = -3;
111   if (header->key_off != 0) x = -4; else x = -5;
112   if (header->key_len != 0) x = -6; else x = -7;
113   if (header->data_off != 0) x = -8; else x = -9;
114   if (header->data_len != 0) x = -10; else x = -11;
115   /* ... and now one which is not defined. */
116   if (header->reserved1 != 0) x = -12; else x = -13;
117
118   handle_rbuf(&params, buf);
119   return x;
120}
121
122__attribute__((noinline))
123static int test_app_proto_icmp(int did)
124{
125   door_arg_t params;
126   char buf[16384];
127
128   /* Set call parameters. */
129   nss_pheader_t *header = (nss_pheader_t *) buf;
130   header->nsc_callnumber = NSCD_SEARCH;
131   header->p_ruid = getuid();
132   header->p_euid = geteuid();
133   header->p_version = NSCD_HEADER_REV;
134   header->p_status = 0;
135   header->p_errno = 0;
136   header->p_herrno = 0;
137   header->libpriv = 0;
138   header->nss_dbop = NSS_DBOP_PROTOCOLS_BYNAME;
139
140   size_t name_len = strlen(NSS_DBNAM_PROTOCOLS);
141   size_t default_config_len = strlen(NSS_FILES_ONLY);
142   header->dbd_off = sizeof(nss_pheader_t);
143   header->dbd_len = sizeof(nss_dbd_t) + name_len + 1 + default_config_len + 1;
144   nss_dbd_t *dbd = (nss_dbd_t *) (buf + sizeof(nss_pheader_t));
145   dbd->o_name = sizeof(nss_dbd_t);
146   dbd->o_config_name = 0;
147   dbd->o_default_config = dbd->o_name + name_len + 1;
148   dbd->flags = 0;
149   strcpy(buf + header->dbd_off + dbd->o_name, NSS_DBNAM_PROTOCOLS);
150   strcpy(buf + header->dbd_off + dbd->o_default_config,
151          NSS_DEFCONF_PROTOCOLS);
152
153   name_len = strlen("icmp");
154   header->key_off = header->dbd_off + ROUND_UP(header->dbd_len, sizeof(nssuint_t));
155   header->key_len = name_len + 1;
156   strcpy(buf + header->key_off, "icmp");
157
158   header->data_off = header->key_off + ROUND_UP(header->key_len, sizeof(nssuint_t));
159   header->data_len = 0;
160   header->pbufsiz = header->data_off + header->data_len;
161
162   params.data_ptr = buf;
163   params.data_size = header->pbufsiz;
164   params.desc_ptr = NULL;
165   params.desc_num = 0;
166   params.rbuf = buf;
167   params.rsize = sizeof(buf);
168
169   /* Sanity checks on the nss_pheader_t header. */
170   assert(header->p_version == NSCD_HEADER_REV);
171   assert(header->dbd_off == sizeof(nss_pheader_t));
172   assert((params.data_size & 3) == 0);
173   assert((header->dbd_off & 3) == 0);
174   assert((header->key_off & 3) == 0);
175   assert((header->data_off & 3) == 0);
176   assert(header->data_off == params.data_size);
177   nssuint_t l1 = header->key_off - header-> dbd_off;
178   assert(l1 >= header->dbd_len);
179   nssuint_t l2 = header->data_off - header->key_off;
180   assert(l2 >= header->key_len);
181   assert(sizeof(nss_pheader_t) + l1 + l2 == header->data_off);
182   assert(header->data_off + header->data_len == header->pbufsiz);
183
184   /* Make the call. */
185   if (door_call(did, &params) != 0) {
186      return errno;
187   }
188
189   /* Print response attributes. */
190   HEADER(stdout, "app_proto_icmp");
191   printf("status=%u\n", header->p_status);
192   printf("errno=%u\n", header->p_errno);
193   printf("herrno=%u\n", header->p_herrno);
194   printf("bufsiz=%" PRIu64 "\n", header->pbufsiz);
195   printf("dbd_off=%" PRIu64 " dbd_len=%" PRIu64 "\n",
196          header->dbd_off, header->dbd_len);
197   printf("key_off=%" PRIu64 " key_len=%" PRIu64 "\n",
198          header->key_off, header->key_len);
199   printf("data_off=%" PRIu64 " data_len=%" PRIu64 "\n",
200          header->data_off, header->data_len);
201   printf("ext_off=%" PRIu64 " ext_len=%" PRIu64 "\n",
202          header->ext_off, header->ext_len);
203   printf("key=%s\n", buf + header->key_off);
204
205   /* Parse response proto data. */
206   char *p = buf + header->data_off;
207   char *limit = p + header->data_len;
208
209   while ((p < limit) && isspace(*p))
210      p++;
211   char *name_start = p;
212   while ((p < limit) && !isspace(*p))
213      p++; // skip over the name
214   name_len = p - name_start;
215
216   while ((p < limit) && isspace(*p))
217      p++;
218   char *number_start = p;
219   do {
220      p++; // skip over the proto number
221   } while ((p < limit) && !isspace(*p));
222   size_t number_len = p - number_start;
223
224   while ((p < limit) && isspace(*p))
225      p++;
226   char *aliases_start = p;
227   while ((p < limit) && !isspace(*p))
228      p++; // skip over the aliases
229   size_t aliases_len = p - aliases_start;
230
231   printf("data: name=%.*s number=%.*s aliases=%.*s\n",
232      (int) name_len, name_start, (int) number_len, number_start,
233      (int) aliases_len, aliases_start);
234
235   return handle_rbuf(&params, buf);
236}
237
238int main(int argc, const char *argv[])
239{
240   /* Uninitialised, but we know px[0] is 0x0. */
241   long *px = malloc(sizeof(long));
242   x0 = px[0];
243
244   int did = open(DOOR_FILE, O_RDONLY);
245   if (did < 0) {
246      perror("open " DOOR_FILE);
247      fprintf(stderr, "Make sure the name service switch daemon (nscd) "
248              "is running.\n");
249      return 1;
250   }
251
252   struct door_info info;
253   if (door_info(did, &info) != 0) {
254      perror("door_info " DOOR_FILE);
255      close(did);
256      return 1;
257   }
258
259   HEADER(stderr, "app_small_request");
260   test_app_small_request(did);
261
262   HEADER(stderr, "app_uninitialized_request");
263   test_app_uninitialized_request(did);
264
265   HEADER(stderr, "app_proto_icmp");
266   test_app_proto_icmp(did);
267
268   close(did);
269
270   return 0;
271}
272
273